kendo ui: how to remove a dataItem of a dataSource bound to some comboBox, inside combobox dataBound event - combobox

I have a grid, inside of some column of which I have created a combobox editing UI, using columns.editor function.
My goal is every time a user selects some value from the combobox -while populating a newly created grid record-, this value to be
removed from the list options of a next record's combobox.
One of the things i've tried is shown below:
function equipmentDropDownEditor(container, options) {
var equipmentComboBox = $('<input id="equipmentDropDownEditor" required data-text-field="name" data-value-field="name" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoComboBox({
autoBind: false,
dataSource: equipmentTypesDS,
dataBound: function(e) {
var equipmentData = e.sender.dataSource.data();
if(currentlyInsertedEquipmentTypes.length > 0){
for(var i=0;i<currentlyInsertedEquipmentTypes.length;i++){
$.each( equipmentData, function( index, selectedEquipmentData ) {
if (selectedEquipmentData.name == currentlyInsertedEquipmentTypes[i]){
var dataItem = e.sender.dataSource.at(index);
console.log("dataItem: " + dataItem.name + " is being removed");
e.sender.dataSource.remove(dataItem);
}
});
}
}
}
});
}
I've created a global array variable named "currentlyInsertedEquipmentTypes" inside of which I hold all the user's already selected values
(for example if the user has created 2 records inside the grid and has selected "laptop" option in the combobox of the first and "workstation" option
in the combobox of the second --> currentlyInsertedEquipmentTypes = ["laptop", "workstation"] ).
Inside the combobox dataBound event I check whether the user has already selected values (currentlyInsertedEquipmentTypes.length>0)
and if he has, I locate the corresponding object inside the bound dataSource and I remove it, so that it wont be available in the next record's combobox list.
This is where the whole thing crashes even though the data item removal takes place.
Am i missing something that i should do after the data item removal? Should i rebind the datasource to the combobox in some way?
Any help would be much appreciated.
[EDIT]
---- The combobox datasource code
var equipmentTypesDS= new kendo.data.DataSource({
transport: {
read: {
url: "api/equipment_types",
type: "GET",
data: {
//"equipment_category": 1
},
dataType: "json"
}
},
schema: {
data: "data",
total: "total"
}
});
--- the kendo grid code:
$("#popup_equipment").kendoGrid({
dataSource: {
schema:{
model:{
id: "equipment_type_id",
fields:{
equipment_type_id: { editable: false },
name: { }, //validation: {required: true}, defaultValue: "LAPTOP",
items:{ type: "number", defaultValue:1, validation: { required: true, min: 1} }
}
}
}
},
toolbar: ["create"],
columns: [
{ field: "name", title: "εξοπλισμός", width: "300px", editor: equipmentDropDownEditor, template: "#=name#" },
{ field: "items", title:"πλήθος", width: "80px"},
{ command: ["destroy"], title: " ", width: "100px" }
],
//editable: "inline",//true,
editable:{confirmation: false},
scrollable: false,
selectable: false
});
[EDIT 2]
$("#popup_equipment").kendoGrid({
dataSource: {
schema:{
model:{
id: "equipment_type_id",
fields:{
equipment_type_id: { editable: false },
name: { }, //validation: {required: true}, defaultValue: "LAPTOP",
items:{ type: "number", defaultValue:1, validation: { required: true, min: 1} }
}
}
}
},
toolbar: ["create"],
columns: [
{ field: "name", title: "εξοπλισμός", width: "60%", editor: equipmentDropDownEditor, template: "#=name#" },
{ field: "items", title:"πλήθος", width: "20%"},
{ command: ["destroy"], title: " ", width: "20%" }
],
editable:{confirmation: false},
scrollable: false,
selectable: false,
save: function(e){
console.log("GRID SAVE EVENT! ", e);
var equipment_name = e.values.name;
equipmentTypesDS.get(equipment_name).used = true;
console.log("equipmentTypesDS", equipmentTypesDS);
console.log("END OF GRID SAVE EVENT!");
}
});
function equipmentDropDownEditor(container, options) {
var equipmentComboBox = $('<input id="equipmentDropDownEditor" required data-text-field="name" data-value-field="name" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoComboBox({
autoBind: false,
dataSource: equipmentTypesDS,
});
}
var equipmentTypesDS= new kendo.data.DataSource({
transport: {
read: {
url: "api/equipment_types",
type: "GET",
data: {
//"equipment_category": 1
},
dataType: "json"
}
},
schema: {
data: "data",
total: "total",
model:{
id: "name"
}
},
filter: { field: "used", operator: "neq", value: true }
});

I would suggest a different approach. Instead of removing the element filter it out.
Example: I define a DataSource with a list of Cities (your Inserted Equipment) as follow:
var cityDS = new kendo.data.DataSource ({
data : [
{ City : "Seattle", used : false },
{ City : "Tacoma", used : false },
{ City : "Kirkland", used : false },
{ City : "Redmond", used : false },
{ City : "London", used : false },
{ City : "Philadelphia", used : false },
{ City : "New York", used : false },
{ City : "Boston", used : false }
],
schema : {
model : {
id : "City"
}
},
filter: { field: "used", operator: "eq", value: false }
});
As you can see I added a field called used that simply says if that City is already used or not. And I set it as id of this DataSource. In addition, I set a filter saying that I only want those where used id equal (eq) to false.
The editor function is pretty much yours:
function cityDropDownEditor(container, options) {
var equipmentComboBox = $('<input required data-text-field="City" data-value-field="City" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoComboBox({
autoBind: false,
dataSource: cityDS
});
}
but with no dataBound or any other event handler.
Finally in the Grid when I save a record, I filter that city from the list. Something like:
var grid = $("#grid").kendoGrid({
dataSource: ds,
editable : "popup",
pageable : true,
toolbar: [ "create" ],
columns :
[
{ field: "FirstName", width: 90, title: "First Name" },
{ field: "LastName", width: 200, title: "Last Name" },
{ field: "City", width: 200, editor : cityDropDownEditor }
],
save : function(e) {
console.log("e", e);
var city = e.model.City;
cityDS.get(city).used = true;
}
}).data("kendoGrid");
This might work if you start the Grid with no elements otherwise you would have to conveniently initialize the used field. It might require some additional code dealing with cases as changing the City but from your description, doesn't seem to be the case.
You can see this running here : http://jsfiddle.net/OnaBai/ZH4aD/

Related

How to disable checkbox of a row in kendo grid using javascript function

I have a kendo grid where columns are defined and 2 columns are checkbox type. based on some validation in the comments row data, I want to disable the checkbox of that particular row in the grid.
I have a separate javascript function that I am using for validation but I am not able to disable the checkbox of that row. I am adding both the kendo grid code and the javascript function.
Kendo Grid:
createGrid: function (data) {
$("#ProductGrid").kendoGrid({
dataSource: {
data: tableData
},
columns: [
{ field: "Accept", tilte: commonLib.readMessageByUserLanguage(COLUMNTITLENAME.Accept), "template": "<input type=\"checkbox\" />" },
{ field: "Decline", tilte: commonLib.readMessageByUserLanguage(COLUMNTITLENAME.Decline), "template": "<input type=\"checkbox\" />" },
{ field: "Item", tilte: commonLib.readMessageByUserLanguage(COLUMNTITLENAME.Item) },
{ field: "PartID", title: commonLib.readMessageByUserLanguage(COLUMNTITLENAME.PartID) },
{ field: "Description", title: commonLib.readMessageByUserLanguage(COLUMNTITLENAME.Description), width:'300px' },
{ field: "SubPart", title: commonLib.readMessageByUserLanguage(COLUMNTITLENAME.SubPart) },
{ field: "SubPartDescription", title: commonLib.readMessageByUserLanguage(COLUMNTITLENAME.SubPartDescription) },
{ field: "BusinessPartner", title: commonLib.readMessageByUserLanguage(COLUMNTITLENAME.BusinessPartner) },
{ field: "ReqDelTM", title: commonLib.readMessageByUserLanguage(COLUMNTITLENAME.ReqDelTM) },
{ field: "EarDelTM", title: commonLib.readMessageByUserLanguage(COLUMNTITLENAME.EarDelTM) },
{ field: "EarDelDate", title: "Ear Del Date", hidden: true },
{ field: "Comments", title: commonLib.readMessageByUserLanguage(COLUMNTITLENAME.Comments) },
]
});
},
JS Function:
checkComments: function () {
var productGrid = $("#ProductGrid").data("kendoGrid");
var productGridData = productGrid.dataSource;
var noofproduct = productGridData.data().length;
var dataList = productGridData.data();
for (var i = 0; i < noofproduct; i++)
{
if (dataList[i].Comments == "Date not met")
{
(dataList[i].Accept.enable(false));
}
}
}
You can use kendo templates to disable your checkboxes by condition.
var data = [
{disabled: false},
{disabled: true},
{disabled: false}
];
$('#grid').kendoGrid({
dataSource: data,
columns: [{
title: "checkbox",
template: function (item){
return "<input type='checkbox' " + (item.disabled ? 'disabled': '') + ">"}
}]
});
You can try this solution here

Kendo grid not showing data only on the initial load, but works fine when stepping through with breakpoints

The problem I'm having is exactly what I said in the title. When I step through my application in the debugger it properly sets everything that needs to be set, but when I just let it go through on its own, it never loads data on the initial attempt, but if i go back and click the same thing again, or any thing else that has to send data to this grid, it will forever work. Even if I go to a page that empties everything in the grid and then go back to one that shows data again.
To me it sounds like a timing issue, but using $timeout() before the data calls doesn't seem to be working. And I set up a broadcast that should only be called after all the data is pulled in and set, and only then should it go to the code for the kendo grid and start painting it on the page.
Like I said stepping through this code line by line on the initial load of the page, it works exactly as it should and pulls in all data that it needs, but letting it just run without me doing that, it never does.
here is hopefully enough code to go off of.
Here is the code for my grid:
$scope.$on('loadRxHistoryGrids', function () {
console.log('user id of ' + pServ.patientId.get());
$scope.activeHistoryGrid = {
pageable: {
pageSizes: [5, 10, 15, 20],
},
dataSource: new kendo.data.DataSource({
type: 'aspnetmvc-ajax',
contentType: "application/json; charset=utf-8",
transport: {
read: {
url: function () {
var x = pServ.patientId.get();
return "api/rx/ActiveRxHistory/" + pServ.patientId.get();
},
dataType: "json",
type: "POST"
},
},
pageSize: 5,
schema: {
model: {
fields: {
rxId: { type: "number" },
refillsLeft: { type: "number" },
shortName: { type: "string" },
unitsRemaining: { type: "number" },
dispenseRefillQuantity: { type: "number" },
description: { type: "string" },
shipDate: { type: "date" }
},
},
data: function (data) {
if (data != undefined) {
$scope.ActiveHistoryCount = data.length;
return data;
} else { return []; }
},
total: function (data) {
return data.length;
},
},
}),
serverPaging: true,
serverSorting: true,
serverFiltering: true,
columns: [
{ hidden: true, field: "rxId"},
{ field: "shortName", title: "DRUG NAME"},
{ field: "refillsLeft", title: "REFILLS LEFT", width: "16%", template: '#= (refillsLeft == null) ? " " : kendo.toString( refillsLeft, "n0")#', attributes: { style: "text-align:left" } },// template: '<div style="text-align:left">#= ((unitsRemaining == null) || (dispenseRefillQuantity == null)) ? " " : kendo.toString(unitsRemaining / dispenseRefillQuantity, "n5")#</div>' },
{ field: "description", title: "STATUS", width: "14%", template: '<div style="text-align:left">#= (description == null) ? " " : description#</div>' },
{ field: "shipDate", title: "SHIPPED DATE", width: "15%", template: '#= (shipDate == null) ? " " : kendo.toString(kendo.parseDate(shipDate), "MM/dd/yyyy") #' }
],
groupable: false,
scrollable: true,
selectable: true,
resizeable: true,
sortable: true,
}
Here is the other code where the broadcast is being sent:
$scope.$on('loadPatientProfileData', function () {
//A lot of data gets and sets are being done here for other things on the
//page, all data is being set in the grid datasource itself
setTimeout(function () {
$rootScope.$broadcast('patientProfile-DataPullFinish');
$rootScope.$broadcast('loadRxHistoryGrids');
}, 100);
});

KendoUI+AngularJS : Showing dropdown list for an inline editor in a hierarchical nested grid

I am having a hierarchical nested Kendo grid. The parent grid is displaying a list of currency and each currency has a list of allocation. Both grid have a inline editor. Currency has a property 'currencyName' and allocation has a property 'allocationName'. Both these property need to have a kendo dropdownlist editor.
In my solution, I am able to get the drop down for the currencyName, but for allocationName I am getting a textbox. Below is the code:
HTML :
<div kendo-grid="ctrl.currencyKendoGrid" style="margin-top: 2em" k-options="ctrl.currencyGridOptions"></div>
Currency Grid DataSource:
This is being assigned by another parent funds grid. The funds grid has an editable pop-up window, and assigns the currencyKendoGrid it's data source on the edit event as follows.
edit: function (e) {
if (e.model.currencies)
ctrl.currencyKendoGrid.dataSource.data(e.model.currencies);
}
Currency DropDown DataSource:
ctrl.currencyDataSource = new kendo.data.DataSource({
type: "json",
transport: {
read: function (e) {
DataSvc.getCurrencyData().then(function (response) {
e.success(response.data);
});
}
}
});
Allocation DropDown DataSource:
ctrl.allocationsList = [{ allocName: "Cash", allocId: 1 }, { allocName: "Money Market", allocId: 2 }, { allocName: "TBill", allocId: 3 }, { allocName: "FX-Forward", allocId: 4 }];
ctrl.allocationDataSource = new kendo.data.DataSource({
type: "json",
transport: {
read: function (e) {
e.success(ctrl.allocationsList);
}
}
});
Currency Grid Options:
ctrl.currencyGridOptions = {
dataSource: {
schema: {
model: {
fields: {
currency: { type: "string", editable: true }
}
}
}
},
editable: "inline",
toolbar: [{
name: 'create',
text: 'Add Currency',
}],
columns: [
{
field: "currencyName", title: "Currency",
editor: function (container, options) {
$('<input kendo-drop-down-list required k-data-text-field="\'currencyName\'" k-data-value-field="\'currencyName\'" k-data-source="ctrl.currencyDataSource" data-bind="value:' + options.field + '"/>')
.appendTo(container);
}
},
{ command: [{ name: "edit", text: "" }, { name: "destroy", text: "" }], title: " ", width: "250px" }
],
detailInit: detailInitCurrency,
dataBound: function () {
this.expandRow(this.tbody.find("tr.k-master-row").first());
},
}
Allocation Grid Options:
function detailInitCurrency(e) {
if (e.data.allocations)
ctrl.selectedCurrencyAllocations = e.data.allocations;
$("<div/>").appendTo(e.detailCell).kendoGrid({
dataSource: {
transport: {
read: function (e) {
e.success(ctrl.selectedCurrencyAllocations);
},
},
filter: { field: "currencyId", operator: "eq", value: e.data.currencyId },
schema: {
model: {
id: "allocationId",
fields: {
allocationId: { type: "number", editable: false },
allocationName: { type: "string", editable: true },
}
}
}
},
editable: "inline",
toolbar: [{
name: 'create',
text: 'Add Allocation',
}],
columns: [
{
field: "allocationName", title: "Allocation",
editor: function (container, options) {
$('<input kendo-drop-down-list required k-data-text-field="\'currencyName\'" k-data-value-field="\'currencyName\'" k-data-source="ctrl.allocationDataSource" data-bind="value:' + options.field + '"/>')
.appendTo(container);
}
},
{ command: [{ name: "edit", text: "" }, { name: "destroy", text: "" }], title: "", width: "250px" }
]
});
}
Output :
Please feel free to point me out on any code that I may have missed since I have removed a lot of unnecessary code for keeping the problem simple.

Update function in Kendo UI Grid (using with AngularJs) never fires, using with Local Data

I have a Kendo UI grid, which is bound to an KendoObservableArray. I am using inline edit mode. And my options are declared as below :
valueMapCtrl.lookupMappingDetails = new kendo.data.ObservableArray([]);
valueMapCtrl.gridOptions = {
dataSource: new kendo.data.DataSource({
type: "json",
transport: {
read: function (options) {
options.success(valueMapCtrl.lookupMappingDetails);
},
update: function (options) {
console.log("Update", options);
options.success(options.data);
},
create: function (options) {
console.log("Create", options);
options.data.mappingId = mappingId;
mappingId = mappingId + 1;
options.success(options.data);
},
destroy: function (options) {
console.log("Delete", options);
options.success(options.data);
},
parameterMap: function (options, type) {
// this is optional - if we need to remove any parameters (due to partial OData support in WebAPI
console.log(options, type);
if (operation !== "read" && options.models) {
return JSON.stringify({models: options});
}
},
},
change: function (e) {
console.log("change: " + e.action);
// do something with e
},
error: function (e) {
// handle error
alert("Status: " + e.status + "; Error message: " + e.errorThrown);
},
//data: valueMapCtrl.dynamicData,
schema: {
model: {
id: "mappingId",
fields: {
mappingId: {editable: false, nullable: false, defaultValue: 0},
Col1: {
type: "string",
validation: {
required: true
}
},
Col2: {
type: "string",
validation: {
required: true
}
}
}
}
},
pageSize: 10,
batch: false
}),
columns: [{
field: "col1",
title: "Column 1"
}, {
field: "col2",
title: "Column 2"
}, {
command: /*"destroy"*/ ["edit", "destroy"],
title: " ",
width: "200px"
}],
selectable: "multiple cell",
allowCopy: "true",
//save: function (e) {
// console.log("Save", e);
//},
toolbar: ["create"],
height: 300,
navigatable: true,
filterable: true,
sortable: true,
pageable: true,
editable: "inline"
};
Add record : create fires correctly
Delete record: destroy fires correctly
Update record : nothing happens, no error, all I see in change event sync() action.
But If I declare save as well in my options, that fires correctly.
save: function (e) {
console.log("Save", e); //This fires on each update
},
I am not sure what is wrong in above declaration; browsed through a lot of forums/questions for similar issue but could not get it working. Any help ?
I was able to get it working, posting here in case anyone gets the same issue.
valueMapCtrl.lookupMappingDetails = new kendo.data.ObservableArray([]);
I changed this observable array to normal array and things worked fine after that :
valueMapCtrl.lookupMappingDetails =[];// new kendo.data.ObservableArray([]);
Also, with observable array, I was facing another issue; where cancelling of edit was removing ALL ROWS from the grid. That also worked correctly after this change. Not sure of the reason though and couldn't find any explanation in telerik docs (Whatever I could search).

AngularJS Kendo UI grid with row filters behaviour

I am using Kendo UI Grid with row filters. i am facing filters options issue. I am using Filterbale.cell.template for filters to display kendo autoComplete.
Issue is as displayed in image autocomplete options are not updating on selecting of one of the filters.
Below is my html
<div ng-controller="VehiclesController" class="my-grid" >
<kendo-grid options="vehiclesGridOption">
</kendo-grid>
</div>
Below is my Controller
$scope.vehiclesGridOption = {
dataSource: {
schema: {
id: "_id",
model: {
fields: {
make: {type: "string"},
model: {type: "string"},
year: {type: "number"}
}
}
},
transport: {
read: function (e) {
vehicleService.vehicles().then(function (response) {
e.success(response);
console.log(response.length);
}).then(function () {
console.log("error happened");
})
}
},
pageSize: 12,
pageSizes: false,
},
sortable: {
mode: "multiple",
allowUnsort: true
},
filterable: {
mode: "row"
},
pageable: {
buttonCount: 5
},
columns: [
{
title: "",
template: '',
width: "3%" // ACTS AS SPACER
},
{
field: "make",
title: "Make",
filterable: {
cell: {
operator: "contains",
template: function (args) {
args.element.kendoAutoComplete({
dataSource: args.dataSource,
dataTextField: "make",
dataValueField: "make",
valuePrimitive: true,
placeholder: "Make",
});
}
}
},
width: "29%",
}, {
field: "model",
filterable: {
cell: {
operator: "contains",
template: function (args) {
console.log(args);
args.element.kendoAutoComplete({
dataSource: args.dataSource,
dataTextField: "model",
dataValueField: "model",
valuePrimitive: true,
placeholder: "Model",
});
}
}
},
title: "Model",
width: "29%",
}, {
field: "year",
title: "Year",
filterable: {
cell: {
template: function (args) {
args.element.kendoAutoComplete({
dataSource: args.dataSource,
dataTextField: "year",
dataValueField: "year",
placeholder: "Year",
suggest: true,
ignoreCase: true,
filter: "gte"
});
}
}
},
width: "29%",
},
{
field: "",
title: "Edit",
template: '<a class=\"k-link text-center grid-edit-btn vehicle-grid-edit-btn\" ui-sref="vehicleDetails({\'id\': \'#=_id #\' })"><span class=\"icon-editpencil icon-grid\"></span></a>',
width: "10%",
}],
};
Below is the Issue if user selects the Make in the first column filter then Model filter should display only selected make models like Honda (make)-> Accord , Civic ..etc but its displaying all unique values irrespective of model filter..
Kendo filter row uses the same dataSource from the grid component, just providing unique values. Since the autocomplete components are initialized when the grid dataSource is empty, they always show all the values.
You can manually filter based on current filter row values.
Firstly, add ids for your coresponding autocomplete components i.e. inside template functions:
args.element.attr('id', 'make');
//<...>
args.element.attr('id', 'model');
//<...>
args.element.attr('id', 'year');
Then add a data bound event to the grid (since autocomplete components do not fire change events when filters are cleared).
$scope.vehiclesGridOption = {
//...
dataBound : function(e) {
setTimeout(function() { //timeout is to make sure value() is already updated
var make = $('#make').data('kendoAutoComplete').value();
if (make) {
$('#model').data('kendoAutoComplete').dataSource.filter({field: 'make', operator: 'eq', value: make });
} else {
$('#model').data('kendoAutoComplete').dataSource.filter({});
}
});
}
}
Or if you also want to filter by "Year" column, it could go like this:
$scope.vehiclesGridOption = {
//...
dataBound: function(e) {
setTimeout(function() { //timeout is to make sure value() is already updated
var make = $('#make').data('kendoAutoComplete').value();
var model = $('#model').data('kendoAutoComplete').value();
if (make) {
$('#model').data('kendoAutoComplete').dataSource.filter({field: 'make', operator: 'eq', value: make });
} else {
$('#model').data('kendoAutoComplete').dataSource.filter({});
}
var yearFilter = {filters: [], logic: 'and'};
if (make) {
yearFilter.filters.push({field: 'make', operator: 'eq', value: make });
}
if (model) {
yearFilter.filters.push({field: 'model', operator: 'eq', value: model });
}
$('#year').data('kendoAutoComplete').dataSource.filter(yearFilter.filters.length ? yearFilter : null);
});
}
}

Resources