I faced a strange problem in IE with Dojo EnhancedGrid.
The data for the grid I get from server with AJAX, then in load() method i'm trying to go through all the elements in the grid. And here things go mad in IE. Here is the method that tries to get elements :
var grid = dijit.byId(prefix + "mySuperGrid");
for (var i = 0 , l = grid.getTotalRowCount(); i < l; i++) {
item = grid.getItem(i);
}
In the first iteration I get
object does not support this action
In FireFox the same code works perfectly.
Ok I found the bad guy. The thing was that IE needs var keyword before variable name when firefox does not. So the code should be :
var grid = dijit.byId(prefix + "mySuperGrid");
for (var i = 0 , l = grid.getTotalRowCount(); i < l; i++) {
var item = grid.getItem(i);
}
Related
I have to create a dozen protected ranges in a sheet. I have code that works but is very slow because it contacts the server for each range. I know it's possible to work on a local copy of the data if there's some cell processing involved. Is it possible for range protections also?
If it's not, would caching help?
The below code uses the username from the first row as an editor for a bunch of rows in the same column.
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var sheets = spreadSheet.getSheets();
//Set protections per column, we start from the 4th.
for (var i = 4; i <= sheets[3].getLastColumn(); i++){
///Get the username.
var editor = sheets[3].getRange(1, i).getDisplayValue();
//Set the protection.
var protection = sheets[3].getRange(3, i, 22, 1).protect();
protection.setDescription(editor);
//Handle the case of deleted/unknown usernames.
try{
protection.addEditor(editor + '#domain.com');
} catch(error){
protection.addEditor('user#domain.com');
}
}
I've found a solution for a similar issue https://stackoverflow.com/a/37820854 but when I try to apply it to my case I get an error "TypeError: Cannot find function getRange in object Range" so I must be doing something wrong.
var test = [];
for (var i = 4; i <= sheets[3].getLastColumn(); i++){
test.push(sheets[3].getRange(3, i, 22, 1));
}
var editor;
for (var i = 0; i<test.length; i++){
var editor = test[i].getRange(1, 1).getDisplayValue();
}
The syntax for the method getRange() is getRange(row, column, numRows, numColumns), while you counter variable i loops through the COLUMNS instead of ROWS.
If your intention is to loop through all columns and add an editor to each one, it should be something like
for (var i = 4; i <= sheets[3].getLastColumn(); i++){
///Get the username.
var editor = sheets[3].getRange(1, i).getDisplayValue();
//Set the protection.
var protection = sheets[3].getRange(startRow, i, rowNumber, columnNumber).protect();
protection.setDescription(editor);
//Handle the case of deleted/unknown usernames.
try{
protection.addEditor(editor + '#domain.com');
} catch(error){
protection.addEditor('user#domain.com');
}
}
Its possible to do batch processing.
But you'll have to use Advanced Google Services. Check out the Sheets Advanced service and the Sheets API documentation.
In my ASP.NET Core 1.1 app I'm using EPPlus.Core to export data to Excel. Some columns exported have mostly numbers but rarely a text (e.g. N/A). These columns in generated Excel are showing (as expected) a green triangle on the top left corner of their cells. I want to get rid of those warnings.
Question: What's a good way of getting rid of those triangles when Excel is generated? I tried setting the format of these columns to text as follows but it did not work. I guess we need to set the format of these columns to General but I can't figure out how:
workSheet.Cells["D1:P1"].Style.Numberformat.Format = "General";
UPDATE:
Per a user's request, the code looks similar to following.
Error at inner loop for (var j = 4; j < testlist[i].Count(); j++){...}: MyViewModel does not contain a definition of Count()
Error at line if (testlist[i][j] is string){...}: cannot apply indexing with [] to an extension of type MyViewModel
Controller:
....
....
var testlist = (qry to load a MyViewModel).ToList();
using (ExcelPackage pkg= new ExcelPackage())
{
var ws = excel.Workbook.Worksheets.Add("TestWorkSheet");
ws.Cells[1, 1].LoadFromCollection(rc_excel, true);
//I'm starting from 2nd row and 5th column
for (var i = 1; i < testlist.Count; i++)
{
for (var j = 4; j < testlist[i].Count(); j++)
{
if (testlist[i][j] is string)
{
....
....
}
}
pkg.Save();
return(....);
}
consider the following:
gridID = datagridID;
//column headers
domConstruct.place("<div class=\"gridheaderrow\" data-type =\"BolingerGridHeaderRow\" ></div>", gridID, "first");
var node = query("div[data-type=\"BolingerGridRow\"]", gridID);
var headerNode = query("div[data-type=\"BolingerGridHeaderRow\"]", gridID);
var cells = query("div[data-type=\"BolingerGridCell\"]", node[0]);
for (var i = 0; i < cells.length; i++)
{
var columnname;
columnname = attr.get(cells[i], "data-columnname");
var headernode = domConstruct.place("<div class=\"gridheadercell\" data-type=\"BolingerGridHeaderCell\">" + columnname + "</div>", headerNode[0], "last");
var sortup = domConstruct.place("<div id=column'" + i + "' data-columnupid = '" + i + "' data-type='sortuparrow' style='display:inline; cursor:pointer'>▲</div>", headernode, "last");
var sortdown = domConstruct.place("<div id=column'" + i + "' data-columndownid = '" + i + "' data-type='sortdownarrow' style='display:inline; cursor:pointer'>▼</div>", headernode, "last");
}
for (var i = 0; i < cells.length; i++)
{
var sortupnode = query("[data-columnupid = '" + i + "']", gridID)[0];
var sortdownnode = query("[data-columndownid = '" + i + "']", gridID)[0];
on(sortupnode, "click", function (e) {
var num = attr.get(sortupnode, "data-columnupid");
sort(true, num);
});
on(sortdownnode, "click", function (e) {
var num = attr.get(sortdownnode, "data-columndownid");
sort(false, num);
});
}
This code places little up and down arrows above each column and attaches on click events to them, which calls the sort function. I'm quite sure I'm attaching the events each up or down arrow once. Yet, no matter what arrow I click on the handler that handles it belongs to the arrow of the last column. Why is this? I'm figuring it has something to do with attaching handlers to nodes I just placed. Thoughts?
Variables do not have block scope in JavaScript. You are expecting that each iteration through your second for loop has its own sortupnode and sortdownnode variables, but in fact each time through the loop, the same variable is being redeclared and its value is being replaced. Your on handlers are continuing to reference the same sortupnode and sortdownnode variables, which by the time they run, will always reference the very last nodes iterated.
In this case the absolute simplest fix would likely be to replace sortupnode and sortdownnode inside your event handlers with this, which should reference the element that the handler fired for. However, you should be able to avoid this issue completely and hook up these event handlers much more efficiently using event delegation. Something along the lines of:
on(document.getElementById(gridID), '[data-columnupid]:click', function (event) {
// Inside delegated event handlers registered with dojo/on,
// `this` references the element that matched the selector
var num = this.getAttribute('data-columnupid');
sort(true, num);
});
Addendum
In response to your second comment: the problem you are facing has no direct correlation to event handling; it is purely related to how scope works in JavaScript.
To attempt to better illustrate how the variables in your loops are actually working, bear in mind that this:
for (var i = 0; i < ...; i++) {
var foo = ...;
...
}
... is essentially equivalent to this, because JavaScript variables do not have block scope:
var i;
var foo;
for (i = 0; i < ...; i++) {
foo = ...;
...
}
That is to say, the variable foo exists in the scope of the surrounding function, not the for loop. The same foo variable has its value modified each time through the loop.
Any code that looks at foo after the loop finishes running will see the last value foo was assigned in the loop. You are defining event handler callbacks in each iteration through your loop which have access to foo from the containing function's scope, but those callbacks are only actually called way later when the user performs an action. "Way later" = after the loop finished running = foo is always going to be the value it was set to during the last iteration.
I'm using a Dojo Data grid together with a REST service to display view data. When I double click on a row, an XPage is opened. My problem is that, if one of the columns in the grid is not sorted, the wrong XPage is opened. What could be the problem here?
<xe:djxDataGrid id="P_Alle_DDG" store="restService2"
styleClass="DojoViewTable" title="Pendenzen - Alle" autoHeight="20"
rowsPerPage="25" selectable="true" selectionMode="multiple"
singleClickEdit="true" rowSelector="2" style="font-size:12pt"
escapeHTMLInData="true">
<xe:this.onRowDblClick><![CDATA[var idx = arguments[0].rowIndex;
var unid = restService2._items[idx].attributes["#unid"];
var url = 'Reparatur.xsp?documentId='+unid+'&action=openDocument';
window.document.location.href = url;]]></xe:this.onRowDblClick>
UPDATE: With the following JavaScript code the problem has been solved:
var grid = arguments[0].grid;
var index = arguments[0].rowIndex;
var item = grid.getItem(index);
var unid = item.attributes["#unid"];
var url = 'Reparatur.xsp?documentId='+unid+'&action=openDocument';
window.document.location.href = url;
Tony, try this method of opening the document. The code if very similar to yours, but the key difference is that I made a view column that contains the unid, I called it "docid". This works for me.
var grid = arguments[0].grid;
var index = arguments[0].rowIndex;
var item = grid.getItem(index);
var unid = item["docid"];
var url = "New_PO.xsp?doc=" + unid;
window.document.location.href = url;
First, you have to know that I am developing my project with Struts (J2EE
Here is my problem :
I have 2 dijit.form.Select widgets in my page, and those Select are filled with the same list (returned by a Java class).
When I select an option in my 1st "Select widget", I would like to update my 2nd Select widget, and disable the selected options from my 1st widget (to prevent users to select the same item twice).
I succeed doing this (I'll show you my code later), but my problem is that when I open my 2nd list, even once, it will never be refreshed again. So I can play a long time with my 1st Select, and choose many other options, the only option disabled in my 2nd list is the first I've selected.
Here is my JS Code :
function removeSelectedOption(){
var list1 = dijit.byId("codeModif1");
var list2 = dijit.byId("codeModif2");
var list1SelectedOptionValue = list1.get("value");
if(list1SelectedOptionValue!= null){
list2.reset();
for(var i = 0; i < myListSize; i++){
// If the value of the current option = my selected option from list1
if(liste2.getOptions(i).value == list1SelectedOptionValue){
list2.getOptions(i).disabled = true;
} else {
list2.getOptions(i).disabled = false;
}
}
}
Thanks for your help
Regards
I think you have to reset() the Select after you've updated its options' properties. Something like:
function removeSelectedOption(value)
{
var list2 = dijit.byId("codeModif2"),
prev = list2.get('value');
for(var i = 0; i < myListSize; i++)
{
var opt = myList[i];
opt.disabled = opt.value === value;
list2.updateOption(opt);
}
list2.reset();
// Set selection again, unless it was the newly disabled one.
if(prev !== value) list2.set('value', prev);
};
(I'm assuming you have a myList containing the possible options here, and the accompanying myListSize.)