Telerik UI MVVM grid misbehaving with checkboxes - checkbox

I have a Telerik UI grid I'm using, and I can't get it to quite behave correctly with a Checkbox column.
What I'd like is to have it tie to a field in a Dataset that is boolean. I'd like to edit this item with a Checkbox. And whenever the checkbox is selected or unselected, I'd like to do some math on the row.
I've searched around Stackexchange and found some code bits that help, but it's not 100%. I've created a JSFiddle to demonstrate the odd behavior.
The grid is defined as follows:
<script type="text/x-kendo-template" id="checkboxTemplate">
<input type="checkbox" #=Discontinued ? checked="checked" : "" # class="chkbx" />
</script>
<div
id="LineItemsGrid"
data-role="grid"
data-editable="true"
data-bind="source: LineItems"
style="height: 470px"
data-navigatable="true"
data-columns="[
{ 'field': 'Discontinued', 'title':'<center>Discontinued</center>', 'width': 95, 'template': kendo.template($('#checkboxTemplate').html()) },
{ 'field': 'ProductName', 'title':'<center>Product Name</center>', 'width': 90 },
{ 'field': 'UnitPrice', 'title':'<center>Unit Price</center>', 'width': 90 },
{ 'field': 'UnitsInStock', 'title':'<center>Units In Stock</center>', 'width': 90 },
{ 'field': 'TotalInventory', 'title':'<center>Total Inventory</center>', 'width': 90 }
]">
</div>
Nothing too fancy. And the javascript to handle the checkboxes is here:
$(document).on('change', 'input:checkbox', function (e) {
var grid = $("#LineItemsGrid").data("kendoGrid");
var row = $(this).closest("tr");
var rowIdx = $("tr", grid.tbody).index(row);
var colIdx = $("td", row).index(this);
var checkval = $(this).prop("checked");
var items = LineItemsSource.data();
// set data - this causes the move to (0,0)
items[rowIdx].set("Discontinued", checkval);
if(checkval)
{
var total = items[rowIdx].get("UnitPrice") * items[rowIdx].get("UnitsInStock");
items[rowIdx].set("TotalInventory",total);
}
else
{
items[rowIdx].set("TotalInventory",0);
}
})
If you click on the checkbox, when you .set() the value to the checkbox, it moves the caret to (0,0). And when you click in the cell beside the checkbox, it moves the checkbox a bit to the left and doesn't select it. If you click it at that point it edits and doesn't move to (0,0).
I'm absolutely certain there is a more elegant way of doing this, but I'm having no luck finding any clues about it.

Your code was a bit hard to debug in jsfiddle.
but I made this for you and hopefully it can help you:
You can use the change event of the data source and MVVM instead of trying to deal with JQuery Events.
Also by default kendo grid are not MVVM in display mode just in edit mode.
If you look at the data bound event this makes your rows even in view mode mvvm.
here is the Dojo displaying it.
https://dojo.telerik.com/AYEsUSiz/4
here is the code
<div id="grid"></div>
<script type="text/x-kendo-template" id="checkboxTemplate">
<input type="checkbox" data-bind="checked: Discontinued" class="chkbx" />
</script>
<script>
$('#grid').kendoGrid({
dataBound: function(e) {
let visibleModels = e.sender.dataSource.view();
var items = e.sender.items();
for(var i = 0 ; i < items.length; i++) {
kendo.bind(items[i], visibleModels[i]);
}
},
editable: true,
navigatable: true,
dataSource: {
change: function(e) {
console.log(e);
if (e.action == "itemchange" && e.field == 'Discontinued') {
var model = e.items[0];
if(model.get('Discontinued'))
{
var total = model.get("UnitPrice") * model.get("UnitsInStock");
model.set("TotalInventory",total);
}
else
{
model.set("TotalInventory",0);
}
}
},
transport: {
read: function(options) {
options.success(products);
}
}
},
columns: [
{ 'field': 'Discontinued', 'title':'<center>Discontinued</center>', 'width': 95, 'template': kendo.template($('#checkboxTemplate').html()) },
{ 'field': 'ProductName', 'title':'<center>Product Name</center>', 'width': 90 },
{ 'field': 'UnitPrice', 'title':'<center>Unit Price</center>', 'width': 90 },
{ 'field': 'UnitsInStock', 'title':'<center>Units In Stock</center>', 'width': 90 },
{ 'field': 'TotalInventory', 'title':'<center>Total Inventory</center>', 'width': 90 }
]
});
</script>
Revision if you don't set the field the grid won't try to convert your column to an editable control and it will react the same way and changing the model inside your data source at the same time.
https://dojo.telerik.com/AYEsUSiz/6
code:
<div id="grid"></div>
<script type="text/x-kendo-template" id="checkboxTemplate">
<input type="checkbox" data-bind="checked: Discontinued" class="chkbx" />
</script>
<script>
$('#grid').kendoGrid({
dataBound: function(e) {
let visibleModels = e.sender.dataSource.view();
var items = e.sender.items();
for(var i = 0 ; i < items.length; i++) {
kendo.bind(items[i], visibleModels[i]);
}
},
editable: true,
navigatable: true,
dataSource: {
change: function(e) {
console.log(e);
if (e.action == "itemchange" && e.field == 'Discontinued') {
var model = e.items[0];
if(model.get('Discontinued'))
{
var total = model.get("UnitPrice") * model.get("UnitsInStock");
model.set("TotalInventory",total);
}
else
{
model.set("TotalInventory",0);
}
}
},
transport: {
read: function(options) {
options.success(products);
}
}
},
columns: [
{ 'title':'<center>Discontinued</center>', 'width': 95, 'template': kendo.template($('#checkboxTemplate').html()) },
{ 'field': 'ProductName', 'title':'<center>Product Name</center>', 'width': 90 },
{ 'field': 'UnitPrice', 'title':'<center>Unit Price</center>', 'width': 90 },
{ 'field': 'UnitsInStock', 'title':'<center>Units In Stock</center>', 'width': 90 },
{ 'field': 'TotalInventory', 'title':'<center>Total Inventory</center>', 'width': 90 }
]
});
</script>

Related

kendo ui dropdown list default value

how is it possible to set a default select on a dropddownlist with kendo ui and angular js ? I tried with k-value but it doesn't work. I use angular 1.5 and es6. I want to display a list of users and each user has an id. Thanks !
<select kendo-drop-down-list="vm.dpwnN1"
class="col s5"
id="idUtilisateurResponsableN1"
name="idUtilisateurResponsableN1"
k-options="vm.responsableN1Options"
k-value="vm.utilisateur.id_utilisateur_responsable_n1"
ng-model="vm.utilisateur.id_utilisateur_responsable_n1"
>
</select>
this.responsableN1Options = {
dataSource: {
transport: {
read: promise => {
this.getDataForN1(promise);
}
}
}, dataBound: () => {
this.utilisateur.id_utilisateur_responsable_n1 = this.dpwnN1.value();
},
optionLabel: 'Choisissez votre responsable (N+1)',
dataTextField: 'nom',
dataValueField: 'id',
template: '{{dataItem.nom}} {{dataItem.prenom}}',
valueTemplate: 'Responsable (N+1) : {{dataItem.nom}} {{dataItem.prenom}}',
animation: {
close: {
effects: 'fadeOut zoom:out',
duration: 300
},
open: {
effects: 'fadeIn zoom:in',
duration: 300
}
}
};
You can do this using jQuery , Add the following script:
<script>
$(document).ready(function(){
var dropdownList = $("#idUtilisateurResponsableN1").data("kendoDropDownList");
dropdownList.select(0); // in this case first option will be default value.
})
</script>
You can set the default value of the DropDownList using the "value" configuration option:
http://docs.telerik.com/kendo-ui/api/javascript/ui/dropdownlist#configuration-value
So in your case you would use:
this.responsableN1Options = {
dataSource: {
transport: {
read: promise => {
this.getDataForN1(promise);
}
}
}, dataBound: () => {
this.utilisateur.id_utilisateur_responsable_n1 = this.dpwnN1.value();
},
optionLabel: 'Choisissez votre responsable (N+1)',
dataTextField: 'nom',
dataValueField: 'id',
value: vm.utilisateur.id_utilisateur_responsable_n1,
template: '{{dataItem.nom}} {{dataItem.prenom}}',
valueTemplate: 'Responsable (N+1) : {{dataItem.nom}} {{dataItem.prenom}}',
animation: {
close: {
effects: 'fadeOut zoom:out',
duration: 300
},
open: {
effects: 'fadeIn zoom:in',
duration: 300
}
}
};
Where I have inserted "value" after the "dataValueField" option.

Altering the class values or styles of cells in ui-grid

I have several unique cases inside ui-grid where the cells of certain table contents need additional class, or even style rules assigned, so the appearance for these cells stands out compared to others. Looking through the official ui-grid documentation I found that it could be done with cellTemplate, but I couldn't get any consistent results. What is the best approach here?
Below are the code changes I have attempted before, with the intent being to change the class name based on the returned value from a filter call made
//Define Grid Headings
$scope.scheduledPatientAppointments = [
{
field: 'appointment_date',
displayName: 'Appointment Date'
},
{
field: 'doctor_name',
displayName: 'Doctor Name'
},
{
field: 'procedure_type_eng',
displayName: 'Medical Procedure Type'
},
{
field: 'appointment_status_eng',
displayName: 'Appointment Status'
},
{
field: 'docs_received',
displayName: 'Related Documents',
cellTemplate: '<div class="ui-grid-cell-contents" ng-click="grid.appScope.loadDocumentsModal(\'{{row.entity.id}}\')">{{grid.getCellValue(row, col) | hasDocuments}}</div>',
cellFilter: 'hasDocuments',
cellClass: function(grid, row, col, rowRenderIndex, colRenderIndex) {
if (grid.getCellValue(row, col).toLowerCase() === 'missing') {
return 'missing';
} else if (grid.getCellValue(row, col).toLowerCase() === 'received') {
return 'received';
} else {
return 'undefined';
}
}
}
];
// Define Grid Options
$scope.PatientAppointmentsGrid = {
selectionRowHeaderWidth: 25,
enableHorizontalScrollbar: false,
rowHeight: 35,
enableSorting: true,
columnDefs: $scope.columnsPatient,
data: [],
onRegisterApi: function (gridApi) {
$scope.gridApi = gridApi;
}
};
//Behavior for patient page load
$scope.appointmentsProvider = patientsService.patientFactory.getAppointmentsForPatient($stateParams.id).then(
function successCallback(response) {
var preFetchData = response.data.data;
angular.forEach(preFetchData, function (value, key) {documentsService.documentsFactory.getDocumentsByAppointmentId(value.id).then(
function successCallback(response2) {
if (response2.data.length >= 1) {
//Append value state to the preFetchData object (count size)
var totalFiles = response2.data.length;
preFetchData[key].docs_received = totalFiles;
} else {
preFetchData[key].docs_received = 0;
}
}, function errorCallback(response2) {
console.debug("Error", response2);
});
});
$scope.PatientAppointmentsGrid.data = preFetchData;
},
function errorCallback(response) {
console.debug("Error", response);
});
The contents from the "Related Documents" are initally set to Missing (the original rest call returns nothing, and the filter call sets it to that. However, a later call actually loads associated documents per row, and I believe the inactivity of the grid on this particular call is what is causing no class to get set here.
Thoughts on the best approach here?
adding custom class with cellTemplate:
columnDefs: [
{
name:'firstName',
field: 'first-name',
// adding custom class
cellTemplate: "<div class=\"ui-grid-cell-contents custom-class\" title=\"TOOLTIP\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
},
{ name:'1stFriend', field: 'friends[0]' },
{ name:'city', field: 'address.city'},
{ name:'getZip', field: 'getZip()', enableCellEdit:false}
],
.......
there are plenty of predefined customizable templates defined with $templateCache at the bottom of https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/3.2.9/ui-grid.js
adding custom style:
.......
onRegisterApi: function(gridApi){
//set gridApi on scope
$scope.gridApi = gridApi;
// adding custom style
gridApi.grid.registerStyleComputation({
func: function () {
return [
'.custom-class { ',
' color: red; ',
' font-weight: bold; ',
'} ',
'.ui-grid-row:nth-child(1) .custom-class { ',
' color: blue; ',
'} '
].join('\n');
}
});
}
plunker: http://plnkr.co/edit/YbnYoWLlEYzwmjuKOFa0?p=preview

Struggling with Kendo Grid datasource and Angular.js

I tried to make a simple example of adding a new item to a kendo grid data source but I can't seem to get it to work. The item is added to the array but the grid never updates. Is this supposed to be automatic or do I have to make a call to trigger the update?
HTML:
<kendo-grid source="people" drop="selectedPeople" groupable="true" sortable="true" columns="columns" pageable="true"></kendo-grid>
<input type="text" ng-model="nameInput">
<input type="number" ng-model="ageInput">
<button ng-click="onAdd()" type="button">Add</button>
JS:
var myApp = angular.module('myApp', []).controller('Tester', ['$scope', Tester]);
myApp.directive('kendoGrid', function() {
return {
restrict: 'E',
replace: true,
scope:{source:'=source',columns:'=columns',drop:'=drop'},
template: '<div id="kendogrid"></div>',
link: function(scope,element,attrs) {
element.kendoGrid({
dataSource: scope.source,
groupable: attrs.groupable,
sortable: attrs.sortable,
pageable: {
refresh: true,
pageSizes: true
},
columns: scope.columns
});
}
};
});
function Tester($scope) {
$scope.columns = [ {
field: "name",
width: 90,
title: "First Name"
} , {
field: "age",
width: 90,
title: "Last Name"
} , {
field: "id",
hidden: true
}
];
var man1 = new Man('name1', 25, 1);
var man2 = new Man('name2', 28, 2);
var man3 = new Man('name3', 21, 3);
var man4 = new Man('name4', 29, 4);
var man5 = new Man('name5', 22, 5);
var lastId = 5;
$scope.onAdd = function(){
if($scope.nameInput !== "" && $scope.ageInput !== "")
{
lastId++;
var myman = new Man(lastId, $scope.nameInput,$scope.ageInput);
$scope.people.push(myman);
alert("Added!");
}
}
$scope.people = [man1, man2, man3];
$scope.selectedPeople = [man4, man5];
}
function Man(name, age, id) {
this.id = id;
this.name = name;
this.age = age;
}
The fiddle:
http://jsfiddle.net/yuqorcvL/5/
Any help would be appreciated.
Use kendo observable array and it will do the magic !!.
Instead of
$scope.people = [man1, man2, man3];
Use this :
$scope.people = new kendo.data.ObservableArray([man1, man2, man3]);
updated ur fiddle : JSfiddle

how to Fit row height to content in ng-grid?

Any idea how to Fit row height to content in ng-grid? See that the text is wrapped but not shown as the row has a fix height.
I saw several posts claiming there is no support for that... thought maybe someone can enlighten me...
Thanks.
Here is my code:
this.gridOptions = { data: 'tenants.elements',
selectedItems: this.mySelections,
enableColumnResize: true,
enableColumnReordering: true,
enableRowReordering: true,
showSelectionCheckbox: true,
selectWithCheckboxOnly: true,
showFooter: true,
//sortInfo: {fields: ['percent'], directions: ['desc']},
columnDefs:
[
{width: '7%', field:'apartment', displayName:'דירה'},
{width: '2%', field:'tenant_type', displayName:'-', cellTemplate: '<i ng-class="tenants.getTenantType(row.entity.tenant_type)" class="fa fa-child"></i>'},
{width: '2%', field:'defecto', displayName:'-', cellTemplate: '<i ng-show="row.entity.defecto" class="fa fa-child defecto"></i>'},
{width: '30%', field:'tenant_name', displayName:'שם דייר', cellTemplate: '{{row.entity.tenant_name}}'},
{width: '25%' ,field:'phones', displayName:'טלפונים'},
{width: '25%' ,field:'mails', displayName:'מיילים'}
],
filterOptions: this.filterOptions,
plugins: [new ngGridAutoRowHeightPlugin()]
//plugins: [new ngGridFlexibleHeightPlugin()]
}
Here is a plugin, some code taken from the ngGridFlexibleHeightPlugin
Be warned, that height will be changed on all rows by maximum height
ngGridAutoRowHeightPlugin = function () {
var self = this;
self.grid = null;
self.scope = null;
self.init = function (scope, grid, services) {
self.domUtilityService = services.DomUtilityService;
self.grid = grid;
self.scope = scope;
var recalcHeightForData = function () { setTimeout(innerRecalcForData, 1); };
var innerRecalcForData = function () {
var gridId = self.grid.gridId,
rowHeight = self.grid.config.rowHeight;
$('.' + gridId + ' .ngRow [ng-cell-text]').each(function (index, cellText) {
//+10 for default top and bottom padding of .ngCellText class
rowHeight = Math.max(rowHeight, $(cellText).outerHeight() + 10);
});
if (self.grid.config.rowHeight < rowHeight) {
self.grid.config.rowHeight = rowHeight;
//update grid's scope.rowHeight as vertical bars height depends on it
if (scope.$$phase == '$apply' || scope.$$phase == '$digest') {
updateGridScopeHeight();
} else {
scope.$apply(updateGridScopeHeight);
}
self.domUtilityService.RebuildGrid(self.scope, self.grid);
function updateGridScopeHeight() {
self.grid.$root.scope().rowHeight = rowHeight;
}
}
};
self.scope.catHashKeys = function () {
var hash = '',
idx;
for (idx in self.scope.renderedRows) {
hash += self.scope.renderedRows[idx].$$hashKey;
}
return hash;
};
self.scope.$watch('catHashKeys()', innerRecalcForData);
self.scope.$watch(self.grid.config.data, recalcHeightForData);
};
};
And also, add this style rule to your css (after ng-grid css)
.ngCellText {
white-space: normal !important;
}
Plunker here

How to get the value of a checkbox in a Kendo UI Grid?

So I've searched many of the answers and can't seem to find anything specific on this... so here goes..
I have a standard Kendo UI Grid - and I've setup a column as follows:
{ title: "Sharing Enabled?",
field: "permissions_users_apps_user_sharing",
attributes: {
style: "text-align: center; font-size: 14px;"
},
filterable: true,
headerAttributes: {
style: "font-weight: bold; font-size: 14px; width: 40px;"
},
template: function(dataItem) {
if ( dataItem.permissions_users_apps_user_sharing == 0 ) {
return "<input type='checkbox' name='permissions_users_apps_status' id='permissions_users_apps_status' value='1' />"
} else if ( dataItem.permissions_users_apps_user_sharing == 1 ) {
return "<input type='checkbox' name='permissions_users_apps_status' id='permissions_users_apps_status' value='1' checked />"
}
}
},
What I'm trying to do is get the value of this checkbox (to see if it's changed) when I click a COMMAND button I've defined. The ROW is selectable.. so I can get the row's ID. But I can't seem to gather the value of the checkbox.
Anyone have suggestions?
Thanks in advance..
You can get the instance of checkbox in dataBound event when the checkbox state changes.
See if the below code helps you.
....
columns: [
{
{ field: "select", template: '<input id="${BindedColumn}" onclick="GrabValue(this)" type="checkbox"/>', width: "35px", title: "Select" },
}
....
selectable: "multiple, row",
dataBound: function () {
var grid = this;
//handle checkbox change
grid.table.find("tr").find("td:nth-child(1) input")
.change(function (e) {
var checkbox = $(this);
//Write code to get checkbox properties for all checkboxes in grid
var selected = grid.table.find("tr").find("td:nth-child(1) input:checked").closest("tr");
//Write code to get selected checkbox properties
......
//Code below to clear grid selection
grid.clearSelection();
//Code below to select a grid row based on checkbox selection
if (selected.length) {
grid.select(selected);
}
})
}
.....
function GrabValue(e)
{
//Alert the checkbox value
alert(e.value);
//get the grid instance
var grid = $(e).closest(".k-grid").data("kendoGrid");
//get the selected row data
var dataItem = grid.dataSource.view()[grid.select().closest("tr").index()];
}
using this method you get selected checkbox value.
$("#MultiPayment").click(function () {
var idsToSend = [];
var grid = $("#Invoice-grid").data("kendoGrid")
var ds = grid.dataSource.view();
for (var i = 0; i < ds.length; i++) {
var row = grid.table.find("tr[data-uid='" + ds[i].uid + "']");
var checkbox = $(row).find(".checkboxGroups");
if (checkbox.is(":checked")) {
idsToSend.push(ds[i].Id);
}
}
alert(idsToSend);
$.post("/whatever", { ids: idsToSend });
});
for more detail Goto

Resources