i need filter a Backgrid by a model sub field. I have the next JSON string from the server:
[{"iduser":
{"iduser":1224,"apellido":"Agostini","nombre":"Juan Ignacio","dni":47121281}
},
{"iduser":
{"iduser":1225,"apellido":"Alvarez","nombre":"Pedro","dni":4712312}
}]
So, i show the user fullname with the next custom StringCell render:
{name: 'fullname', label: 'Nombre completo', cell: Backgrid.StringCell.extend({
render: function(){
var user = this.model.get('iduser');
var fullname = user.apellido + ", " + user.nombre;
this.$el.html(fullname);
return this;
}
}), editable: false, sortable: true}
Now, i try set the filter by "fullname", but not works. Any ideas ?
Because by default each Backgrid column name corresponds to an actual Model attribute name, and sorting will sort on the values of that attribute in every model. In your case, you don't have an Model attribute called "fullname", but you can approximate that by defining a sortValue column attribute.
var columns = [{
name: "fullname",
label: "Nombre completo",
cell: MyStringCell,
editable: false,
sortable: true,
sortValue: function (model, colName) {
var user = model.get("iduser");
return user.apellido + ', ' + user.nombre;
}
}]
Related
I have a Backbone.Collection SprachLandList with a model SprachLand.
SprachLand
'use strict'
module.exports = class SprachLand extends Backbone.Model
SprachLandList
"use strict"
SprachLand = require('../models/SprachLand')
module.exports = class SprachLandList extends Backbone.Collection
model: SprachLand
I want to display another collection with Backgrid and this collection has a model with an attribute with an array of ids referencing the SprachLand models.
Now i want to use the SprachlandList collection for the values of a Select2Cell cell in a Backgrid.
Naively i tried
columns = [
{ name: "id", label: "ID", editable: false, cell: "integer" },
{ name: "bez", label: "Bezeichnung", editable: false, cell: "string" },
{ name: "rub.bez", label: "Rubrik", editable: false, cell: "string" },
{ name: "sl", label: "Sprachlandkombinationen", editable: true, cell:
Backgrid.SelectCell.extend({
#sllist is an instance of the SprachLandList
optionValues: sllist
multiple: true
})
}
]
I want the Select widget display the "bez" attribute" and have the "id" attribute as value.
Here is a JSON representation of sllist
"[{"id":1,"bez":"de-DE"},{"id":2,"bez":"fr-FR"},\
{"id":3,"bez":"en-GB"},{"id":4,"bez":"nl-NL"},\
{"id":5,"bez":"it-IT"},{"id":6,"bez":"de-CH"},\
{"id":7,"bez":"fr-CH"},{"id":8,"bez":"it-CH"},\
{"id":9,"bez":"de-AT"}]"
I get an error:
Uncaught TypeError: 'optionValues' must be of type {Array.<Array>|Array.<{name: string, values: Array.<Array>}>}
How can i get an acceptable representation of the SprachLandList collection for optionValues?
After some searching i found Converting Array of Objects into Array of Arrays
After some meddling i have now a possible solution:
columns = [
{ name: "id", label: "ID", editable: false, cell: "integer" },
{ name: "bez", label: "Bezeichnung", editable: false, cell: "string" },
{ name: "sl", label: "Sprachlandkombinationen", editable: true, cell: Backgrid.SelectCell.extend({
optionValues: sllist.map((obj) ->
nobj = obj.attributes
Object.keys(nobj).sort().map (key) ->
nobj[key]
)
formatter:
fromRaw: (rawValue, model) ->
(if _.isArray(rawValue) then rawValue else (if rawValue? then [rawValue] else []))
toRaw: (formattedValue, model) ->
(if not formattedValue? then [] else _.map(formattedValue, (v) ->
parseInt v
))
multiple: true
})
}
]
The formatter is to convert the string values of the select element back to integers after edit.
Is this a correct solution?
I am using Kendo UI with Angular/Breeze. I have an editable grid with one column being a drop-down menu. Everything works fine until the save happens. The problem is my odata call is expecting:
Id(guid), Name, Description, CategoryId(guid)
When the drop-down is changed it triggers a save command and sends back like this:
Id(guid), Name, Description, Category(categoryId, Name, Desc)
Where and How do I make the grid send back only the `categoryId instead of the whole category object?
vm.columns = [
{ field: 'name', title: 'name' },
{ field: 'desc', title: 'description' },
{
field: 'categoryId',
title: 'group',
template: getCategory,
editor: categoryDropDown
}
];
function categoryDropDown(container, options) {
$('<input data-text-field="categoryName" data-value-field="categoryId" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoDropDownList({
dataTextField: "categoryName",
dataValueField: "categoryId",
dataSource: vm.categories
});
}
function getCategory(item) {
for (var i = 0, length = vm.category; i < length; i++) {
console.log(vm.categories[i].categoryId);
if (vm.categories[i].categoryId === item.categoryId) {
return vm.categories[i].categoryName;
}
}
return '';
}
Here is the schema for the main datasource:
schema: {
model: {
id: 'Id',
fields: {
categoryName: { editable: true },
categoryDesc: { editable: true },
categoryId: { editable: true }
}
}
}
valuePrimitive was the missing key
function categoryDropDown(container, options) {
$('<input data-text-field="categoryName" data-value-field="categoryId" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoDropDownList({
dataTextField: "categoryName",
dataValueField: "categoryId",
dataSource: vm.categories,
valuePrimitive: true
});
}
I am trying to filter a store based on a set of mapped Ext.util.Filters. For example:
comboBox.store.filter(_.map(this.displayFields, function (displayField) {
return {
property: displayField.name,
value: queryString,
anyMatch: true
};
}));
this.displayFields is a list of display fields in my combobox template. In my combobox template I have something like:
'{codeValue} {displayValue} {descriptionValue}'
displayValue is the displayField property on my combobox. When I search for 'co' in my combobox, all displayFields must have 'co' in the value when I apply the filters to the store. My filters look like this:
[
{property: 'codeValue', value: 'co'},
{property: 'displayValue', value: 'co'},
{property: 'desciptionValue', value: 'co'}
]
I would like a set of records that have the value 'co' in any of the displayFields' property.
Each filter is applied after the previous one, resulting in a logical "and". You've probably got that, or you wouldn't be asking. So, how do you get an "or" with Ext? If that were an "or" on values, you could use a regex for value, but you want it on property. As far as I know there isn't a built-in config option for that, but you can do anything you want in filterFn.
Here's, for example, a combo that displays all records with an 'a', either in their code or name, and only them:
Ext.widget('combo', {
renderTo: Ext.getBody()
,store: {
fields: ['id', 'code', 'name']
,data: [
{id: 1, code: 'a', name: 'Foo'}
,{id: 2, code: 'b', name: 'Bar'}
,{id: 3, code: 'ba', name: 'Baz'}
,{id: 4, code: 'z', name: 'Zoo'}
]
,filters: [{
filterFn: function(record) {
var match = false;
Ext.each(fields, function(field) {
if (re.test(record.get(field))) {
match = true;
return false; // break the loop
}
});
return match;
}
}]
}
,displayField: 'name'
,valueField: 'id'
});
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/
Suppose if i have created a grid store like this
var store = Ext.create('Ext.data.ArrayStore', {
fields:['id','title', 'director', 'released', 'genre','tagline', 'price', 'available'],
data: [
[
1,
"Office Space",
"Mike Judge",
"1999-02-19",
1,
"Work Sucks",
"19.95",
1
],
[
3,
"Super Troopers",
"Jay Chandrasekhar",
"2002-02-15",
1,
"Altered State Police",
"14.95",
1
]
]
});
when i run it on browser i could not see anything because it has already been saved in the browser's memory , we need to display it to the the grid to see those data.
if i am editing the grid in the browser using editors plugin, so how can i see the changes made to the grid store? how to see it ?
You can add storeId to the store and then you can use the following global function:
Ext.StoreManager.lookup('storeId');
with this function you can always get the store from anywhere.
the gridpanel has the edit( editor, e, eOpts ) event which can be used after editing is complete.
Example:
var store = Ext.create('Ext.data.ArrayStore', {
storeId: 'gridStore',
(...)
});
var grid = Ext.create('Ext.grid.Panel', {
store: store,
(...),
listeners: {
edit: function(editing, e, eOpts) {
var record = e.record;
console.log('Changes on this record: ', e.record.getChanges());
console.log('Original value: ', (editing.ptype == 'cellediting' ? e.originalValue : e.originalValues));
console.log('New value: ', (editing.ptype == 'cellediting' ? e.value : e.newValues));
}
}
});
//for save on a toolbar
var button = Ext.create('Ext.button.Button', {
text: 'Save',
(...),
handler: function() {
var gridStore = Ext.StoreManager.lookup('gridStore');
console.log('all added, but not synchronized records: ', gridStore.getNewRecords());
console.log('all edited, but not synchronized records: ', gridStore.getUpdatedRecords());
console.log('all modified(added and edited), but not synchronized records:', gridStore.getModifiedRecords());
console.log('all removed, but not synchronized records:', gridStore.getRemovedRecords());
}
});
I'd say it depend.
First, to display you store in a grid, it should be something like this (simplified), following your code:
var grid = Ext.create('Ext.grid.Panel', {
title: 'Test',
store: store,
columns: [
{ text: 'title', dataIndex: 'title' },
{ text: 'director', dataIndex: 'director', flex: 1 }
],
height: 200,
width: 400
});
var MyWindow = Ext.create('widget.window',{width:400,height:200,items:[grid]});
MyWindow.show();
You assigned your store to a local variable "store". Normaly, if you use that store in a grid, and you make changes in that grid, it should reflect in the store.
When you make it editable with the editable grid plugin, changes are directly writen in the store, so this should work:
var currentStoreContent = store.data.items;
or, from the grid:
var currentStoreContent = grid.getStore().data.items