So my aim it to loop through all selected item in my kendo grid, but after the first iteration the dataItem method returns undefined.
function myFunction() {
var selectedItem = $("#DropDown").val();
var grid = $("#Grid").getKendoGrid();
var selectedItems = grid.select();
for (var i = 0; i < selectedItems.length; i++) {
var dataItem = grid.dataItem(selectedItems[i]);
if (dataItem != undefined)
dataItem.set("Item", SelectedItem);
}
}
Does anyone know why this might be happening?
That happens because set() performs a grid refresh behind-the-scenes so the DOM is recreated. The array you had with the selected items is lost. You can't rely on the tr's references. As a suggestion I think you can use they indexes instead:
function myFunction() {
var selectedItem = $("#DropDown").val();
var grid = $("#Grid").getKendoGrid();
var selectedItems = grid.select().toArray().map((item) => { return $(item).index(); });
for (var i = 0; i < selectedItems.length; i++) {
var currentItem = grid.tbody.find(`tr:eq(${selectedItems[i]})`);
var dataItem = grid.dataItem(currentItem );
if (dataItem != undefined)
dataItem.set("Item", SelectedItem);
}
}
var selectedItems = grid.select().toArray().map((item) => { return $(item).index(); });
This line gets an array of indexes from the selected grid rows to iterate further ahead;
var currentItem = grid.tbody.find(`tr:eq(${selectedItems[i]})`);
This line retrieves the selected row from by the index.
Demo
Related
I'm having a bit of trouble trying to parse the results of an array and print to the console. It's a two part problem actually. When I build the array it's adding "undefined" to the results. When I try to loop through the individual strings in the array it isn't parsing, just returning the full array object.
What I'm trying to do is collect all the field values selected from a list view and write them to another child list as separate items. When displaying results in a console it shows as an object array. When I run the typeof method against it I believe it shows as a string.
To reiterate, why am I getting undefined and why is my array not printing to console correctly. Below is an example of what is being returned thus far (when two records are selected) and my code.
Results:
undefinedDaffy DuckBugs Bunny
undefined
Code:
// Grabs selected items from getSelected function and passes parameters to writeSelected function
function callAccepted() {
getSelected().done(function(varObjects) {
for (var k in varObjects) {
console.log(varObjects[k]);
}
}); // End getSelected
} // End callAccepted
// Grabs selected items, accepts input from callAccepted or callRejected functions
function getSelected() {
var dfd = $.Deferred(function(){
var ctx = SP.ClientContext.get_current();
var clientContext = new SP.ClientContext();
var targetList = clientContext.get_web().get_lists().getByTitle(ListName);
var SelectedItems = SP.ListOperation.Selection.getSelectedItems(ctx);
var items = [];
var arrItems = [];
for (var i in SelectedItems) {
var id = SelectedItems[i].id;
var item = targetList.getItemById(id);
clientContext.load(item, "Title");
items.push(item);
} // End for
clientContext.executeQueryAsync(
function(){ // Return to button click function
var itemLength = 0;
var itemObjects = [];
for (var j = 0; j < items.length; j++) {
itemObjects = items[j].get_item("Title");
itemLength += itemObjects;
arrItems.push(itemObjects);
}
dfd.resolve(arrItems, itemLength);
},
function(){ // Return to button click function
dfd.reject(args.get_message());
}
); // End ClientContext
}); // End dfd
return dfd.promise();
} // End getSelected
Why are you writing "var itemObjects;" in 1 line and add one string "itemObjects += items[j].get_item("Title");" in another? There'll be only 1 string anyway, so when you change those 2 lines into one, "undefined" should disappear:
function callAccepted() {
getSelected().done(function(varObjects, iLength) {
// Stuff
for (var k = 0; k < iLength; k++) {
console.log(varObjects[k]);
}
}); // End getSelected
} // End callAccepted
// Get user information function
function getSelected() {
var dfd = $.Deferred(function(){
var ctx = SP.ClientContext.get_current();
var clientContext = new SP.ClientContext();
var targetList = clientContext.get_web().get_lists().getByTitle(ListName);
var SelectedItems = SP.ListOperation.Selection.getSelectedItems(ctx);
var items = [];
var arrItems = [];
for (var i in SelectedItems) {
var id = SelectedItems[i].id;
var item = targetList.getItemById(id);
clientContext.load(item, "Title");
items.push(item);
} // End for
clientContext.executeQueryAsync(
function(){ // Return to button click function
for (var j = 0; j < items.length; j++) {
var itemObjects = items[j].get_item("Title");
var itemLength = items.length;
arrItems.push(itemObjects);
}
dfd.resolve(arrItems, itemLength);
},
function(){ // Return to button click function
dfd.reject(args.get_message());
}
); // End ClientContext
}); // End dfd
return dfd.promise();
} // End getSelected
The reason for this is that after creating the variable without any value, it's undefined, so += 'Unicorn' will give us ugly 'UndefinedUnicorn'. If you wish to make variable for this purpose, write it "var x = ''".
And if - for example - you want to sum length of all "items", then this one function should look like:
function(){ // Return to button click function
var itemLength = 0;
for (var j = 0; j < items.length; j++) {
var itemObjects = items[j].get_item("Title");
itemLength += itemObjects;
arrItems.push(itemObjects);
}
dfd.resolve(arrItems, itemLength);
}
But I'm not exactly sure what are you trying to get here.
I have some code like this:
var data = // coming in from AJAX and confirmed working, don't need to wory about this...
var row = // cloning an existing HTML structure in the DOM
for (i = 0; i < data.length; i++) {
var rowclone = row.clone();
var orderLastChangedTime = new Date(data[i].createDate);
var diffDays = Math.round(Math.abs((currentTime.getTime() - orderLastChangedTime.getTime())/(oneDay)));
rowclone.find(".home-order-calc").text(diffDays);
rowclone.find(".home-order-status").text(data[i].status);
rowclone.find(".home-order-po-number").text(data[i].poNumber);
rowclone.find(".home-order-number").text(data[i].orderId);
rowclone.find(".home-order-last-changed").text(orderLastChangedTime);
rowclone.find(".home-order-lines").text(data[i].itemsCount);
rowclone.find(".home-order-cost").text(data[i].cost);
var rowstatus = rowclone.find(".home-order-status").text();
rowstatus = rowstatus.toUpperCase();
openJSONitems = [];
closedJSONitems = [];
otherJSONitems = [];
if (status[rowstatus] == "open") {
openJSONitems.push(rowclone);
}
else if (status[rowstatus] == "closed") {
closedJSONitems.push(rowclone);
}
else {
otherJSONitems.push(rowclone);
}
console.log(openJSONitems);
openJSONitems.appendTo("#home-table-orders");
}
I am trying to create 3 new JavaScript arrays and array push data into them based on sort criteria from the JSON payload. Once they are sorted I want to hang on to them and attach them to the DOM on some user actions... what am I doing wrong?
openJSONitems is an array, it doesn't have the appendTo method, you'll have to iterate over that array and append its elements to "#home-table-orders". Besides, you're creating a new array in each iteration. I think this changes would fix the problem. You could also avoid the last loop inserting the element directly when status[rowstatus] == "open" if you liked.
var openJSONitems = [],
closedJSONitems = [],
otherJSONitems = [];
var data = // coming in from AJAX and confirmed working, don't need to wory about this...
var row = // cloning an existing HTML structure in the DOM
for (i = 0; i < data.length; i++) {
var rowclone = row.clone();
var orderLastChangedTime = new Date(data[i].createDate);
var diffDays = Math.round(Math.abs((currentTime.getTime() - orderLastChangedTime.getTime())/(oneDay)));
rowclone.find(".home-order-calc").text(diffDays);
rowclone.find(".home-order-status").text(data[i].status);
rowclone.find(".home-order-po-number").text(data[i].poNumber);
rowclone.find(".home-order-number").text(data[i].orderId);
rowclone.find(".home-order-last-changed").text(orderLastChangedTime);
rowclone.find(".home-order-lines").text(data[i].itemsCount);
rowclone.find(".home-order-cost").text(data[i].cost);
var rowstatus = rowclone.find(".home-order-status").text();
rowstatus = rowstatus.toUpperCase();
if (status[rowstatus] == "open") {
openJSONitems.push(rowclone);
}
else if (status[rowstatus] == "closed") {
closedJSONitems.push(rowclone);
}
else {
otherJSONitems.push(rowclone);
}
}
console.log(openJSONitems);
for (i = 0; i < openJSONitems.length; i++) {
$(openJSONitems[i]).appendTo("#home-table-orders");
}
You could add then as a data element onto a DOM object.
$('body').data('openItems', openJSONitems);
And retrieve them later:
var items = $('body').data('openItems');
Have you considered using localStorage?
localStorage.setItem('openJSONitems', openJSONitems );
And retrieving it with...
var openJSONitems = localStorage.getItem('openJSONitems');
I'm processing a form onchange event, in this form i got a few inputs, selects and textareas, I was wondering if something like this would work for grabbing the input values in this form
var lat = {
listen: function () {
var input = document.getElementsByTagName('input');
var select = document.getElementsByTagName('select');
var textarea = document.getElementsByTagName('textarea');
var elements = [input,select,textarea];
console.log(elements.length);
for (var a = 0 ; a < elements.length ; a++) {
for ( var b = 0 ; elements[a].length ; b++) {
console.log(elements[a][b].value);
}
}
}
};
Get silly wit it
http://jsfiddle.net/jkabxpkw/1/
var values = document.getElementById('form') ? (function (array) {
var elements = document.getElementById('form').children;
for (var element in elements) {
if (elements.hasOwnProperty(element)) {
if (elements[element].value) {
array.push(elements[element].value);
}
}
}
return array;
}([])) : null;
Yes, you can map and reduce like so:
var elements = [
document.getElementsByTagName('input'),
document.getElementsByTagName('select'),
document.getElementsByTagName('textarea')
].map(function(i) {
// converts the HTMLCollection elements to an array
return Array.prototype.slice.call(i);
}).reduce(function(result, value) {
return result.concat(value);
}, []).forEach(function(element) {
console.log(element.value);
});
Let's say I have few rows of data populated with numbers. I want to select multiple cells and then on click on a button outside the grid change their values to some other number, let's say '8'. See the sample.
The guys at Telerik gave me this solution:
$(".change").click(function () {
var grid = $("#Grid").data("kendoGrid");
var cellsToChange = grid.select();
for (var i = 0; i < cellsToChange.length; i++) {
var item = grid.dataItem($(cellsToChange[i]).closest("tr"));
item.ProductName = "new value";
}
grid.refresh();
});
But the problem is that I don't know which cells will be selected, so I can't work with item.ProductName, for example. Is there a way to set the value of all selected cells directly, something like cellsToChange[i].value?
You can either get the column name from grid.columns or from the corresponding th element. use the grid.cellIndex method to select the correct column:
$("#change").click(function() {
var selected = grid.select();
var header = grid.thead;
for (var i = 0, max = selected.length ; i < max ; i++) {
var index = grid.cellIndex(selected[i]);
var th = $(header).find("th").eq(index);
// could also use grid.columns[index].field
// (not sure if this gets reordered on column reorder though)
var field = $(th).data("field");
var item = grid.dataItem($(selected[i]).closest("tr"));
item[field] = "new value";
}
grid.refresh();
});
Regarding your comment:
dataItem.set() causes the <tr> elements to get removed from their context (because grid.refresh() will create new rows for the view), and because of that, grid.dataItem() won't give you the expected result with the old DOM elements you still have a reference to.
If you want to use dataItem.set(), you can try something like this as a work-around:
$("#change").click(function () {
var selected = grid.select(),
header = grid.thead,
dataItem,
index,
field,
value,
th;
for (var i = 0, max = selected.length; i < max; i++) {
dataItem = grid.dataItem($(selected[i]).closest("tr"));
index = $(selected[i]).index();
th = $(header).find("th").eq(index);
field = $(th).data("field");
value = "new value " + i;
setTimeout(function (dataItem, field, value) {
return function () {
dataItem.set(field, value);
}
}(dataItem, field, value), 5);
}
});
(demo)
You have to retrieve the ColumnList of your grid first and then loop through it
$(".change").click(function () {
var grid = $("#Grid").data("kendoGrid");
var columnsListOfView = grid.columns;
var cellsToChange = grid.select();
for (var j = 0; i < cellsToChange.length; i++) {
var item = grid.dataItem($(cellsToChange[i]).closest("tr"));
for (var j = 0; j < columnsListOfView.length; j++) {
//Here columnsListOfView[j].field will give you the different names that you need
var field=columnsListOfView[j].field;
item[field] = "new value";
}
}
grid.refresh();
});
I was able to utilize paging in slickGrid however I am new to jquery and slickGrid and can't get to move in between pages. can anyone help me with this? Any help is greatly appreciated. Thanks!
$(document).ready(function() {var columns = [
{id:"counter", name:"#",field:"counter"},
{id:"data1", name:"Data 1",field:"data1"},
{id:"data2", name:"Data 2",field:"data2"},
{id:"data3", name:"Data 3",field:"data3"},
{id:"data4", name:"Data 4",field:"data4"}];
var options = { enableCellNavigation: false,
enableColumnReorder: false};
var FB_C_grid;
var FB_C_data;
var selectedRowIds = [];
var dataView;
$(function() {
FB_C_data = [];
FB_C_data[0]={"id":"0",
"data1":"test1",
"data2":"test1",
"data3":"test1",
"data4":"test1,
"counter":"1"
};
for (var i=1; i<50000; i++) {
var d = (FB_C_data[i] = {});enter code here
d["id"] = "id_" + i;
d["data1"] = "data1_" + i;
d["data2"] = "data2_" + i;
d["data3"] = "data3_" + i;
d["data4"] = "data4_" + i;
d["counter"] = i;
}
dataView = new Slick.Data.DataView();
dataView.setItems(FB_C_data);
dataView.setPagingOptions({pageSize:20});
FB_C_grid= new Slick.Grid($("#FB_C_sheet"),dataView.rows, columns,options);
var pager = new Slick.Controls.Pager(dataView, FB_C_grid, $("#pagerTest"));
dataView.onRowsChanged.subscribe(function(rows) {
FB_C_grid.removeRows(rows);
FB_C_grid.render();
if (selectedRowIds.length > 0)
{
// since how the original data maps onto rows has changed,
// the selected rows in the grid need to be updated
var selRows = [];
for (var i = 0; i < selectedRowIds.length; i++)
{
var idx = dataView.getRowById(selectedRowIds[i]);
if (idx != undefined)
selRows.push(idx);
}
FB_C_grid.setSelectedRows(selRows);
}
});
dataView.onPagingInfoChanged.subscribe(function(pagingInfo) {
var isLastPage = pagingInfo.pageSize*(pagingInfo.pageNum+1)-1 >= pagingInfo.totalRows;
var enableAddRow = isLastPage || pagingInfo.pageSize==0;
var options = FB_C_grid.getOptions();
if (options.enableAddRow != enableAddRow)
FB_C_grid.setOptions({enableAddRow:enableAddRow});
});
dataView.onRowCountChanged.subscribe(function(args) {
FB_C_grid.updateRowCount();
FB_C_grid.render();
});
})
});
I see some of your errors as you are trying to pass a jQuery object into SlickGrid while SlickGrid already uses jQuery in the code behind. When you create your SlickGrid object, you just need to pass the name of your grid and so in your code, you have to replace this $("#pagerTest") without jQuery wrapper becomes this "#pagerTest"
I see you called it the same in 2 different locations, so replace your 2 lines with this:
FB_C_grid= new Slick.Grid("#FB_C_sheet",dataView.rows, columns,options);
var pager = new Slick.Controls.Pager(dataView, FB_C_grid, "#pagerTest");
Hope that helps you make it to work...