JavaScript JTable - Null value with multiple cascaded lists/dropdowns - javascript

I am using the latest version of JTable from http://jtable.org/ (downloaded it yesterday). I setup my JTable as shown below (I also included the server-side code below, which is written in C#). The List function works (the data shows up in the table), the Add function works, and the Delete function works. However, when I go to Edit a row, there is an error when trying to populate the data for the "ElevationsMulti" field. I get an error that simply says, "Cannot load options for field ElevationsMulti."
JTable Code:
$('#ReportsContainer').jtable({
title: 'Reports',
actions: {
listAction: '/Report_SingleEstimate/GetReportNames?customerId=' + customerId,
createAction: '/Report_SingleEstimate/AddReport',
updateAction: '/Report_SingleEstimate/EditReport',
deleteAction: '/Report_SingleEstimate/DeleteReport'
},
fields: {
ReportID: {
key: true,
list: false
},
ReportName: {
title: 'Report Name'
},
CustomerID: {
title: 'Customer',
list: false,
options: '/Estimates/GetCustomers',
defaultValue: customerId
},
PlanNameID: {
title: 'Plan Name',
dependsOn: 'CustomerID',
options: function (data) {
if (data.source == 'list') {
return '/Estimates/GetListOfPlanNames?customerId=0';
}
//data.source == 'edit' || data.source == 'create'
return '/Estimates/GetListOfPlanNames?customerId=' + data.dependedValues.CustomerID;
}
},
ProductID: {
title: 'Product',
options: '/Estimates/GetProducts'
},
HeaderFieldsMulti: {
title: 'Fields',
options: '/Report_SingleEstimate/GetHeaderFields',
type: 'multiselectddl',
list: false
},
ElevationsMulti: {
title: 'Elevations',
type: 'multiselectddl',
dependsOn: ['PlanNameID', 'ProductID'],
options: function (data) {
if (data.source == 'list') {
return '/Elevation/GetAllElevations';
}
return '/Report_SingleEstimate/GetElevations?PlanNameID=' + data.dependedValues.PlanNameID +
'&ProductID=' + data.dependedValues.ProductID;
},
list: false
}
}
});
$('#ReportsContainer').jtable('load');
Not sure if it makes a difference in JTable, but the ElevationsMulti depends on the PlanNameID and ProductID fields, and the PlanNameID field depends on the CustomerID fields. In other words, the ElevationsMulti field depends on a field that depends on another field (multiple nested dropdowns).
C# server-side code:
[HttpPost]
public JsonResult GetElevations(int PlanNameID, int ProductID)
{
try
{
int estimateId = Estimates.getEstimateId(PlanNameID, ProductID);
List<MyDropdownList> elevations = Estimate_ElevationList.listElevationsByEstimateForDropdown(estimateId);
return Json(new { Result = "OK", Options = elevations });
}
catch (Exception ex)
{
return Json(new { Result = "ERROR", Message = ex.Message });
}
}
Error here:
Further debugging has given me a more specific error.
The parameters dictionary contains a null entry for parameter 'PlanNameID' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.JsonResult GetElevations(Int32, Int32)' in 's84.Controllers.Report_SingleEstimateController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Basically, JTable sends PlanNameID to the server as a null value. Which seems to indicate that JTable has not loaded the options for the PlanNameID field yet when it makes the server call for the ElevationsMulti field.
How do I make JTable wait to load the ElevationsMulti field until after the PlanNameID field has been loaded?

Problem solved.
The problem came from using the Type "multiselectddl" in JTable. I changed the code in JTable that creates the multiselectddl to the same code as the regular dropdown. Here is the code:
_createInputForRecordField: function (funcParams) {
...
//Create input according to field type
if (field.type == 'date') {
return this._createDateInputForField(field, fieldName, value);
} else if (field.type == 'textarea') {
return this._createTextAreaForField(field, fieldName, value);
} else if (field.type == 'password') {
return this._createPasswordInputForField(field, fieldName, value);
} else if (field.type == 'checkbox') {
return this._createCheckboxForField(field, fieldName, value);
} else if (field.options) {
if (field.type == 'multiselectddl') {
return this._createDropDownListMultiForField(field, fieldName, value, record, formType, form);
} else if (field.type == 'radiobutton') {
return this._createRadioButtonListForField(field, fieldName, value, record, formType);
} else {
return this._createDropDownListForField(field, fieldName, value, record, formType, form);
}
} else {
return this._createTextInputForField(field, fieldName, value);
}
},
_createDropDownListMultiForField: function (field, fieldName, value, record, source, form) {
//Create a container div
var $containerDiv = $('<div class="jtable-input jtable-multi-dropdown-input"></div>');
//Create multi-select element
var $select = $('<select multiple="multiple" class="' + field.inputClass + '" id="Edit-' + fieldName + '" name=' + fieldName + '></select>')
.appendTo($containerDiv);
var options = this._getOptionsForField(fieldName, {
record: record,
source: source,
form: form,
dependedValues: this._createDependedValuesUsingForm(form, field.dependsOn)
});
this._fillDropDownListWithOptions($select, options, value);
return $containerDiv;
}

Related

How to pass additional parameters to the JsGrid custom sortStrategies function?

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

How to get data from the store to filter by field. Extjs

For the contragent field, I need to set filtering. I can not understand how I correctly set the value in the parameter "store:".
{
text: 'Контрагент',
dataIndex: 'contragent',
filter: {
type: 'list',
store: //how to get the "name" of the record from the ContrAgents for filtering
},
renderer: function(value, metaData, record, rowIndex, colIndex, store, view) {
if (value > 0) {
if (rec = me.myContrAgents.findRecord('id', value)) {
return rec.get('name');
}
}
return '';
}
}
I give an example in FIDDLE Location code app/view/ListView.js

Typeahead Bootstrap Return ID and Value Json

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

How to handle POST results with formidable package and mongoose?

I did some research on handling POST request with node.js, so that's working now, kind of.
I also know how to save a new JSON object to a mongoDB collection with mongoose.
I feel like I'm close to the solution but I'm having trouble finding the answer.
The specific problem
Now, I need some help to put these two together.
Handling POST request [ok+-] => converting to JSON object/mongoose object [not okay] => saving it to collection [ok+-]
The controllers code
Here is the code I'm using. The basic features work :
handling the fields posted and "saving" them to an object
rendering the fields posted (the "fields" object)
The code:
// controller function for adding a ressource
var post = function(req, res){
// incoming form
var form = new formidable.IncomingForm();
var fields = {};
console.dir('ceci est bien un post');
// everytime an field is parsed...
// This is the place where I should do validation and throw errors if needed
form.on('field', function (field, value) {
console.log(field);
console.log(value);
fields[field] = value;
});
// Once the form is parsed completely
form.on('end', function () {
// testing the output
var ressources = util.inspect(fields, {showHidden: false, depth: null});
console.dir(util.inspect(fields, {showHidden: false, depth: null}));
// here save it in mongodb collection
var ressource = new Ressource(fields);
// ressource.save(function (err, ressource, isSuccess) {
// if (err) {
// res.status(400);
// res.send('Error occured ' + err);
// }
// else if (isSuccess === 1) {
// res.status(201);
// res.send(ressource);
// }
// else {
// res.status(400);
// }
// });
// rendering the page with the results
res.render('addRessourceView', {
title: 'Ressources',
fields: ressources
});
});
form.parse(req);
};
And here's the mongoose model:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var ressourceModel = new Schema({
title: { type: String },
descr_short: { type: String },
m_visual: { type: Boolean, default: false },
m_writing:{ type: Boolean, default: false },
m_moving: { type: Boolean, default: false },
m_speaking:{ type: Boolean, default: false },
m_music:{ type: Boolean, default: false },
age: String,
minAge: { type: Number },
maxAge: { type: Number },
prerequisite:{ type: Array,
items: { type: String },
uniqueItems: true},
language: { type: String },
source: { type: String },
intra_identify: { type: Boolean, default: false },
intra_expression: { type: Boolean, default: false },
intra_comprehension: { type: Boolean, default: false },
intra_regulation: { type: Boolean, default: false },
intra_utilisation: { type: Boolean, default: false },
theme_impulsivity: { type: Boolean, default: false },
theme_violence: { type: Boolean, default: false },
inter_identify: { type: Boolean, default: false },
inter_expression: { type: Boolean, default: false },
inter_comprehension: { type: Boolean, default: false },
inter_regulation: { type: Boolean, default: false },
inter_utilisation: { type: Boolean, default: false },
details:{
type: Object,
properties: {
goals: { type: Array,
items: { type: String },
uniqueItems: true},
preparation: String,
exercices: { type: Array,
items: { type: Object }},
reflexion: String
}
},
upload:{ type: Array,
items: { type: Object }}
});
module.exports = mongoose.model('Ressource', ressourceModel);
Note : evrything that is "boolean" is a checkbox input
So all these fields are also in the form (I've just not implemented the file upload).
So basically what I need help for is:
adapting the post fields into something I can use with mongoose and save it
maybe some help on how add some validation (like being sure the minAge is smaller than maxAge, or other stuff)
and if you have time or would want to, how to handle file uploads
I'm really here to learn, I'm just a beginner and I tried to be as clear as possible with my question, and I hope you guys will be able to help me out!
Thanks,
Xogno
Yesterday, I spent the whole day working on it and I came to make it work as I wanted ! Actually, after researching a bit more, it wasn't really difficult : it just needed some good logic and taking the time to do it.
Disclaimer : I'm using 'formidable' package to handle the post request, and learned using it with this tutorial.
I first started by adding the structure with comments, just to write down the logical thinking behind my code. And then I started to implement the code for each field one by one. form.on('field'....){} executes each time a field is parsed, so that's how I cand handle them one by one. To do that i used a switch(true) with multiples cases ... : ... break; .
I added the verification needed, adding an error to the object, and this way all the fields were added one by one to an JSON object.
Regarding errors, I displayed them using EJS template in the html page.
Then, once everything was working (handling POST fields and handling errors), the only thing I had left to do was linking it (saving it) to the mongodb collection, using .save method from mongoose.
So this happens all on server side, and doesn't happen dynamically. Maybe later I will recode it to work dynamically, with ajax or some other framework (Vue.js ?), so it doesn't need to reload the whole page and will be more efficient.
Here's the code in case it might help some!
The code handling the post request
form.on('field') // handling each field one by one
form.on('field', function (field, value) {
console.log(field);
console.log(value);
switch (true) {
//check if title is not empty, if empty, throw error
case field === 'title':
if(value == ''){
// then error
console.log('titre vide')
fields.error = ['title-empty'];
fields[field] = value;
}
else{
fields.error = [];
fields[field] = value;
}
break;
// check if description is not empty
case field === 'short_descr':
if(value == ''){
// then error
console.log('titre vide')
fields.error = ['descr-empty'];
fields[field] = value;
}
else{
fields[field] = value;
}
break;
// when receiving minAge or maxAge, save it as number
case (field === 'minAge' || field === 'maxAge') :
if(field === 'maxAge'){
var maxAge = value;
if(Number(maxAge) < Number(fields.minAge)){
// then error
console.log('Error : maxAge plus petit que minAge')
fields.error.push('maxAge<minAge');
}
}
fields[field] = Number(value);
break;
// if 'objectives'
case field === 'objectives':
console.log('hey we have an objectif!')
// when receiving an objective, verify if there's already one
if('objectives' in fields.details){
//then there is already an objective object
console.log('adding an objective to the list');
fields.details[field].push(value);
}
// then we create the objective entry in fields.details
else {
fields.details[field] = [value];
console.log('ajouté aux détails');
}
break;
// if 'materials'
case field === 'materials':
console.log('hey we have an material!')
// when receiving an objective, verify if there's already one
if('materials' in fields.details){
//then there is already an objective object
console.log('adding an material to the list');
fields.details[field].push(value);
}
// then we create the objective entry in fields.details
else {
fields.details[field] = [value];
console.log('ajouté aux détails');
}
break;
// when receiving an exercice, verify if there's already an exercice that exists
// if there's already an exercice that exists, and this one isn't null, add this one as another exercice
// verify also if ex_time is a number
// and insert it under 'details.exercices' (array of objects : {ex_descr: '', ex_time:''})
// renvoyer une erreur si le temps est vide ou si pas un nombre
case field === 'exercices':
console.log('hey we have an exercice!')
// when receiving an objective, verify if there's already one
//first check if it's not empty
if('exercices' in fields.details){
if(value === ''){
//it's empty, add an error
fields.error.push('Empty-' + field + '[' + j + ']');
console.log('exercice is empty');
}
//then there is already an objective object
console.log('adding an exercice to the list');
var object_exercices = {};
object_exercices.ex = value;
fields.details.exercices.push(object_exercices);
j++;
}
// then we create the objective entry in fields.details
else {
if(value === ''){
//it's empty, add an error
fields.error.push('Empty-' + field + '[' + j + ']');
console.log('exercice is empty');
}
var object_exercices = {};
object_exercices.ex = value;
fields.details.exercices = [object_exercices];
console.log('ajouté aux détails');
j++;
}
break;
//if it's an exercice_time we need to add it to the exercice object in the exercice array
case field === 'exercices-time':
console.log('hey we have an exercice-time!')
// when receiving an exercice-time, verify if there's already an exercice existing
if ('exercices' in fields.details){
if(isNaN(value) || value === ''){
// if it's not a number, push a new error
fields.error.push('NaNexercice_time[' + i + ']');
console.log('but its not a number or is empty ' + i);
//recuparate the object of the exercice
var object_exercices = {};
object_exercices = fields.details.exercices[i];
object_exercices.exercice_time = value;
// add the value of ex_time to it
fields.details.exercices[i] = object_exercices;
i++;
} else {
// if it's a number
// and then there is already an exercice object
console.log('adding an exercice-time to the last exercice ' + i);
//recuparate the object of the exercice
var object_exercices = {};
object_exercices = fields.details.exercices[i];
object_exercices.exercice_time = Number(value);
// add the value of ex_time to it
fields.details.exercices[i] = object_exercices;
i++;
}
}
break;
// if "preparation" add it to details.preparation
case field === 'preparation':
fields.details[field] = value;
console.log('ajouté aux détails');
break;
case field === 'intra_identification' || field === 'intra_regulation' || field === 'intra_understanding'
|| field === 'intra_utilisation' || field === 'intra_expression' || field === 'inter_identification'
|| field === 'inter_expression' || field === 'inter_utilisation' || field === 'inter_regulation'
|| field === 'inter_understanding':
//to see if they've at least checked one competence
fields[field] = value;
break;
// otherwise it's a basic input
default:
fields[field] = value;
}
});
form.on('end') // once the whole form is parsed
// Once the form is parsed completely
form.on('end', function () {
// last error handling
//test if they've at least added one competence
if(!fields.intra_identification && !fields.intra_regulation
&& !fields.intra_understanding && !fields.intra_utilisation
&& !fields.intra_expression && !fields.inter_identification
&& !fields.inter_expression && !fields.inter_utilisation
&& !fields.inter_regulation && !fields.inter_understanding) {
fields.error.push('No competence selected');
console.log('No competence selected');
}
// testing the output
console.dir(util.inspect(fields, {showHidden: false, depth: null}));
//time to save
// see if there were errors
if(fields.error.length < 1){
//no errors
//then save it in the database
console.log('no errors');
// save it in mongodb collection
var ressource = new Ressource(fields);
ressource.save(function (err, ressource, isSuccess) {
if (err) {
res.status(400);
//res.send('Error occured ' + err);
res.render('addRessourceView', {
title: 'Ressources',
fields: fields,
saved: false
});
}
else if (isSuccess === 1) {
res.status(201);
//res.send(ressource);
// render the page with save success
res.render('addRessourceView', {
title: 'Ressources',
fields: fields,
saved: true
});
}
else {
res.status(400);
res.render('addRessourceView', {
title: 'Ressources',
fields: fields,
saved: false
});
}
});
} else {
console.dir(fields.error);
// render the page with save success
res.render('addRessourceView', {
title: 'Ressources',
fields: fields,
saved: false
});
}
});
form.parse(req);

Unable to select item in Select2 drop down

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) {

Categories