How can i use a Backbone.Collection as optionValues for a Backgrid.SelectCell? - backbone.js

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?

Related

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);
});
}
}

How to hide backgrid column?

Hi friends. I'm using backgrid in my project. I want to hide Id column from backgrid. Here is my code.
var columns = [
{ name: "id", label: "Id", cell: "integer", editable: false },
{ name: "payment_date", label: "Payment Date", cell: "date" ,editable: false },
{ name: "number_of_task", label: "Total Task", cell: "integer" ,editable: false },
{ name: "amount", label: "Amount", cell: "integer" ,editable: false }
];
add a renderable: false attribute. See renderable here http://wyuenho.github.io/backgrid/api/index.html#!/api/Backgrid.Column
Simply remove the column definition. You don't need a column definition for each addribute in your data; you only need the column definition of attributes you want visible in the table.
var columns = [
{ name: "payment_date", label: "Payment Date", cell: "date" ,editable: false },
{ name: "number_of_task", label: "Total Task", cell: "integer" ,editable: false },
{ name: "amount", label: "Amount", cell: "integer" ,editable: false }];
The attribute renderable:false didn't work for me hence used below as workaround
var HideCell = Backgrid.HideCell = Backgrid.Cell.extend({
/** #property */
className: "hide-cell",
initialize: function () {
Backgrid.Cell.prototype.initialize.apply(this, arguments);
},
render: function () {
this.$el.hide();
return this;
}
});
use in column as cell "hide"
var columns = [
{ name: "id", label: "Id", cell: HideCell, editable: false }
];

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

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/

Backbone-UI, TableView, rendering columns

I'm trying to render a table view with four columns, 'name', 'birthday', 'gender', 'married', but
a) they columns aren't showing up at all
b) I'm not even sure if I am passing them correctly, because when I console.log table.options the columns property is rendered as "empty":
Object {columns: Array[0], emptyContent: "no entries", onItemClick: function, sortable: false, onSort: null}
I've tried this:
var table = new Backbone.UI.TableView({
model: people,
columns: [
{ title: "Name", content: 'name' },
{ title: "Gender", content: "gender" } },
{ title: "Birthday", content: "birthday" } },
{ title: "Married", content: "married" } }
]
});
And this:
var table = new Backbone.UI.TableView({
model: people,
options: {
columns: [
{ title: "Name", content: 'name' },
{ title: "Gender", content: "gender" },
{ title: "Birthday", content: "birthday" },
{ title: "Married", content: "married" }
]
}
});
The source code change is adding the options as mu is too short said. Change the initialize method of the Backbone.UI.TableView object to be the following within the source code:
initialize : function(options) { //add parameter
Backbone.UI.CollectionView.prototype.initialize.call(this, arguments);
$(this.el).addClass('table_view');
this._sortState = {reverse : true};
this.options = _.extend({}, this.options, options); //Add this line
}
I'm sure there might be a better place to put this but I'm just going through tutorials to learn some advanced backbone stuff considering the documentation does not match the current version I would shy away from using the library in production as of right now. Hopefully it is fixed in the future.

Backgrid unable to render columns

I am just learning the basics of backgrid.js. So when I attempt to replicate the code on the main page Backgrid.js, I am unable to render a grid due to a particular error when passing in an array of objects for the columns. I believe I am using proper format
var columns = [
{ name: "name", label: "Name", cell: "string" },
{ name: "address", label: "Address", cell: "string" },
{ name: "tel", label: "Phone", cell: "integer" },
{ name: "email", label: "Email", cell: "string" },
{ name: "type", label: "Contact Type", cell: "string" }
];
The error Uncaught TypeError: Object [object Object] has no method 'listenTo' occurs in the process of initializing the grid at this step:
var grid = new Backgrid.Grid({
columns: columns,
collection: this.collection
});
Is there an issue with how I am initializing the grid?
The issue was with the version of backbone.js I was using. I reccommend using the proper version of libraries.
Backgrid.js depends on 3 libraries to function:
jquery >= 1.7.0, underscore.js ~ 1.4.0, and backbone.js ~ 0.9.10.
Here's a simple structure on how to use it.
HTML
<div id="container"></div>
JS
$(function(){
/** Columns definition */
var columns = [
{ name: "name", label: "Name", cell: "string" },
{ name: "address", label: "Address", cell: "string" },
{ name: "tel", label: "Phone", cell: "integer" },
{ name: "email", label: "Email", cell: "string" },
{ name: "type", label: "Contact Type", cell: "string" }
];
/** Model instance */
var mdl = Backbone.Model.extend({});
/** Collection instance */
var col = Backbone.Collection.extend({
model: mdl
});
/** Test array of JSON (usually coming from a server) */
var json = [
{"name": "Goose", "address": "a 1st address", "tel": 25500100, "email": "w#test.net","type": 1},
{"name": "Ducky", "address": "a 2nd address", "tel": 25500123, "email": "w#test1.net","type": 2}
];
/** Create the Grid */
var grid = new Backgrid.Grid({
columns: columns,
collection: new col(json)
});
/** Add the Grid to the container */
$("#container").append(grid.render().$el);
});

Resources