I would like to know how to have a dynamic data in JavaScript. Here's the code:
function createChart(selected) {
if (selected === "SMPC5") {
var distanceChart = Highcharts.chart('smpc5Chart', {
chart: {
type: 'column'
},
title: {
text: 'SMPC5',
style: {
fontWeight: 'bold',
size: '5'
}
},
...
function afisChart(selected) {
var mychart = createChart(selected);
mychart.showLoading();
$.ajax({
dataType: "json",
url: "/Statistics/GetChartData/",
data: { data: selected },
success: function (data, textStatus, jqXHR) {
while (mychart.series.length > 0) {
mychart.series[0].remove(false);
}
var xAxisCategories;
if (selected == "SMPC5") {
for (var key in data) {
if (key == "date") {
document.getElementById("updatedate").textcontent = "last updated: " + data[key];
}
else if (key == "Date") {
xAxisCategories = data[key];
}
else {
mychart.addSeries({ name: key, data: data[key] }, false);
}
}
}
else if (selected == "GVP4") {
....
The selected data is bind with the data that it's in C# Controller. What I want is to save the data in an array or list(from controller) and after that send it to JavaScript and loop through it(not test every time using the if and else condition)
Your code doesn't help at all, but I would refer you to the following javascript array functions to solve any problem like this. Once your data is in the array you can use one of them to filter or apply some change to each item and get the new values back individually or as a new array.
Click these to learn more about each.
Array.map()
Array.filter()
Array.forEach()
Array.reduce()
If I knew more about what you were trying to do I could be more specific.
Related
I'm using JsGrid v1.5.3 and i successfully created a field like this using JsGrid
{
name: "1_price",
className: 'wordwrap',
title: 'Test Price',
type: "text",
width: 75,
filtering: false,
sorting: true,
sorter: 'priceSorter',
itemTemplate: function(value, item) {
if (typeof value === 'undefined') value = '';
if (item && item.hasOwnProperty('is_sold_out') && item.is_sold_out == 1) {
return '<span class="sold-out-strikethrough">' + value + '</span>';
} else {
return '<span>' + value + '</span>';
}
}
}
then i tried to create the custom sorter function like this:
window.jsGrid.sortStrategies.priceSorter = function(price1, price2) {
console.log(arguments)
}
from the console.log(arguments) it only send 2 parameters value, how can i extend it so i can receive another parameters, for example the additional parameters is the field name (1_price):
window.jsGrid.sortStrategies.priceSorter = function(price1, price2, fieldName) {
console.log(arguments)
}
You can send multiple parameters by defining them in an Array or JSON object.
window.jsGrid.sortStrategies.priceSorter = function({price1:price1, price2:price2, fieldName:fieldName}) {
console.log(arguments)
}
Or
var params = {price1:price1, price2:price2, fieldName:fieldName};
window.jsGrid.sortStrategies.priceSorter = function(params) {
console.log(arguments)
}
Or
var params = [price1, price2, fieldName];
window.jsGrid.sortStrategies.priceSorter = function(params) {
console.log(arguments)
}
I need the autocomplete of the typeahead to work with the name field and when clicking on the item, the id value is collected.
$('.autocomplete').typeahead({
source: function (query, process) {
return $.get('view/_list.php', { query: query }, function (data)
{
data = $.parseJSON(data);
return process(data);
});
}
});
_list.php
[
{
"id":"47",
"nome":"Maril\u00e2ndia"
},
{
"id":"57",
"nome":"Pi\u00fama"
},
{
"id":"71",
"nome":"Sooretama"
}
]
Autocomplete works only if json does not have the id, only name field, but if you add the name field as it is in the json example, nothing works. And the error in the console is b.toLowerCase is not a function
You can add all the properties you wish on your objects, as long as
you provide a "name" attribute OR you provide your own displayText
method (source).
Here is the defaultText method:
displayText: function (item) {
return typeof item !== 'undefined' && typeof item.name != 'undefined' ? item.name : item;
}
Because you have a nome property in objects in _list.php, not a name property , you need to set displayText method:
$.get("_list.php", function(data){
$(".autocomplete").typeahead({ source:data,
displayText : function(item) {
return item.nome;
}
});
},'json');
Resolved.
$('.autocomplet').typeahead({
displayText: function(item) {
return item.nome
},
afterSelect: function(item) {
this.$element[0].value = item.nome;
$("#field_id").val(item.id);
},
source: function (query, process) {
return $.getJSON('_list.php', { query: query }, function(data) {
process(data)
})
}
})
I have a list of models I want to search through and pull the url for the correct one. I won't always have the full key, and never the full value, but will always have at least a unique part of it.
Right now the code is just in test mode, with a set number that matches a key, print a success or failure.
The console keeps telling me that models[i].indexOf isn't a function. I know it's an object, but when I do a toString on it, I get "object Object". What am I not understanding?
I'm happy with a solution that is either vanilla JavaScript or uses jQuery.
The code:
if ($('.mobile_tutorial').length) {
var device = /*$device.model*/ "NTZEZ717VLU", model_code = device.substr(2).substr(0,device.length-3);
$.ajax({
url: "/scripts/phone_models.json",
type: 'get',
dataType: 'json',
success: function (data) {
var models = data.Manufacturer;
for (var i = models.length - 1; i >= 0; i--) {
if (models[i].indexOf(model_code) > -1) {
console.log(models[i])
} else {
console.log('no match')
}
}
}
});
}
The JSON (partial):
{
"Manufacturer": [{
"ZEZ955L": "http://x.com/mobile/home.seam?custId=ZEZ955L"
}, {
"ZEZ990G": "http://x.com/mobile/home.seam?custId=ZEZ990G"
}, {
"ZEZ828TL": "http://x.com/mobile/home.seam?custId=ZEZ828TL"
}, {
"ZEZ716BL": "http://x.com/mobile/home.seam?custId=ZEZ716BL"
}, {
"ZEZ717VL": "http://x.com/mobile/home.seam?custId=ZEZ717VL"
}, {
"ZEZ962BL": "http://x.com/mobile/home.seam?custId=ZEZ962BL"
}, {
"ZEZ963VL": "http://x.com/mobile/home.seam?custId=ZEZ963VL"
}]
}
models[i] is not a string so you are getting error. If you want to check key then use .each() function on models[i]. In that each loop compare the key using indexOf function.
if ($('.mobile_tutorial').length) {
var device = /*$device.model*/ "NTZEZ717VLU", model_code = device.substr(2).substr(0,device.length-3);
$.ajax({
url: "/scripts/phone_models.json",
type: 'get',
dataType: 'json',
success: function (data) {
var models = data.Manufacturer;
for (var i = models.length - 1; i >= 0; i--) {
$.each(models[i], function( key, value ) {
if (key.indexOf(model_code) > -1) {
console.log(models[i])
} else {
console.log('no match')
}
}
}});
});
}
You would need to grab the value of the key changing models[i].indexOf(model_code) to Object.keys(models[i])[0].indexOf(partial_model_code). Here's it in action:
var partial_model_code = '3VL'
function ajax(data) {
var models = data.Manufacturer;
for (var i = models.length - 1; i >= 0; i--) {
// grab the keys in the object
// since there will only be one object grab the first one
// check if the key partially matches
if (Object.keys(models[i])[0].indexOf(partial_model_code) > -1) {
console.log(models[i])
} else {
console.log('no match')
}
}
}
var data = JSON.parse(`{
"Manufacturer": [{
"ZEZ955L": "http://x.com/mobile/home.seam?custId=ZEZ955L"
}, {
"ZEZ990G": "http://x.com/mobile/home.seam?custId=ZEZ990G"
}, {
"ZEZ828TL": "http://x.com/mobile/home.seam?custId=ZEZ828TL"
}, {
"ZEZ716BL": "http://x.com/mobile/home.seam?custId=ZEZ716BL"
}, {
"ZEZ717VL": "http://x.com/mobile/home.seam?custId=ZEZ717VL"
}, {
"ZEZ962BL": "http://x.com/mobile/home.seam?custId=ZEZ962BL"
}, {
"ZEZ963VL": "http://x.com/mobile/home.seam?custId=ZEZ963VL"
}]
}`)
ajax(data)
I hope that helps!
I am working on an app that uses Select2 (version 3.5.1). The HTML to setup this drop down / autocomplete field looks like this:
<input id="mySelect" class="form-control" type="hidden">
The form-control class in this snippet comes from Bootstrap. I am initializing this field from JavaScript using the following:
function getItemFormat(item) {
var format = '<div>' + item.ItemName + '</div>';
return format;
}
$(function() {
$('#mySelect').select2({
minimumInputLength: 5,
placeholder: 'Search for an item',
allowClear: true,
ajax: {
url: '/api/getItems',
dataType: 'json',
quietMillis: 250,
data: function (term, page) {
return {
query: term
};
},
results: function (data, page) {
return { results: data, id: 'ItemId', text: 'ItemText' };
}
},
formatResult: getItemFormat,
dropdownCssClass: "bigdrop",
escapeMarkup: function (m) { return m; }
});
});
When my select field loads, it successfully renders. Once I type at least the fifth character, it successfully pulls items from the server and lists them as options. However, if I try to select one of them, nothing happens. The drop-down popup stays open. Nothing gets put in the actual field. There are no errors in the JavaScript console. Its like I didn't click anything.
In addition, I noticed that nothing is highlighted when I put my mouse over an item or attempt to navigate the list of options with the arrow keys.
What am I doing wrong?
What is happening:
By default, results of the object you are returning in ajax.results should be an array in this structure [{id:1,text:"a"},{id:2,text:"b"}, ...].
results: function (data, page) {
var array = data.results; //depends on your JSON
return { results: array };
}
In Select2.js it actually states:
* #param options.results a function(remoteData, pageNumber, query) that converts data returned form the remote request to the format expected by Select2.
* The expected format is an object containing the following keys:
* results array of objects that will be used as choices
* more (optional) boolean indicating whether there are more results available
* Example: {results:[{id:1, text:'Red'},{id:2, text:'Blue'}], more:true}
Reading the source code, we can see that ajax.results is called on AJAX success:
success: function (data) {
// TODO - replace query.page with query so users have access to term, page, etc.
// added query as third paramter to keep backwards compatibility
var results = options.results(data, query.page, query);
query.callback(results);
}
So ajax.results is really just a function for you to format your data into the appropriate structure ( e.g. [{id:a,text:"a"},{id:b,text:"b"}, ...]) before the data is passed to query.callback:
callback: this.bind(function (data) {
// ignore a response if the select2 has been closed before it was received
if (!self.opened()) return;
self.opts.populateResults.call(this, results, data.results, {term: term, page: page, context:context});
self.postprocessResults(data, false, false);
if (data.more===true) {
more.detach().appendTo(results).html(self.opts.escapeMarkup(evaluate(self.opts.formatLoadMore, self.opts.element, page+1)));
window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
} else {
more.remove();
}
self.positionDropdown();
self.resultsPage = page;
self.context = data.context;
this.opts.element.trigger({ type: "select2-loaded", items: data });
})});
And what query.callback eventually does is to set the logic up properly so that everything works fine when you choose one of the items and trigger .selectChoice.
selectChoice: function (choice) {
var selected = this.container.find(".select2-search-choice-focus");
if (selected.length && choice && choice[0] == selected[0]) {
} else {
if (selected.length) {
this.opts.element.trigger("choice-deselected", selected);
}
selected.removeClass("select2-search-choice-focus");
if (choice && choice.length) {
this.close();
choice.addClass("select2-search-choice-focus");
this.opts.element.trigger("choice-selected", choice);
}
}
}
So if there is some misconfiguration (e.g. results is not in the correct structure) that causes the class .select2-search-choice-focus not to be added to the DOM element before .selectChoice is called, this is what happens:
The drop-down popup stays open. Nothing gets put in the actual field. There are no errors in the JavaScript console. Its like I didn't click anything.
Solutions
There are many solutions to this. One of them is, of course, do some array keys manipulation in ajax.results.
results: function (data, page) {
//data = { results:[{ItemId:1,ItemText:"a"},{ItemId:2,ItemText:"b"}] };
var array = data.results;
var i = 0;
while(i < array.length){
array[i]["id"] = array[i]['ItemId'];
array[i]["text"] = array[i]['ItemText'];
delete array[i]["ItemId"];
delete array[i]["ItemText"];
i++;
}
return { results: array };
}
But you may ask: why must the id be "id" and the text be "text" in the array?
[{id:1,text:"a"},{id:2,text:"b"}]
Can the array be in this structure instead?
[{ItemId:1,ItemText:"a"},{ItemId:2,ItemText:"b"}]
The answer is yes. You just need to overwrite the id and text functions with your own functions.
Here are the original functions for .selecte2 in Select2.js:
id: function (e) { return e == undefined ? null : e.id; },
text: function (e) {
if (e && this.data && this.data.text) {
if ($.isFunction(this.data.text)) {
return this.data.text(e);
} else {
return e[this.data.text];
}
} else {
return e.text;
}
},
To overwrite them, just add your own functions inside the object you are passing to .selecte2:
$('#mySelect').select2({
id: function (item) { return item.ItemId },
text: function (item) { return item.ItemText }
......
});
Updates
What else is happening :
However, the text of the selected item does not appear in the field after the list closes.
This means .selectChoice has been successfully executed. Now the problem lies in .updateSelection. In the source code:
updateSelection: function (data) {
var container=this.selection.find(".select2-chosen"), formatted, cssClass;
this.selection.data("select2-data", data);
container.empty();
if (data !== null) {
formatted=this.opts.formatSelection(data, container, this.opts.escapeMarkup);
}
if (formatted !== undefined) {
container.append(formatted);
}
cssClass=this.opts.formatSelectionCssClass(data, container);
if (cssClass !== undefined) {
container.addClass(cssClass);
}
this.selection.removeClass("select2-default");
if (this.opts.allowClear && this.getPlaceholder() !== undefined) {
this.container.addClass("select2-allowclear");
}
}
From here we can see that, before the corresponding string of text is placed into the input, it would call formatSelection.
formatSelection: function (data, container, escapeMarkup) {
return data ? escapeMarkup(this.text(data)) : undefined;
},
Update: Solution
Previously I thought this.text(data) can be overwritten by having text: funcion(item){ ... } in the parameters, but sadly it doesn't work that way.
Therefore to render the text properly in the field, you should overwrite formatSelection by doing
$('#mySelect').select2({
id: function (item) { return item.ItemId },
formatSelection: function (item) { return item.ItemText }
//......
});
instead of trying to overwrite text (which should supposedly have the same effect but this way of overwriting is not yet supported/implemented in the library)
$('#mySelect').select2({
id: function (item) { return item.ItemId },
text: function (item) { return item.ItemText } //this will not work.
//......
});
The issue you are facing is that select2 wants all your results to have an id property. If they don't you need to initialise with an id function which returns the id from each result.
It will not allow you to select a result unless you satisfy one of these. So in the case of your example :
function getItemFormat(item) {
var format = '<div>' + item.ItemName + '</div>';
return format;
}
$(function() {
$('#mySelect').select2({
minimumInputLength: 5,
placeholder: 'Search for an item',
allowClear: true,
id: function(item) { return item.ItemId; }, /* <-- ADDED FUNCTION */
ajax: {
url: '/api/getItems',
dataType: 'json',
quietMillis: 250,
data: function (term, page) {
return {
query: term
};
},
results: function (data, page) {
return { results: data, id: 'ItemId', text: 'ItemText' };
}
},
formatResult: getItemFormat,
dropdownCssClass: "bigdrop",
escapeMarkup: function (m) { return m; }
});
});
You need to provide an ID that returns from your API like #itsmejodie said.
The other problem is that you have to provide select2 formatResult and formatSelection functions, once you have it loaded from Ajax but you can't put html on that. e.g.:
function format (item) {
return item.name;
}
$(function() {
$('#mySelect').select2({
minimumInputLength: 2,
placeholder: 'Search for an item',
allowClear: true,
ajax: {
url: '/api/getItems',
dataType: 'jsonp',
quietMillis: 250,
data: function (term, page) {
return {
query: term
};
},
results: function (data, page) {
return { results: data };
}
},
formatResult: format,
formatSelection: format
});
});
For version 4 of Select2 use
processResults: function (data) {
instead of
results: function (data) {
so I've implemented the treeview of Fuel UX within my website. Whenever it's loaded, I need to reselect the items I want manually. Is there a possibility to preselect certain items after each reload?
Thanks in advance!
I was in the same situation since yesterday and could now solve the problem with the solution below. Just explaining that I used the methods present on the button "select nested Test Item 1" on this page. Here's the solution:
var preSelectFolder = function ($treeEl, folder, $parentEl) {
var $elParent = $parentEl || $treeEl;
if (folder.type == "folder") {
var $folderEl = $elParent.find("div.tree-folder-name").filter(function (_, treeFolder) {
return $(treeFolder).text() == folder.name;
}).parent();
$treeEl.one("loaded", function () {
$.each(folder.children, function (i, item) {
preSelectFolder($treeEl, item, $folderEl.parent());
});
});
$treeEl.tree("selectFolder", $folderEl);
}
else {
preSelectItem($treeEl, folder, $elParent);
}
};
var preSelectItem = function ($treeEl, item, $parentEl) {
var $elParent = $parentEl || $treeEl;
if (item.type == "item") {
var $itemEl = $elParent.find("div.tree-item-name").filter(function (_, treeItem) {
return $(treeItem).text() == item.name && !$(treeItem).parent().is(".tree-selected");
}).parent();
var itemId = $($itemEl).data() != null ? $($itemEl).data().id : "";
if (itemId == item.id)
$treeEl.tree("selectItem", $itemEl);
}
else if (item.type == "folder") {
preSelectFolder($treeEl, item, $elParent);
}
};
And in the event of 'loaded' I use this code:
element.on('loaded', function (e) {
angular.forEach(scope.items, function (item) {
preSelectItem($("#BuildTree"), item);
});
});
I use AngularJs so just replace "angular.forEach" for each function of Jquery and "scope.items" are items that should be pre-selected. In my case the items are in the following format:
[
{ name: 'Dir 1', type: 'folder', id: 'D1' },
{ name: 'Dir 2', type: 'folder', id: 'D2' },
{ name: 'Item 1', type: 'item', id: 'i1' },
{ name: 'Item 2', type: 'item', id: 'i2' }
]
Hope that helps.
If by manually, you mean you're actually clicking on the items again there should be a way to do this more programmatically.
I haven't tested it, but if you call $('#MyTree').tree('selectItem', $el) where $el is a .tree-item element, that should select the item.
It would be nice for your datasource to be able to tell the tree which items are selected. I see you've posted the feature request to https://fuelux.uservoice.com/forums/181290-general/suggestions/4097231-add-preselect-option-for-treeview which is great - anyone else reading this who agrees it would be useful should vote there.
I make if for ASP.NET MVC. I use a dynamic tree.
At first I received a route for selected item
[{
"id": 1, // parent category
"name": "Все категории",
}, {
"id": 56, // 1-st sub category
"name": "Для дома",
}, {
"id": 63, // item
"name": "Домашние растения",
}]
Then it need to switch off Async request for Ajax in dataSource function: 'async':false
This is all code:
#{
var jsonSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
string catRoute = jsonSerializer.Serialize(ViewBag.catRoute);
}
var catRoute = $.parseJSON('#Html.Raw(catRoute)'); // this is object of item route
function dynamicDataSource(openedParentData, callback) {
var childNodesArray = [];
$.ajax({
'type': 'post',
'url': '#Url.Action("getFuelUxTree", "Category", new { area = "Root" })',
'data': openedParentData,
'async':false // switch off ajax request
})
.done(function (data) {
childNodesArray = data;
lastTree = data;
callback({
data: childNodesArray
});
});
}
$('#categoryTree').tree({
dataSource: dynamicDataSource,
multiSelect: false,
folderSelect: false
});
// iterate all route items and open category
for (var i = 0; i < catRoute.length; i++) {
$('li#'+catRoute[i].id+' button', '#categoryTree').click();
}