I'm trying to extend a kendo multiselect so that it has a default data source as well as templates. It's all working except the pre-loaded values in the MVVM object. When I start updating the exented multiselect, the value of the MVVM gets updated, the initial items are just not pre-loaded:
kendo.ui.plugin(kendo.ui.MultiSelect.extend({
init: function(element, options) {
var ds = new kendo.data.DataSource({
type: "json",
serverFiltering: true,
transport: {
read: {
url: "/SecurityEntities",
dataType: "json"
},
parameterMap: function(data) {
return {
prefixText: '',
count: 5,
getUsers: true,
getGroups: false
};
}
},
schema: {
data: function(data) {
console.log($.parseJSON(data));
return $.parseJSON(data);
}
}
});
options = options == null ? {} : options;
options.itemTemplate = "...";
options.tagTemplate = "...";
options.dataSource = ds;
kendo.ui.MultiSelect.fn.init.call(this, element, options);
},
options: {
name: 'EntityMultiSelect'
}
}));
kendo.data.binders.widget.entitymultiselect =
kendo.data.binders.widget.multiselect;
Then my html is:
<div data-bind="value: machine.Managers" data-role="entitymultiselect"
data-delay="400" data-animation="false"
data-placeholder="Select users to notify"></div>
And I am binding the whole container to the page's viewModel object.
I've seen other people have issues with this very problem and added the
kendo.data.binders.widget.entitymultiselect =
kendo.data.binders.widget.multiselect;
(And yes that does seem like a bug)
But it still doesn't work.
When there are already values in Machine.Managers, it doesn't load them. However, if I add values to the multiselect, they get added to Machine.Managers .
EDIT:
I've added a live example
At least in your demo it's a trivial problem: your data-value-field is wrong. As a result, the binder can't match the selected elements.
Instead of
<div data-role="entitymultiselect"
data-bind="value: selected"
data-value-field="ProductId"></div>
you need
<div data-role="entitymultiselect"
data-bind="value: selected"
data-value-field="ProductID"></div>
(working demo)
Since you're not defining the value field in the code in your question, it might be the same issue.
Related
I have a grid with dynamic columns:
MODEL
Ext.define('App.mdlCriteriosConcurso', {
extend: 'Ext.data.Model',
fields: [
]
});
STORE
Ext.define('App.strCriteriosConcurso', {
extend: 'Ext.data.Store',
model: 'App.mdlCriteriosConcurso',
autoLoad: false,
proxy: {
type: 'ajax',
api: {
read: 'some url',
update: 'some url',
},
reader: {
type: 'json',
root: 'data',
totalProperty: 'total'
},
writer: {
root: 'records',
encode: true,
writeAllFields: true
}
}
});
GRID
var almacenCriteriosConcurso = Ext.create('App.strCriteriosConcurso');
//Some code ...
{
xtype:'grid',
itemId:'gridCriteriosConcursoV4',
store:almacenCriteriosConcurso,
plugins: [Ext.create('Ext.grid.plugin.CellEditing', {clicksToEdit: 2})],
columns:[]
}
//Some code...
CONTROLLER
Here in the controller I have the next piece of code:
Ext.ComponentQuery.query('viewFichaDetalle #tabpanelsecundario4_1 #gridCriteriosConcursoV4')[0].getStore().addListener('metachange',function(store,meta){
var columnas=0;
var renderer1 = function(v,params,data){
if(v==''){
return '<div style="background-color:#F5FAC3;color:blue;">'+Ext.util.Format.number(0,'0.000,00/i')+'</div>';
}
else{
return '<div style="background-color:#F5FAC3;color:blue;">'+Ext.util.Format.number(v,'0.000,00/i')+'</div>';
}
};
var renderer2 = function(v,params,data){
if(v=='' || v==0){
return '<div style="background-color:#F5FAC3;color:green;">'+Ext.util.Format.number(0,'0.000,00/i')+'</div>';
//return '';
}
else{
return '<div style="background-color:#F5FAC3;color:green;">'+Ext.util.Format.number(v,'0.000,00/i')+'</div>';
}
};
Ext.each(meta.columns,function(col){
if(columnas==2){
meta.columns[columnas].renderer = renderer1;
}
if(columnas>=3){
meta.columns[columnas].renderer = renderer2;
}
columnas++;
},this);
Ext.suspendLayouts();
Ext.ComponentQuery.query('viewFichaDetalle #tabpanelsecundario4_1 #gridCriteriosConcursoV4')[0].reconfigure(store, meta.columns);
Ext.ComponentQuery.query('viewFichaDetalle #tabpanelsecundario4_1 #gridCriteriosConcursoV4')[0].setTitle("<span style='color:red;font-weight:bold;font-size: 12pt'>Criterios del Concurso con ID:</span> "+"<span style='color:black;font-weight:bold;font-size: 12pt'>"+this.IdConcurso+"</span>");
Ext.resumeLayouts(true);
},this);
I create the columns in the php, using the metadata.
With this code I add some renderers to the grid columns. And I see all the data perfect, and can edit the data.
In the php y generate the column and the field like this:
$array_metadata['columns'][]=array("header"=>"<span style='color:blue;'>Resultado</span>","dataIndex"=>"puntos_resultado","width"=>82,"align"=>"right","editor"=>"textfield");
$array_metadata['fields'][]=array("name"=>"puntos_resultado","type"=>"float");
And then pass $array_metadata to 'metaData' response.
But when I try to sync or autosync the store I get this error:
Uncaught TypeError: Cannot read property 'name' of undefined
at constructor.getRecordData (ext-all-dev.js:62247)
at constructor.write (ext-all-dev.js:62192)
at constructor.doRequest (ext-all-dev.js:102306)
at constructor.update (ext-all-dev.js:101753)
at constructor.runOperation (ext-all-dev.js:106842)
at constructor.start (ext-all-dev.js:106769)
at constructor.batch (ext-all-dev.js:62869)
at constructor.sync (ext-all-dev.js:64066)
at constructor.afterEdit (ext-all-dev.js:64162)
at constructor.callStore (ext-all-dev.js:101428)
UPDATE 1
I have fount this thread in Sencha Forums link , and I have tried all posibles solutions and Im getting allways the same error.
The error tells us that you don't fill the model's fields array properly, because that is where name is a required config. In ExtJS 4, you have to add all fields to the model for the sync to work properly.
To be exact, the Model prototype has to be filled with the correct fields before the instances are created.
This means that you will have to override the reader's getResponseData method, because between Ext.decode and readRecords you will have to prepare the model prototype by setting the fields as returned from the server; something like this:
App.mdlCriteriosConcurso.prototype.fields = data.fields;
I don't want select2 multi select drop down loose data in page refresh. select2 drop down should maintain state
below is my code. its working fine, I have only problem that select2 is losing selection/data if we refresh the page.My requirement is even after page refresh it should not remove there values/or empty.
$processOrderNbr.select2({
ajax: getProcessOrderNbr(),
minimumInputLength: 4,
placeholder: " ",
allowClear: false,
multiple: true
});
function getProcessOrderNbr() {
return {
url: 'GetProcessOrder',
dataType: 'json',
delay: 250,
data: function (params) {
return {
searchKeyword: params
};
},
results: function (data) {
return {
results: $.map(data, function (item) {
return {
text: item,
id: item
}
})
};
}
};
}
You need to put them again into the select2 boxes.
I had a similar issue, where I work with window.sessionStorage to store the selected values. After reloading the page, I set the values stored in the session storage into the select2 boxes with this code:
var selectionList = [{ id: window.sessionStorage.getItem("searchValue"), text: window.sessionStorage.getItem("searchValue")}];
$("#searchValue").select2({
data: selectionList
});
$('#searchValue').val(window.sessionStorage.getItem("searchValue")).trigger("change");
To store the values in the window.sessionStorage you can use this code:
$('#searchValue').select2({
...
.on("change", function (e) {
window.sessionStorage.setItem("searchValue", $(this).val());
}
...
Maybe this solution helps you in your case, but someone knows a better solution?
If you need to show the previous wrote value after reloading the page without losing the data that is the solution.
var dataCategory = JSON.parse(sessionStorage.getItem('category'));
var select = $("#category");
select.select2({
tags: true,
allowClear: true,
maximumInputLength: 30,
maximumSelectionLength: 20,
tokenSeparators: [',', ' '],
data: dataCategory
}).on("change", function (e) {
var selected = []; // create an array to hold all currently wrote by user
// loop through each option
$('#category option').each(function() {
// if it's selected, add it to the array above
if (this.selected) {
selected.push(this.value);
}
});
// store the array of selected options
sessionStorage.setItem('category', JSON.stringify(selected));
});
// set and show the previous wrote keywords
var dataCategoryLength = dataCategory.length;
for (var i =0; i < dataCategoryLength; i++) {
$('#category').val(dataCategory).trigger('change');
}
I am using ui-select2, version 3.5.2, trying to do a single select, type-ahead and retrieve from REST api, drop down list.
It looks like it is working except for one major issue, which is that, the ng-model's property gets set to an object {Id: "some id", text: "some text"} instead of the actual Id property. I cannot figure out how to tell ui-select2 control to set the ng-model property to the "Id" field of the object, instead of the whole object.
I have tried various hacks with watchers but didnt get anywhere. I am sure there is something that I am missing because this is something that should be possible easily.
Here is my javascript code:
$scope.selectOptions = {
placeholder: '- Select Value -',
allowClear: true,
minimumInputLength: 2,
initSelection: function (element, callback)
{
if ($scope.myobj && $scope.myobj.Id && $scope.myobj.Id !== '00000000-0000-0000-0000-000000000000')
{
$.ajax("../../api/objs/" + $scope.myobj.Id).done(function (data) {
var res = $(data).map(function (i, o) {
return {
id: o.Value,
text: o.Display
};
}).get();
callback(res[0]);
});
}
},
ajax:
{
type: "GET",
url: function (term) {
return ["../../api", "objs", encodeURIComponent(term)].join("/");
},
dataType: "json",
contentType: "application/json",
cache: false,
results: function (data, page) {
return {
results: $(data).map(function (i, o) {
angular.extend(o, {
id: o.Value,
text: o.Display
});
return o;
}).get()
};
}
}
}
Here is my html code:
<div ui-select2='selectOptions' ng-model="myobj.Id" style="width:215px" />
I got around this by binding to a separate property and then adding a ng-change on my div and syncing the binding property's id field to actual property on my object.
My problem is that I Have Hierarchical grid (Master and Child) let say I Have a Department Grid it contains List of Employee Grid, and they both use same datasource.
Here's my GridChild Code:
function detailInit (e){
var msterRow = e.sender.items().index(e.masterRow).toString();
var grid = $("<div id='childGrid"+msterRow+"'
class=childGrid'/>").appendTo(e.detailCell).kendoGrid({
data: e.data.DeptEmployees,
schema: {
model: { fields: { foo: {--skip--}, bar: {--skip--} } }
},
toolbar: ["create", "cancel", "save"],
editable: "popup",
columns: [ --skip--]
save: function(e){
ajaxUpdateDepartment(msterRow, this.dataSource.data());
}
})
As you can see i use data: e.data.DeptEmployees, as child data source to fetch data.
Now I'm stacked in how can I update the child data source?
What I have Tried:
I add child's dataSource.transport for updates, but my child grid keeps on loading.
So I end up configuring the save: function (e) and simply send all data source of the current child but popup editor didn't close at all. And I'm having difficulty to refresh the child data source.
I also attempt to convert my Master and Child Grid to ASP Razor but there was no definite example if how could I handle it in back end, and also my child grid contains drop down grid, so that would be a big re-do. And I also don't know if how can I pass customize parameter through it
I am desperate, I can't find any working reference except this one. but it's using odata, and I dont have child id to use as reference, since I am only using list which I retrieve in a user event.
Please help :'( I'm taking too much time for this one.
The solution is to define a transport properties, in order to fetch data from master, I only need to define the data and convert that to Jason.
take a look of these code:
function detailInit (e){
var msterRow = e.sender.items().index(e.masterRow).toString();
var grid = $("<div id='childGrid"+msterRow+"'
class=childGrid'/>").appendTo(e.detailCell).kendoGrid({
//data: e.data.ChildDetails,
transport: {
read: function (o) {
console.log("child read");
var data = e.data.ChildDetails.toJSON();
o.success(data);
},
update: function (o) {
console.log("child update");
var data = o.data,
arentItem = findByID(data.id);
for (var field in data) {
if(!(field.indexOf("_") === 0)){
arentItem[field] = data[field];
}
}
e.data.dirty = true;
saveChild(record, "#suffix", msterRow, "update");
o.success();
},
destroy: function (o) {
var parentItem = findByID(o.data.id);
preventBinding = true;
e.data.ChildDetails.results.remove(parentItem);
o.success();
saveChild(record, "#suffix", msterRow, "destroy");
},
create: function (o) {
console.log("child create");
var record = o.data;
record.id = index;
index++;
saveChild(record, "#suffix", msterRow, "create");
o.success(record);
}
},
schema: {
model: { fields: { foo: {--skip--}, bar: {--skip--} } }
},
toolbar: ["create", "cancel", "save"],
editable: "popup",
columns: [ --skip--]
}
Here's the working dojo snippet
i have a kendoui grid which list claims. one of the columns is lenders which is a foreign key reference to the lenders table. what i want is to be able to display the lender name in the grid instead of its id reference.
ive setup the lenders datasource as follows
var dsLenders = new kendo.data.DataSource({
transport: {
read: {
url: "../data/lenders/",
dataType: "jsonp"
},
parameterMap: function(options, operation) {
if (operation === "read") {
return options;
}
}
}
});
and the grid looks like this
$("#gridClaims").kendoGrid({
dataSource: claimData,
autoSync:true,
batch: true,
pageable: {
refresh: true,
pageSizes: true
},
filterable: true,
sortable: true,
selectable: "true",
editable: {
mode: "popup",
confirmation: "Are you sure you want to delete this record?",
template: $("#claimFormPopup").html()
},
navigable: true, // enables keyboard navigation in the grid
toolbar: ["create"], // adds insert buttons
columns: [
{ field:"id_clm", title:"Ref", width: "80px;" },
{ field:"status_clm", title:"Status", width: "80px;" },
{ field:"idldr_clm", title:"Lender", values: dsLenders },
{ field:"type_clm", title:"Claim Type"},
{ field:"value_clm", title:"Value", width: "80px;", format:"{0:c2}", attributes:{style:"text-align:right;"}},
{ field:"created", title:"Created", width: "80px;", format: "{0:dd/MM/yyyy}"},
{ field:"updated", title:"Updated", width: "80px;", format: "{0:dd/MM/yyyy}"},
{ field:"user", title:"User" , width: "100px;"},
{ command: [
{text: "Details", className: "claim-details"},
"destroy"
],
title: " ",
width: "160px"
}
]
});
however its still displaying the id in the lenders column. Ive tried creating a local datasource and that works fine so i now is something to do with me using a remote datasource.
any help would be great
thanks
Short answer is that you can't. Not directly anyway. See here and here.
You can (as the response in the above linked post mentions) pre-load the data into a var, which can then be used as data for the column definition.
I use something like this:-
function getLookupData(type, callback) {
return $.ajax({
dataType: 'json',
url: '/lookup/' + type,
success: function (data) {
callback(data);
}
});
}
Which I then use like this:-
var countryLookupData;
getLookupData('country', function (data) { countryLookupData = data; });
I use it in a JQuery deferred to ensure that all my lookups are loaded before I bind to the grid:-
$.when(
getLookupData('country', function (data) { countryLookupData = data; }),
getLookupData('state', function (data) { stateLookupData = data; }),
getLookupData('company', function (data) { companyLookupData = data; })
)
.then(function () {
bindGrid();
}).fail(function () {
alert('Error loading lookup data');
});
You can then use countryLookupData for your values.
You could also use a custom grid editor, however you'll probably find that you still need to load the data into a var (as opposed to using a datasource with a DropDownList) and ensure that the data is loaded before the grid, because you'll most likely need to have a lookup for a column template so that you're newly selected value is displayed in the grid.
I couldn't quite get ForeignKey working in any useful way, so I ended up using custom editors as you have much more control over them.
One more gotcha: make sure you have loaded your lookup data BEFORE you define the column. I was using a column array that was defined in a variable I was then attaching to the grid definition... even if the lookup data is loaded before you use the grid, if it's defined after the column definition it will not work.
Although this post past 2 years, I still share my solution
1) Assume the api url (http://localhost/api/term) will return:
{
"odata.metadata":"http://localhost/api/$metadata#term","value":[
{
"value":2,"text":"2016-2020"
},{
"value":1,"text":"2012-2016"
}
]
}
please note that the attribute name must be "text" and "value"
2) show term name (text) from the foreign table instead of term_id (value).
See the grid column "term_id", the dropdownlist will be created if added "values: data_term"
<script>
$.when($.getJSON("http://localhost/api/term")).then(function () {
bind_grid(arguments[0].value);
});
function bind_grid(data_term) {
$("#grid").kendoGrid({
dataSource: ds_proposer,
filterable: true,
sortable: true,
pageable: true,
selectable: "row",
columns: [
{ field: "user_type", title: "User type" },
{ field: "user_name", title: "User name" },
{ field: "term_id", title: "Term", values: data_term }
],
editable: {
mode: "popup",
}
});
}
</script>
For those stumbling across this now, this functionality is supported:
https://demos.telerik.com/aspnet-mvc/grid/foreignkeycolumnbinding