I am trying to implement a feature to select an item in kendo's multi-select control with server filtering. when user presses tab on the selected item. Here is my code of kepdown event:
if (e.keyCode === 9) {
var selectedItem = multiSelect.current();
if (selectedItem) {
var selectedIndex = selectedItem.data("idx");
if (selectedIndex >= 0) {
var currentValue = multiSelect.value().slice();
var dataitems = multiSelect.dataSource.view();
var selectedDataItem = dataitems[selectedIndex];
multiSelect.dataSource.filter({});
currentValue.push(selectedDataItem.relatedId);
multiSelect.value(currentValue);
multiSelect.trigger("change");
}
}
}
But it works fine as long as I am searching in same data view i.e. lets say I select two values starting with Cloud and then I select a value starting with App then kendo will remove previous two values starting with Cloud and control will contain just one value selected at the last.
I debugged kendo's code that the issue in function _index of kendo because it finds value in dataSource.view
I have recreated the issue at http://dojo.telerik.com/OtAvi
Your code is not working because you have serverFiltering set to true in the dataSource:
dataSource: {
type: "odata",
serverFiltering: true,
transport: {
read: {
url: "http://demos.telerik.com/kendo-ui/service/Northwind.svc/Products",
}
}
},
Since the data is being filtered on the server, the call multiSelect.dataSource.filter({}); is only clearing the already filtered data. With that said, when you call multiSelect.value(currentValue);, only the values from the currently filtered dataSource can be selected. This is causing the selection to only hold items from the current dataView.
Unless you have a strong reason not to, your easiest fix is to set serverFiltering set to false.
Related
I have the ExtJs form combo which shows the values in the dropdown as checkbox and the value to select. I have used the pagination to list all the values with no of pages. I need the selected value to be retained in the current page even when we move to next or previous page and comes back to the same page(without selecting any thing in prev, next pages).
Code:
Ext.create('Ext.form.ComboBox', {
id: 'ageComboPickerReport',
name: 'ageComboPickerReport',
maxHeight: 150,
margin: '0 5 0 0',
width: 150,
emptyText: "Select tags",
listConfig: {
getInnerTpl: function (displayField) {
return '<div class="x-combo-list-item"><img src="" class="chkCombo-default-icon
chkCombo" /> {' + displayField + '}</div>';
},
autoEl: { 'q-name': 'rpt-age-criteria-list'
}, labelAlign: 'top',
pageSize: 25,
displayField: 'age', valueField: 'id', forceSelection: true, store: me.ageStore,
//Disable Typing and Open Combo
onFocus: function () {
if (!this.isExpanded) {
me.ageStore.load()
this.expand()
} this.getPicker().focus();
}
}),
Could any one tell me how to retain the selected value in the page when move to other page and comes back
I faced a very similar issue, in my case I had a grid with checkbox selection model, and I wanted to retain the selected rows during moving between pages. I am quite sure (although not 100%) that there is no built-in functionality for that in ExtJS. I can tell what I did, hope it helps, although you have to adopt it because it is not for ComboBox, but for Grid.
Since this is a paged store, not all of the records are loaded, only the ones that are currently on the displayed page. (I assume your store is remote because I see you call load on it.) So to achieve what you like, you need to:
keep track of the selected record ids to be able the reset selection on page,
keep track the items (records) themselves as well, since you will likely need them,
after a page is loaded and displayed, set the selection accordingly.
(This solution can have issues, so you need to be careful. Depending on the use case, it is possible for example that the user selects something, goes to another page and come back, but the previously selected row is no more available (it was deleted by someone else). You have to consider whether it affects you.)
The complete code is complicated and not general enough to share it, but I can outline the steps I did:
Set up two data entries in viewmodel to track the selected record ids and items (records):
data: {
multiSelection: {
ids: {},
items: [],
},
}
Add listeners to the grid's select and deselect events in the view:
listeners: {
select: 'onGridSelect',
deselect: 'onGridDeselect',
},
Create onGridSelect and onGridDeselect functions in the controller, and also add a isDataChanged variable to the controller to indicate whether the store was changed (it is changed on each paging). It is important because I will programatically change the selection, and I don't want my listeners to be executed in this case, only when the user interacts. Like this:
isDataChanged: false,
onGridSelect: function(selModel, record, index, eOpts) {
if (isDataChanged) {
return;
}
const viewModel = this.getViewModel(),
multiSelection = viewModel.get('multiSelection');
multiSelection.ids[record.getId()] = true;
Ext.Array.push(multiSelection.items, record);
},
onGridDeselect: function(selModel, record, index, eOpts) {
if (isDataChanged) {
return;
}
const viewModel = this.getViewModel(),
multiSelection = viewModel.get('multiSelection');
delete multiSelection.ids[record.getId()];
Ext.Array.remove(multiSelection.items, record);
},
Finally, add a listeners to the store to detect changes, this will be called every time the user moves between pages. This is a little tricky, because I need to access the grid from the store listeners which is not very ExtJS like, but I had to (store needs to be the grid's store:
store.on('datachanged', function(store, eOpts) {
// this part you have to figure out, my solution is way too specific
// for share
const grid = ...;
// this was important for me, if the store is really changed,
// deleted, added rows etc., I deleted the selection, but
// you can consider it
if (store.getUpdatedRecords().length > 0 ||
store.getRemovedRecords().length > 0 ||
store.getNewRecords().length > 0) {
// access the `viewmodel` and reset `multiSelection` data entries to
// default, I `return` here to skip the rest
return;
}
// disable listener
grid.getController().isDataChanged = true;
const selModel = grid.getSelectionModel(),
multiSelection = grid.getViewModel().get('multiSelection');
// deselect everything
selModel.deselectAll();
// get an array of the saved selection and find out, which
// record from the current page is in the saved multiSelection
const selected = [];
Ext.Array.each(grid.getStore().getRange(), function(record) {
if (multiSelection.ids[record.getId()]) {
Ext.Array.push(selected, record);
}
});
// apply selection to current page
selModel.select(selected);
// enable listener
grid.getController().isDataChanged = false;
}
I have two kendo grids (A, B) ...B its loaded by clicking in A and the its data source its loaded by a property of selected row in A ..
A.accounts
dataSource: {
data: this.gridA.dataItem(this.gridA.select()),
},
My problem its that in B I have to change a property using the grid, but when the property its changed the grid its reloaded and if i have 1000 rows when I change the property in the grid (anyrow, 999 i.e), the scroll back to the beginning
...I have read and try to understand it, but a can't fix it... according to the official documentation, the row selected by
var row = this.gridApprovals.select();
var caBean = this.gridApprovals.dataItem(row);
Its a ObservableObject, so, when I try to change a property, some method (of ObservableOject) it's making this behaviour, and the grid its reloaded, its iterating every data source item...
EDITED:
I forgot to mention.. its important keep the relation between the changes of the B grid and its relation in A slection..
Here is a Dojo Project http://dojo.telerik.com/uYemI/2
How about this?
http://dojo.telerik.com/#Stephen/aNije
I removed the k-rebind attribute and instead wire up the dataSource inside your setCarsGrid() method:
$scope.setCarsGrid = function() {
var row = this.brandGrid.select();
var brand = this.brandGrid.dataItem(row);
var brandObj=brand.toJSON();
var dataSource = new kendo.data.DataSource({
data: brand.cars,
schema:{
model:{
fields:{
id:{editable:false},
model:{editable:false},
color:{type:"string"}
}
},
parse: function(response) {
$.each(response, function(idx, elem) {
elem.id = elem.id+10;
//if you put a break point here, every time you try to edit 'color' field.. will be stop because datasourse is iterated again
console.log("Grid has been reloaded and the editable field 'color' can be edited :'( the id property has been added +10")
});
return response;
}
}
});
// This first time this is called, the carsGrid has not been initialized, so it doesn't exist.
// But subsequent times, we just need to set the new datasource.
if (this.carsGrid) {
this.carsGrid.setDataSource(dataSource);
}
$scope.carsGridOptions = {
dataSource: dataSource,
selectable:true,
editable: true,
columns: [{
field: "id",
},{
field: "model",
},{
field: "color",
}]
};
}
Essentially, I am just separating initialization of the GRID from the setting of the grid's DATASOURCE.
The first time through, you set up the grid options AND set the dataSource and then subsequent times through, we just set the grid to the new dataSource.
This avoids the k-rebind behaviour...which I believe is documented: http://docs.telerik.com/kendo-ui/AngularJS/introduction#widget-update-upon-option-changes
This approach is not suitable for dataBound widgets because those widgets are recreated on each change of their data—for example, after paging of the Grid.
Note, I don't really know angular so there may be a better way to organize this code, but it works.
I am working on setting up a scenario as following:
1) User is shown existing results on first grid
2) User can select multiple results and click an 'Edit' button which will extract the selected items from the first grid
3)Second grid will be populated with the rows the user has selected from the first grid and will allow them to make edits to the content
4)Pressing save will update the results and show the first grid with the rows updated
So far using drips and drabs of various forum threads (here and here), I have managed to accomplish the first two steps.
$("#editButton").kendoButton({
click: function () {
// extract selected results from the grid and send along with transition
var gridResults = $("#resultGrid").data("kendoGrid"); // sourceGrid
var gridConfig = $("#resultConfigGrid").data("kendoGrid"); // destinationGrid
gridResults.select().each(function () {
var dataItem = gridResults.dataItem($(this));
gridConfig.dataSource.add(dataItem);
});
gridConfig.refresh();
transitionToConfigGrid();
}
});
dataItem returns what i am expecting to see with regards to the selected item(s) - attached dataItem.png. I can see the gridConfig populating but with blank rows (gridBlankRows.png).
gridConfig setup:
$(document).ready(function () {
// build the custom column schema based on the number of lots - this can vary
var columnSchema = [];
columnSchema.push({ title: 'Date Time'});
for(var i = 0; i < $("#maxNumLots").data("value"); ++i)
{
columnSchema.push({
title: 'Lot ' + i,
columns: [{
title: 'Count'
}, {
title: 'Mean'
}, {
title: 'SD'
}]
});
}
columnSchema.push({ title: 'Comment'});
columnSchema.push({ title: 'Review Comment' });
// build the datasource with CU operations
var configDataSource = new kendo.data.DataSource({
transport: {
create: function(options) {},
update: function(options) {}
}
});
$("#resultConfigGrid").kendoGrid({
columns: columnSchema,
editable: true
});
});
I have run out of useful reference material to identify what I am doing wrong / what could be outstanding here. Any help/guidance would be greatly appreciated.
Furthermore, I will also need functionality to 'Add New' results. If possible I would like to use the same grid (with a blank datasource) in order to accomplish this. The user can then add rows to the second grid and save with similar functionality to the update functionality. So if there is any way to factor this into the response, I would appreciate it.
The following example...
http://dojo.telerik.com/EkiVO
...is a modified version of...
http://docs.telerik.com/kendo-ui/framework/datasource/crud#examples
A couple of notes:
it matters if you are adding plain objects to the second Grid's dataSource (gridConfig.dataSource.add(dataItem).toJSON();), or Kendo UI Model objects (gridConfig.dataSource.add(dataItem);). In the first case, you will need to pass back the updated values from Grid2 to Grid1, otherwise this will occur automatically;
there is no need to refresh() the second Grid after adding, removing or changing its data items
both Grid dataSources must be configured for CRUD operations, you can follow the CRUD documentation
the Grid does not persist its selection across rebinds, so if you want to preserve the selection in the first Grid after some values have been changed, use the approach described at Persist Row Selection
I have an ExtJS grid that has a PagingToolbar for (remote) paging, and a checkbox column defined as:
{
dataIndex : 'selected',
xtype: 'checkcolumn',
width : 60
}
However, if I check a box and then page forwards and backwards, the checkbox state is not saved - all the checkboxes are unchecked.
I guess since the store only contains data for the current page (from the server), I need some way of storing the state for rows that are not in the current page of data, and then reinstating the checkboxes when I return to that page.
Is there a best practice, or example of storing the checkbox state in the store while paging?
Well, that's so low-level work that no one has yet thought to make a "best practice" for it. E.g.
beforeload:function(store) {
if(!store.checkedItems) store.checkedItems = [];
store.each(function(item) {
store.checkedItems[item.get("Id")] = item.get("selected");
});
},
load:function(store) {
if(!store.checkedItems) store.checkedItems = [];
store.each(function(item) {
item.set("selected",store.checkedItems[item.get("Id")]);
});
}
or
beforeload:function(store) {
if(!store.checkedItems) store.checkedItems = [];
store.each(function(item) {
store.checkedItems[item.get("Id")] = {selected: item.get("selected") }; // extensible if you want to keep more than one checkbox...
});
},
load:function(store) {
if(!store.checkedItems) store.checkedItems = [];
store.each(function(item) {
item.set(store.checkedItems[item.get("Id")]);
});
}
When performing an update on the grid it sends all column data.
I have something where updates are performed after the cell is closed:
change: function (e) {
if (e.action == "itemchange") {
this.sync();
}
}
Instead of sending all the data for every column, how can I get it to only send the data that was changed?
You can check for Isdirty flag.When cell data is modified the respective model item is marked as Isdirty=true.
var data = grid.dataSource.data();
var dirty = $.grep(data, function(item) {
return item.dirty
});
// Dirty array contains those elements modified
console.log("dirty", dirty);
Here I'm doing for the entire grid data.You can do the same for single row.