Kendo Grid - accessing and manipulating the item object - kendo-grid

Well I've gotten exactly zero responses to my half-dozen Angular-Kendo-UI grid questions, so I'm gonna cross my finger and hope my problems can be solved more generally. Maybe there's an easier way of manipulating the grid items.
I want to access the objects that contain my data (order items, in this case).
My grid's rows have a checkbox for selecting orders. When the user selects an order, I want to retrieve and manipulate that object.
// dataSource
vm.masterGrid.dataSource = new kendo.data.DataSource({
transport:{
read: function(options) {
return vm.getOrders(options);
}
},
pageSize: 5,
serverPaging: true,
});
//options
vm.masterGrid.gridOptions = {
columns: [
{ title: "Buyer", field: "BuyerName" },
{
title: "Select",
template: "<input " +
type='checkbox' " +
class='checkbox' " +
ng-disabled='#=!HasValidCustomsInfo#' " +
ng-click='ordersVm.selectForPackaging(Id)' " +
ng-model='Id'/>"
}
]
};
The view:
<div
kendo-grid
k-height="'400px'"
k-data-source="ordersVm.masterGrid.dataSource"
k-options="ordersVm.masterGrid.gridOptions">
</div>
Here's where I'm trying to get the object so I can do stuff with it:
// checkbox-click on row
vm.selectForPackaging = function (orderId) {
console.log(orderId); // returns true (useless)
console.log(vm.getOrderItemById(99)); // returns [init: {my actual object which I can't access}]
};
(My get-order-item-by-id helper function:)
vm.getOrderItemById = function (orderId) {
var matches = $filter('filter')( vm.masterGrid.dataSource.data(), function(gridItem, index) {
return gridItem.Id == orderId;
});
};
What I get back in vm.selectForPackaging actually contains my data but it isn't usable!
It looks like this in the console:
v init {_events: Object, _handlers: Object, OrderLines: init[1], Store: init, Id: 99…}
AddressIsValid:true
BuyerEmail:"lance.slack#gmail.com"
etc...
which would be fine, but I can't get it the data!
Calling vm.getOrderItemById(99).init should return my actual object. Instead it returns a function:
function (e){var t,n,i=this,r=function(){return i};we.fn.init.call(this),this._handlers={};for(n in e)t=e[n],"object"==typeof t&&t&&!t.getTime&&"_"!=n.charAt(0)&&(t=i.wrap(t,n,r)),i[n]=t;i.uid=_e.guid…
If I call that function: vm.getOrderItemById(99).init() I get undefined.
What am I doing wrong?

You can use the dataItem method to get the current row information
// checkbox-click on row
vm.selectForPackaging = function () {
var row = $(this).closest("tr"),
var grid = $(vm.masterGrid).data("kendoGrid"),
var dataItem = grid.dataItem(row);
console.log(dataItem);
};
Please refer the live example here

Related

Table data in HTML does not separate well

I was working with a table in HTML and I have the following doubt: I am taking the data from a JSON array: {"key":["1","2","3"],"values":["4","5","6"]} and when trying to insert them into the table instead of putting each data in a column all the data is put in the first column, the JS code that I am using to insert the data in the table is:
var idtabla = document.getElementById("idtabla")
idtabla.innerHTML += window.location.href.split("/tabla/")[1]
function getJson(){
var id = window.location.href.split("/tabla/")[1]
var table = document.getElementById("table")
$.get( `/json`, (data) => {
if(data.error){
idtabla.innerHTML = 404 + ", tabla no encontrada"
} else {
var keys = data.key.forEach(element => {
table.innerHTML += `<tr><td>${element}</td>`
});
var values = data.values.forEach(element => {
table.innerHTML += `<td>${element}</td></tr>`
});
}
})
}
and the result it gives me is this:
How could it be solved? Thanks a lot.
There are two problems.
First, you can't add partial HTML to innerHTML like that. Whenever you assign to innerHTML, it parses the result completely. If there are any unclosed tags, they're closed automatically. If you want to build the HTML incrementally, you should do it by appending to a string, then assign the completed string to innerHTML.
Second, you're appending all the values all the values after all the keys, so they won't be in matching rows. You need to append both the key and value in the same loop. Since forEach() passes the array index to the callback function, you can use that to index into the other array.
let tableHTML = '';
data.keys.forEach((key, i) => {
tableHTML += `<tr><td>${key}</td><td>${data.values[i]}</td></tr>`;
});
table.innerHTML = tableHTML;

The array does not output properly

let test = [];
d3.csv("cgvList.csv", function (data) {
if (data.poi_nm == "CGV") {
let obj = {};
obj.content = '<div>' + data.branch_nm + '</div>';
test.push(obj);
}
});
console.log(test);
console.log("test[0] : " + test[0]);
console.log("test.length : " + test.length);
[enter image description here][1]
I made the csv file into an object array.
And as a result of outputting the array, the array was output well,
enter image description here
but when outputting index 0, undefined came out and the length of the array was also 0.
It was printed properly when it was printed from the console.
What's the problem?
enter image description here
Without a jsfiddle or sandbox to play with, I can't tell exactly what is going on, but what I believe is happening is a mix of two things:
d3.csv is an async function, and therefore returns a promise.
The function you pass on to d3.csv is supposed to tell the function how to parse every element in the csv, and should return the parsed object, not add it to an external array or anything like that. Every element you return in that function will be an element in your resulting array
There's (at least) two possible ways you can deal with this:
await the async function, and its return value will be your required value, something like
const test = await d3.csv("cgvList.csv", function (data) {
if (data.poi_nm == "CGV") {
let obj = {};
obj.content = '<div>' + data.branch_nm + '</div>';
return obj;
}
});
console.log(test);
console.log("test[0] : " + test[0]);
console.log("test.length : " + test.length);
Notice that here the function you pass onto d3.csv returns the object in the way you want to format it!
Do your logic in a .then statement, which also waits for the promise to be fulfilled:
d3.csv("cgvList.csv", function (data) {
if (data.poi_nm == "CGV") {
let obj = {};
obj.content = '<div>' + data.branch_nm + '</div>';
return obj;
}
}).then((test) => {
console.log(test);
console.log("test[0] : " + test[0]);
console.log("test.length : " + test.length);
});

ag-Grid - Is it possible to create a floating menu for each row?

I'm trying to create a menu that appears when a user hovers on a row, just like in the image below.
I did not find any built-in option to achieve this. Also tried using a custom CellRenderer function to create an element that I could move around later, but that didn't work as expected since it presented some other challenges (css wise) and was not really achieving the goal.
Is there a way to build this kind of menus in ag-Grid?
To work around the problem, you could use onCellMouseOver & onCellMouseOut methods:
var gridOptions = {
columnDefs: columnDefs,
onCellMouseOver : onCellMouseOver,
onCellMouseOut: onCellMouseOut,
...
};
Define both functions:
var onCellMouseOver = function(event){
//Get current row
var rowIndex = event.node.rowIndex;
var row = gridOptions.api.getDisplayedRowAtIndex(rowIndex);
//Set current row as not selected - in order to base on 'cellStyle' function
row.setSelected(true);
//Setup refresh params
var params = {
force: true, //Force refresh as cell value didn't change
rowNodes: [row]
};
//Refresh current row cells
gridOptions.api.refreshCells(params);
}
var onCellMouseOut = function(event){
//Get current row
var rowIndex = event.node.rowIndex;
var row = gridOptions.api.getDisplayedRowAtIndex(rowIndex);
//Set current row as not selected - in order to base on 'cellStyle' function
row.setSelected(false);
//Setup refresh params
var params = {
force: true, //Force refresh as cell value didn't change
rowNodes: [row]
};
Then define 'cellStyle' function for your column:
var columnDefs = [
{headerName: "your_column_name", field: "your_column",
cellStyle: function(params) {;
console.log('Is row selected', params.node.selected);
if (params.node.selected) {
return {display : 'none'};
} else {
return {display : 'inherit'};
}
}
}
];
You can find more about data refresh here: https://www.ag-grid.com/javascript-grid-refresh/
The full implementation of the code above might be found here: Working example
Second solution, edited after comments:
Another way is to use css classes to achieve the result.
{
headerName: "Price",
field: "price",
cellStyle: { "text-align": "center" },
cellRenderer: function(params) {
return (
"<div class='buttons'>" +
"<div class='back'>" +
params.value +
"</div>" +
"<div class='front'><button>Option A</button><button>Option B</button></div>" +
"</div>"
);
}
Buttons are shown on hover based on .ag-row-hover ag-grid class:
.front {
display: none;
}
.ag-row-hover .front {
display: inherit;
}
Working example

Create the objectIds map with variable keys for a DuplicateObject request

When creating a "duplicate object" request, the objectIds map will not let me put a variable in the emphasized portion below:
var alternateSlideId = 'alternate_' + i;
{
duplicateObject:
{
objectId: alternateSlide,
objectIds: {
**alternateSlide**: 'Copied_Alternate_Slide_' + i,
}
}
}
(i is a number in a loop)
From my understanding the map function works like
((objectId to be copied) : (name of new objectId))
I'm unable to use a variable on the left side of the map function, and I'm unable to put 'alternate_' + i into the left side of the map and I'm uncertain as to why. I need to duplicate multiple slides that have already been duplicated before, and thus have variable names.
How can I assign variable keys to the objectIds map?
You need to specify unique ids. Not just unique to the slide, but the whole presentation. Consider using Utilities.getUuid() as I do in this answer.
Google Apps Script is essentially JavaScript 1.6, so to write to a a variable property name, you need to use the bracket operator, rather than the dot operator or the variable name / shorthand syntax in the object literal constructor. Your past attempts likely attempted to do this from the constructor:
Won't work (object literal constructor):
var v = "some prop name";
var myObj = {
v: "some prop value",
};
console.log(myObj); // {'v': 'some prop value'}
Won't work (dot operator):
var v = "some prop name";
var myObj = {};
myObj.v = "some prop value";
console.log(myObj); // {'v': 'some prop value'}
Won't work (since GAS is not ECMAScript2015 or newer), and throws "Invalid property ID" error when saving:
var v = "some prop name";
var myObj = {
[v]: "some prop value",
};
console.log(myObj);
Will work (bracket operator):
var v = "some prop name";
var myObj = {};
myObj[v] = "some prop value";
console.log(myObj); // {'some prop name': 'some prop value'}
Thus, your code to copy the a slide represented by the variable altSlide needs to be something like:
var newAltSlideId = ("copied_altSlide_" + i + "_" + Utilities.getUuid()).slice(0, 50);
var dupRqConfig = {
objectId: altSlide.objectId, // the object id of the source slide
objectIds: {} // map between existing objectIds on the altSlide, and the new ids
};
// Set the duplicate's ID
dupRqConfig.objectIds[altSlide.objectId] = newAltSlideId;
// If you want to set the objectIds in the duplicate, you need to
// loop over altSlide's child objects. An example:
altSlide.pageElements.forEach(function (child, index) {
dupRqConfig.objectIds[child.objectId] = /** some new id */;
});
requests.push({ duplicateObject: dupRqConfig }); // add the request to the batchUpdate list
References:
Object initializer
DuplicateObject Request
Page resource (aka a "slide")
"Copy a slide" sample
Array#forEach

Slickgrid - Column Definition with Complex Objects

I have a Java object where the person object contains a displayName object. I have converted it to a JSON object for my JSP. The data looks like the following:
var people = [
{"id":52959,"displayName":{"firstName":"Jim","lastName":"Doe","middleName":"A"},"projectId":50003,"grade":"8","statusCode":"A","gradYear":2016,"buyer":false},
{"id":98765,"displayName":{"firstName":"Jane","lastName":"Doe","middleName":"Z"},"projectId":50003,"grade":"8","statusCode":"A","gradYear":2016,"buyer":true}
];
I want to bind my columns to the name properties that reside within the displayName object, but I am cannot get the column definition to recognize where the data resides. Here is an example of my firstName column definition:
{id: 'displayName.firstName', field: 'displayName.firstName', name: 'First Name',
width: 110, sortable: true, editor: TextCellEditor, formatter: SpaceFormatter,
cssClass: '', maxLength: 250, editable: true}
The view does not render the names although the data is there. Is it possible to bind a column to an object property that resides within another object? If so, what am I doing wrong?
Slickgrid doesn't support this capability by default, but you can workaround it by adding custom value extractor to your options object:
var options = {
dataItemColumnValueExtractor: function(item, columnDef) {
var names = columnDef.field.split('.'),
val = item[names[0]];
for (var i = 1; i < names.length; i++) {
if (val && typeof val == 'object' && names[i] in val) {
val = val[names[i]];
} else {
val = '';
}
}
return val;
}
}
var grid = new Slick.Grid($("#slickgrid"), data, columns, options);
The code is tested with slickgrid 2.0 and is working just fine. Unfortunately seems that slickgrid code is a bit inconsistent and editors don't take into account this option, so this solution is usable only if you will display the data without editing.
I know this is a bit old... but my work around is to do a pre-process on my items. Basically, flattening the model out:
var preProcessItems = function (items) {
var newItems = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
item['firstName'] = item['displayName']['firstName'];
newItems[i] = item;
}
return newItems;
};
/// when the value is updated on the flat structure, you can edit your deep value here
var fNameFormatter = function (row, cell, value, columnDef, dataContext) {
// datacontext.displayName.firstName = value;
return value ? value : "";
};
This problem seems to be more a of a data modeling issue though.