Dropdown in kendo UI grid - javascript

I need a drop down for a Kendo-UI grid, and came across this example:
http://codepen.io/jordanilchev/pen/cnkih?editors=001
But in this example, both the key and the display text for the drop down are included in the data source of the grid as well, which seems very redundant. I looked at a similar example on Telerik's site, and it was the same there.
Here is the data source for the Type drop-down:
var types = [
{
"Type": "FB",
"Name": "Facebook"
},
{
"Type": "TW",
"Name": "Twitter"
},
{
"Type": "YT",
"Name": "YouTube"
},
{
"Type": "PI",
"Name": "Pinterest"
}
];
So far so good. But here is the data for the actual grid - notice how it also contains both Type and Name for every record:
var products = [{
"ProductID": 1,
"ProductName": "Chai",
"Type": {
"Type": "FB",
"Name": "Facebook"
}
}, {
"ProductID": 2,
"ProductName": "Chang",
"Type": {
"Type": "FB",
"Name": "Facebook"
}
}...
What I had expected is that only the Type would have to be in the data source of the grid - like this:
var products = [{
"ProductID": 1,
"ProductName": "Chai",
"Type": "FB",
}, {
"ProductID": 2,
"ProductName": "Chang",
"Type": "FB",
}...
Is there a way to use a drop-down in the Kendo UI grid without having to include both the key and the display text for every record in the data source of the grid? In other words, the grid would know to reference the datasource of the drop-down to get the display text for the cell.
Update 9/23/2014:
The solution proposed by CodingWithSpike works fine when the datasource for the drop down is a hard-coded / local array, but I am having difficulties getting it to work when loading the data for the drop down from a server. The issue seems to be that the grid gets initialized before the data source for the drop down has been read.
To "simulate" an $http call to populate the data source, I use a setTimeout:
$(document).ready(function () {
var categories = [];
setTimeout(function() {
categories = [{
"value": 1,
"text": "Beverages"
},{
"value": 2,
"text": "Condiments"
},{
"value": 3,
"text": "Confections"
}];
$('#grid').data('kendoGrid').dataSource.read(); // Just as a test, but not even this helps
$('#grid').data('kendoGrid').refresh(); // Just as a test, but not even this helps
}, 1000);
When the data is loaded as above (or via $http), the drop down fields now contain the value (id) instead of the text. Here is a plunker that shows this:
http://plnkr.co/edit/DWaaHGVAS6YuDcqTXPL8?p=preview
Note that the real app is an AngularJs app, and I would rather not use some jQuery hack to wait until the drop down data is available and then create the grid element.
How do I get this working with data from a server?

Take a look at the Kendo demo for "Foreign Key" columns. I think it is exactly what you want.
http://demos.telerik.com/kendo-ui/grid/foreignkeycolumn
They use a list of categories:
var categories = [{
"value": 1,
"text": "Beverages"
},{
"value": 2,
"text": "Condiments"
},{
"value": 3,
"text": "Confections"
},{
"value": 4,
"text": "Dairy Products"
},{
"value": 5,
"text": "Grains/Cereals"
},{
"value": 6,
"text": "Meat/Poultry"
},{
"value": 7,
"text": "Produce"
},{
"value": 8,
"text": "Seafood"
}];
The demo is a little deceiving because their data for the grid contains the entire "Category":
var products = [{
ProductID : 1,
ProductName : "Chai",
SupplierID : 1,
CategoryID : 1,
QuantityPerUnit : "10 boxes x 20 bags",
UnitPrice : 18.0000,
UnitsInStock : 39,
UnitsOnOrder : 0,
ReorderLevel : 10,
Discontinued : false,
Category : {
CategoryID : 1,
CategoryName : "Beverages",
Description : "Soft drinks, coffees, teas, beers, and ales"
}
}
However, if you look at the column definition:
{ field: "CategoryID", width: "200px", values: categories, title: "Category" },
The specified field is CategoryID not Category so the grid data item actually doesn't need to specify a "Category" property at all, and could just be:
var products = [{
ProductID : 1,
ProductName : "Chai",
SupplierID : 1,
CategoryID : 1, // <-- this is the important part!
QuantityPerUnit : "10 boxes x 20 bags",
UnitPrice : 18.0000,
UnitsInStock : 39,
UnitsOnOrder : 0,
ReorderLevel : 10,
Discontinued : false
}
I suspect the "Category" was in there just because this JSON file is shared by a few examples, so a different one may have needed it.
Update
Regarding the issue of the Grid loading before the "Category" (or whatever) FK table:
Use a deferred or the callback on the grid datasource to wait until the FK datasource is done loading before populating the grid data. Alternatively, you can init the grid, but set it to autoBind: false so that it doesn't actually read from its DataSource immediately.
Something like this (sorry for any errors, typing this off the top of my head):
(function () {
// for the foreign keys
var categoriesDataSource = new kendo.data.DataSource({
transport: {
read: {
url: "http://somewhere.com/categories"
}
}
});
// for the actual grid data
var gridDataSource = new kendo.data.DataSource({
...
});
// init the grid widget
var gridWidget = $("#grid").kendoGrid({
dataSource: gridDataSource,
autoBind: false, // <-- don't read the DataSource. We will read it ourselves.
columns: [ ... ]
});
// now we can read the FK table data.
// when that completes, read the grid data.
categoriesDataSource.fetch(function () {
gridDataSource.fetch();
});
});

I asked Telerik about this, and here is the solution they gave.
When the drop-down's data is available, use setOptions on the grid, like this (again, I use setTimeout instead of an Ajax call here, for simplicity):
setTimeout(function() {
categories = [{
"value": 1,
"text": "Beverages"
},{
"value": 2,
"text": "Condiments"
},{
"value": 3,
"text": "Confections"
}];
var grid = $('#grid').data('kendoGrid');
var cols = grid.columns;
cols[1].values = categories;
grid.setOptions({columns: cols});
$('#grid').data('kendoGrid').refresh();
}, 200);
Also, autoBind: false is not needed.
Here is an updated plunker:
http://plnkr.co/edit/ZjuK9wk3Zq80yA0LIIWg?p=preview

Related

Attach object to Highcharts click event

Moving from D3 to Highcharts and this is eluding me. I have a fairly complex object that contains a clickthrough object which needs to be accessed in a function on a point click in the series. I'm creating the series array with the data and name just fine with a small conversion, but I need to attach this object to the data points as well. No idea how.
Quick example. original data:
[
{
"key": "Super Cool Thing",
"format": ".2f",
"values": [
{
"label": "01",
"value": 9.5,
"format": ".2f",
"order": 0,
"tooltip": "numerator = 133, denominator = 14",
"clickthrough": {
"output_format": "json",
"metrics": "",
"options": {
"columns": [
{
"order": 1,
"display_as": "Brand",
"format": "{0}",
"name": "brand",
"data_type": "string"
},
{
"order": 2,
"display_as": "Last Submit Time (Month)",
"format": "%m",
"name": "last-submit-time-month",
"data_type": "datetime"
},
{
"order": 3,
"display_as": "Agent Things",
"format": "{0}",
"name": "agent-thing-values",
"data_type": "string"
}
]
},
"cut_y": "brand",
"type": "",
"filter": { },
"cut_x": "last-submit-time-month"
},
"metrics": [
{
"name": "Agent - Feel Appreciated Mean",
"slug": "qcustomersatr4-mean"
}
]
}
]
}
]
run through a (super quick POC) funct:
for(let i = 0; i < data.length; i++){
var values = [];
var xcuts = [];
data[i].values.forEach(val => {
values.push(val.value);
xcuts.push(val.label);
});
chart.addSeries({
name: data[i].key,
data: values
})
chart.xAxis[0].setCategories(xcuts);
}
and this all works fine. But I need the clickthrough object so I can do something like:
plotOptions: {
series: {
allowPointSelect: true,
cursor: 'pointer',
point: {
events: {
click: function (event) {
console.log('CLICKTHROUGH DATA HERE');
console.log(event.point);
}
}
}
},
},
I'm unsure how to format the series data to include additional data that's accessible in an event function later down the line. I currently do this via d3 and it's fine, but am struggling with the Highcharts method to do the same. It seems I can't just add whatever I want to the series or data, so is this possible?
Have it. I have to set the y value explicitly and then I can add whatever else which is then avail in the event.
example:
data[i].values.forEach(val => {
values.push({link: val.clickthrough, y:val.value});
xcuts.push(val.label);
});
chart.addSeries({
name: data[i].key,
data: values
})

AngularJs appending options to select box

I am new to AngularJs. I am having problem in appending options to select boxes created by javascript. Following is my code.
var inputElements = $('<div><label style="float:left;">' + i + '</label><select ng-model="object" class="form-control sel" style="width:300px; float:right; margin-right:75px;"> <option>select</option></select></div></br></br>');
var temp = $compile(inputElements)($scope);
$('#projOrder').append(temp);
$scope.object = object;
//for(var opt=0; opt<selOptLabels.length; opt++) {
$('.sel').append('<option ng-repeat="obj in object" value="'+
{{obj.value}}+'">'+{{obj.value}}+'</option>');
I am getting this error:- SyntaxError: invalid property id
Hi, I am posting json example. This is just a small part of json in my case.
"ProjectOrder": {
"Connect direct required": {
"value": "N",
"id": "STR_15523_62"
},
"Cores": {
"value": ".5",
"id": "NUM_15523_50"
},
"Permanent data in GB": {
"value": "100",
"id": "NUM_15523_56"
},
"Description": {
"value": "AZBNL azbngb",
"id": "STR_15523_2"
},
"Order Id": {
"value": "15523",
"id": "INT_15523_96"
},
"Project cost center": {
"value": "N",
"id": "STR_15523_66"
},
"Project debitor": {
"value": "N",
"id": "STR_15523_64"
},
"Project OE": {
"value": "N",
"id": "STR_15523_57"
},
"Project SITE": {
"value": "N",
"id": "STR_15523_59"
},
"Project Status": {
"value": "RFC",
"id": "STR_15523_54",
"dropdown": [
{
"value": "IW",
"label": "In Work"
},
{
"value": "RFC",
"label": "Ready for Creation"
},
{
"value": "CR",
"label": "Created"
},
{
"value": "FC",
"label": "Failed"
}
]
},
"Project Type (paas, miner)": {
"value": "paas",
"id": "STR_15523_37",
"dropdown": [
{
"value": "paas",
"label": "PaaS Project"
},
{
"value": "miner",
"label": "Miner Project"
}
]
},
"WORK data in GB": {
"value": "100",
"id": "NUM_15523_55"
}
}
Now I have to create input fields and dropdown menus(if there is a dropdown menu) with json data
You really should not be hand-constructing HTML like that. It's best if you use a template and let the template engine handle the heavy lifting.
I also noticed that you're using object as the ng-model. Instead you should have a separate variable which will hold the selected value.
Here's a better way of doing this--in an .html file:
<div ng-repeat="object in listOfObjects"
<label style="float: left">{{ $index }}</label>
<select ng-model="selectedValues[$index]" class="form-control sel"
style="width:300px; float:right; margin-right:75px;"
ng-options="obj.value for obj in object"></select>
</div>
Then in whatever controller you have set up in JavaScript:
// this will be the list of selected values
$scope.selectedValues = new Array(list.length);
// this would be the array that each `object` is part of
$scope.listOfObjects = list;
This isn't the most elegant solution, but basically what I've done is construct an array that is the same length as the list of objects. Angular templates have a special variable $index when you're in an ng-repeat which tracks the current index of the array you're looping through.
So when a user changes the selected value of the 3rd select box (index 2), $scope.selectedValues[2] would be set to the selected option.
EDIT: on transforming the JSON to an array:
var list = Object.keys(json).map(function(jsonKey) {
return {
name: jsonKey,
label: json[jsonKey].label,
value: json[jsonKey].value
};
});`
So.. there are a number of reasons why that won't work. The provided code wouldn't even work because of the template brackets that you are trying to append to your html string...
$('.sel').append('<option ng-repeat="obj in object" value="' +{{obj.value}}+'">'+{{obj.value}}+'</option>');
Is there a reason that you are trying build your markup in js?
It's also advised not to use jquery inside angular controllers. If you have jquery loaded the jQuery object is available through angular.element, otherwise angular uses jQuery light.
Rather than enumerate on the other issues here, I put together this basic example of how a select works in Angular
https://codepen.io/parallaxisjones/pen/BRKebV
Also, you should consult the angular documentation before posting questions to stack overflow. The docs provide a pretty clear example of how to use ng-repeat in a select. https://docs.angularjs.org/api/ng/directive/select
EDIT: I updated my codepen with an example of fetching JSON data with an HTTP GET request
EDIT: updated codepen with provided data example, iterating over object with (key, value) in json syntax in ng-repeat

Kendo re-bind dropdownlist datasource

I have a section of html that contains a rather large set of input controls that is generated dynamically from a set of JSON data returned from the server.
The HTML controls are built from the JSON data along with the items associated with them.
The dropdownlist selection items are bound using the attributes:
data-bind='source: sourceObject'
data-text-field='optionText'
data-value-field='optionValue'
This is the javascript that creates the input select control:
function CreateSelectList(label, i, name) {
var element = '<select data-bind=\'source:reportFormData.FormField[' + i + '].Options.Option\' data-value-field=\'optionValue\' data-text-field=\'optionText\' id=\'' + name + '\' name=\'' + name + '\' data-role=\'dropdownlist\'></select>';
return CreateFormField(label, element);
}
Problem: I need to selectively modify the data source of one of the dropdowns. I can't figure out how to programatically change the datasource.
This doesn't work:
var ddlData = $("#ddl_location").data("kendoDropDownList");
ddlData.setDataSource(jsonData.Option);
nor does this:
$("#ddl_location").kendoDropDownList({
dataTextField: "optionText",
dataValueField: "optionValue",
dataSource: jsonData.Option
});
I've also tried calling these after:
ddlData.trigger("change");
ddlData.refresh();
jsonData.Option is in equivalent format to the original JSON element Report.FormField[i].Options.Option e.g. "Option": [ {"optionText": "All", "optionValue": "0"}, ...
The difference here is that it is a new subset of data that needs to replace the original datasource.
here is a excerpt from the full JSON used to initially create the controls:
{
"Report": {
"report_id": "1",
"FormField": [{
"description": "End DateTime Picker",
"name": "end_date",
"label": "End Date",
"FieldType": "datepicker",
"displayOrder": "2",
"isRequired": "1",
"requiredFieldValidationMessage": "End Date is required."
},
{
"description": "Client",
"name": "ddl_client",
"label": "Client",
"FieldType": "dropdownlist",
"displayOrder": "3",
"isRequired": "0",
"Options": {
"Option": [{
"optionText": "All",
"optionValue": "0"
},
{
"optionText": "*Airport Business Center",
"optionValue": "68955"
},
{
"optionText": "*Cushman & Wakefield",
"optionValue": "68996"
},
{
"optionText": "*IBMC College ",
"optionValue": "68804"
}
...
}
use read() on dataSource:
var ddlData = $("#ddl_location").data("kendoDropDownList");
ddlData.setDataSource(jsonData.Option);
ddlData.dataSource.read();

Handsontable Replace autocomplete values with key before posting

I am using HandsOnTable to make editing database tables more interactive on my site.
HandsOnTable fulfils nearly all my requirements except that some columns in my database actually store foreign keys rather than local string values.
In the UI I would like these columns to appear as dropdown menus where the user selects a readable value mapped to the previously mentioned foreign key (I.e. something like an HTML name/value select).
Unfortunately HandsOnTable does not have such a cell type. The closest thing to it is autocomplete. This allows me to create a dropdown, but it only contains values; no corresponding keys. Here is how it is created:
"source": ["Jebediah", "Bob", "Bill", "Buzz"]
So what I am planning is to send two Json strings from the server:
One containing the parameters needed by HandsOnTable to render the table:
{
"data": [
{ "ID": 1, "Description": "Crude", "Volume": 204, "Customer": "jebediah" },
{ "ID": 2, "Description": "Hidrogen", "Volume": 513, "Customer": "Bob" },
{ "ID": 3, "Description": "Coal", "Volume": '67', "Customer": "Bill" },
{ "ID": 4, "Description": "Wood", "Volume": '513', "Customer": "Buzz" }
],
"columns": [
{ "data": "ID", "type": "numeric" },
{ "data": "Description", "type": "text"},
{ "data: "Volume", "type": "numeric" },
{ "data": "color", "type": "autocomplete", "strict": "true",
"source": ["Jebediah", "Bob", "Bill", "Buzz"]}
]
}
The second mapping keys to values
{
"mappings": [
{"key": 0, "value": "Jebediah"},
{"key": 0, "value": "Bob"},
{"key": 0, "value": "Bill"},
{"key": 0, "value": "Buzz"}
]
}
So far so good. Now for the tricky part:
HandsOnTable has a function (getData()) that allows me to retrieve the tables data as a Json string ready to be sent back to the server:
var jdata = myHandsOnTable.getData();
Where jdata would look something like this:
"data": [
{ "ID": 1, "Description": "Crude", "Volume": 204, "Customer": "jebediah" },
{ "ID": 2, "Description": "Hidrogen", "Volume": 513, "Customer": "Bob" },
{ "ID": 3, "Description": "Coal", "Volume": '67', "Customer": "Bill" },
{ "ID": 4, "Description": "Wood", "Volume": '513', "Customer": "Buzz" }
]
Now before posting, I would like to replace that values for the Customer node with their matching pair key within the mappings json string.
How can I best achieve this in JavaScript/JQuery?
Is there a function that works something as follows?:
jdata.replaceNode('node', mappings)
Thanks
I had a similar issue and here's what I did...
For each foreign key column, I stored 2 values in handsontable; one for the id itself, which I set as a hidden column and the other is the user friendly readable text value as dropdowns.
Everytime the value of a dropdown is changed, I also change the corresponding hidden id. In my case I have a dropdown outside the handsontable as a filter which I use to map key/value pairs, but you could use Hashtables or anything else.
Now the code...
Handsontable config:
afterChange: function (changes, source) { AfterChange(changes, source); }
After change event (called everytime there is a change in the table):
function AfterChange(Changes, Source) {
if (Source === 'loadData') {
return; //don't save this change
}
var rowIndex = 0, columnID = 1, oldTextVal = 2, newTextVal = 3, ntv = '', nv = '';
$(Changes).each(function () {
if (this[columnID] === 'CategoryID') {
// Do nothing...
//To make sure nothing else happens when this column is set through below
}
else if (this[columnID] === 'CategoryName') {
ntv = this[newTextVal];
//This is where I do my mapping using a dropdown.
nv = $('#CategoriesFilterDropdown option').filter(function () { return $(this).text() === ntv; }).val();
//13 is my CategoryID column
$container.handsontable('setDataAtCell', this[rowIndex], 13, nv);
}
});
}
}
This way, you change the foreign keys as you and don't need to loop through it all before saving. It also makes it easy to send the table data as is back to server.
In summary,
The user interacts with CategoryName column (which is of type autocomplete).
The CatgoryID column is hidden to the user by setting the column width to 0 using the colWidths option of handsontable.
When the CategoryName field changes, use afterChange event to set the corresponding CategoryID column. In my case, I use a dropdown somewhere else on the page to map Name => ID, but you can use other means such as a hashtable.
I hope it makes sense...

Knockout mapping not giving me access to properties

For demo purposes, I'm writing a project tracking app. Projects have tasks, people, etc and each have associated properties like title and description.
I created a select list and expected it to be populated with the title properties of each project. Instead, it's being populated with the text of a function. I assume it's because title is an observable. But I don't know how I can ask for the value...
Here is the HTML that isn't populating correctly:
<select data-bind="options: projects,
optionsText: 'title',
optionsValue: 'id',
value: selectedList.id()">
</select>
Here is the javascript with the json included (it's injected using JSON.Net in ASP.Net MVC). The format should be the same, although I tried to sanitize it, so please excuse any missing brackets.
<script type="text/javascript">
var initialData = [
{
"id": "2150980c-1033-4b20-a58b-9e5400abb651",
"title": "project1",
"description": "project 1 description",
"persons": [
{
"id": "1f6f531c-bafa-4fe8-aac8-9e5400abb65a",
"firstname": "p1_fname"
},
{
"id": "1f6f531c-bafa-4fe8-aac8-9e5400abb65a",
"firstname": "p1_fname"
}],
"tasks": [
{
"id": "1f6f531c-bafa-4fe8-aac8-9e5400abb65a",
"title": "task1"
},
{
"id": "1f6f531c-bafa-4fe8-aac8-9e5400abb65a",
"title": "task2"
}]
},
{
"id": "54d4dc7c-0928-4c05-93a2-9e5400abb6a0",
"title": "project2",
"description": "project 2 description",
"persons": [
{
"id": "1f6f531c-bafa-4fe8-aac8-9e5400abb65a",
"firstname": "p1_fname"
},
{
"id": "1f6f531c-bafa-4fe8-aac8-9e5400abb65a",
"firstname": "p1_fname"
}],
"tasks": []
}
];
var viewModel = {
projects: ko.mapping.fromJS(initialData)
};
viewModel.selectedList = {
id: ko.observable("")
};
if(viewModel.projects().length > 0)
viewModel.selectedList.id(viewModel.projects()[0].id());
ko.applyBindings(viewModel);
</script>
EDIT:
Green was right. The code is fine. I hadn't provided enough information. I was using Knockout 1.1.1 with mapping plugin 0.5. This is what caused the problem. Knockout is currently on v1.1.2. When I upgraded to 1.1.2, it worked. Good catch green. I should have checked it in fiddle first.
Note: It doesn't look like there is currently any documentation indicating the requirement to use 1.1.2.
I don't see the problem with the code. The fiddle shows the selection is correctly populated with project title: http://jsfiddle.net/greenlaw110/Tkqqb/3/

Categories