Can't select item in list created by ui-select2 - javascript

In my HTML I have this line:
<input ng-change="privChanged()" ng-model="selectedPriv" ui-select2="privsSelect2options"></input>
and the privsSelect2options function:
$scope.privsSelect2options = {
placeholder: "Wybierz privo",
allowClear:true,
minimumInputLength: function(){return 3;},
formatInputTooShort: function (input, min) {return "Wprowadź conajmniej " + min + " znaki.";},
formatSearching: function () { return "Wyszukiwanie..."; },
formatNoMatches: function () { return "Nie znaleziono pasujących województw."; },
query: function (query) {
query.callback( {results: $filter('filter')($scope.privs,{name: query.term}) } );
},
formatResult: function(priv){
return priv.name;
},
formatSelection: function(priv){
return priv.name;
}
};
Everything works OK when I put 3 letters it filters the result and shows it correct but I can't click and select any item from the result list. Can anyone help me in this matter? It doesn't even come into the formatSelection function.

the problem was that Priv class/table didn't have id property, and its Primary Key was field code. I had to add function :
id : function(priv) {
return priv.code;
},
in $scope.privNameSelect2options

Please refer to Select2 Ajax Method Not Selecting,
and take the correct value:
id: function(data){return {id: data.id};},
or
id: function(data){return data.id}

Although this isn't really specified in the select2 documentation, you'll need to pass an id key with a function value to select2.
$scope.privsSelect2options = {
id: function(element) { return element.name; }
...
};

Related

How to set selected value of typeahead

how can i set a default value in typeahead .
i tried many solutions here, but no one seems to work .
Like tagApi.tagsManager("pushTag", 'deafulttag');
Below is my whole code .
$(document).ready(function() {
var tagApi = $(".tm-input").tagsManager();
jQuery(".typeahead").typeahead({
name: 'job_skill',
displayKey: 'category',
source: function (query, process) {
return $.get('ajaxpro.php', { query: query }, function (data) {
data = $.parseJSON(data);
return process(data);
});
},
afterSelect :function (item){
tagApi.tagsManager("pushTag", item);
}
});
});
Thanks in advance for the help .
You could pre-fill the element with a value?
jQuery(".typeahead").typeahead('val',"test");
Source: Bootstrap typeahead - How to set the default value manually
Edit:
In your example you'd want to initiate typeahead with this value something like below rather than re-initialising it:
$(document).ready(function() {
var tagApi = $(".tm-input").tagsManager();
jQuery(".typeahead").typeahead({
name: 'job_skill',
displayKey: 'category',
val: 'test',
source: function (query, process) {
return $.get('ajaxpro.php', { query: query }, function (data) {
data = $.parseJSON(data);
return process(data);
});
},
afterSelect :function (item){
tagApi.tagsManager("pushTag", item);
}
});
});

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

Need to Format this JSON properly and display in HTML using AJAX

I have a JSON that looks like this, I get it from a PHP file that calls Yahoo Finance API,
It's the first time I see a JSON like this.
I looked everywhere but all I manage to do is console log it... I'd like to display it into a table, or a ul, with AJAX
I'd like to access everything and display just what I need or everything.
I tried a bunch of different code snippets from everywhere but couldn't make it work, in three days !...
I'm using scheb/yahoo-finance-api on packagist for that, if it helps.
Thanks for your help.
{
query: {
count: 1,
created: "2017-06-07T12:34:44Z",
lang: "en-US",
results: {
quote: {
symbol: "APLL",
Symbol: "APLL",
LastTradePriceOnly: "0.119",
LastTradeDate: "6/6/2017",
LastTradeTime: "11:13am",
Change: "+0.023",
Open: "0.119",
DaysHigh: "0.119",
DaysLow: "0.110",
Volume: "300"
}
}
}
}
$(function(){
$("#get-data").click(function() {
//do ajax here and load data
var showData = $('#show-data');
var $data = $.getJSON("data.php", function(data) {
// $data = $data.responseText;
function buildTree(data, container) {
$data.forEach(function(node) {
var el = document.createElement(node.tag);
if (Array.isArray(node.content)) {
buildTree(node.content, el);
}
else if (typeof(node.content) == 'object') {
buildTree([node.content], el);
}
else {
el.innerHTML = node.content;
}
container.appendChild(el);
});
}
console.log($data);
buildTree($data, document.body);
});
});
});
That's the one I have for now, I deleted all the others, I took it form here and modified it with no success tho..
Thank you for answering :)
literal notation, not Json.
You can go over this in a for in loop, something like this:
var x = {
query: {
count: 1,
created: "2017-06-07T12:34:44Z",
lang: "en-US",
results: {
quote: {
symbol: "APLL",
Symbol: "APLL",
LastTradePriceOnly: "0.119",
LastTradeDate: "6/6/2017",
LastTradeTime: "11:13am",
Change: "+0.023",
Open: "0.119",
DaysHigh: "0.119",
DaysLow: "0.110",
Volume: "300"
}
}
}
}
for (var key in x) {
if (!x.hasOwnProperty(key)) continue;
var obj = x[key];
for (var prop in obj) {
if(!obj.hasOwnProperty(prop)) continue;
alert(prop + " = " + obj[prop]);
}
}
Is this what you want to achieve?
// let's assume this is your data
var data = {
query: {
count: 1,
created: "2017-06-07T12:34:44Z",
lang: "en-US",
results: {
quote: {
symbol: "APLL",
Symbol: "APLL",
LastTradePriceOnly: "0.119",
LastTradeDate: "6/6/2017",
LastTradeTime: "11:13am",
Change: "+0.023",
Open: "0.119",
DaysHigh: "0.119",
DaysLow: "0.110",
Volume: "300"
}
}
}
};
// prints one li with key and value
function printTree(key, value, container) {
var li = $('<li></li>');
if (typeof value === 'object') {
// value is a nested object, create a new <ul> element for it
li.append(key + ': ');
var ul = $('<ul></ul>');
for (var index in value) {
printTree(index, value[index], ul); // call the function recursively
}
li.append(ul);
} else {
li.text(key + ': ' + value);
}
container.append(li);
}
printTree('data', data, $('#container')); // call the function for the first time
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="container">
This is in literal notation so I assume you've already parsed it into an object. Let's call that object myObject
var myObject={
query : {
count : 1 ,
created : "2017-06-07T12:34:44Z" ,
lang : "en-US" ,
results : {
quote : {
symbol : "APLL" , Symbol : "APLL" , LastTradePriceOnly : "0.119" , LastTradeDate : "6/6/2017" , LastTradeTime : "11:13am" , Change : "+0.023" , Open : "0.119" , DaysHigh : "0.119" , DaysLow : "0.110" , Volume : "300" } } } }
You can access properties as follows:
var myCount = myObject.query.count
console.log(myCount) // logs 1

Find duplicate object from one collection to another collection - using 2 arrays in knockout JS

In knockout JS I want to find out 1st duplicate object from my collection and return that object as modal. I have to check for 1st duplicate object from first array aginst 2nd Array based on my condition. Tried _findWhere & _.Some & _.each nothing worked. Can someone help
Here -- MyMainModal is my Moda which will have multiple objects
self.dupRecord= function (MyMainModal) {
var Modaldata= ko.mapping.toJS(MyMainModal);
return _.some(Modaldata, function (MD1) {
return _.some(Modaldata, function (MD2) {
if ((MD1.ID!== MD2.Id) &&
(MD1.Name === MD2.name));
});
});
};
How about incorporating the check for first duplicate into the mapping? Something like:
function Child(data) {
ko.mapping.fromJS(data, {}, this);
};
var model = {
children: [{
id: '1',
name: 'Billy'
}, {
id: '2',
name: 'Susy'
}]
};
var mapping = {
children: {
key: function(data) {
return ko.utils.unwrapObservable(data.id);
},
create: function(options) {
console.log('creating ' + options.data.name, options.parent);
var newChild = new Child(options.data);
if(options.parent.firstDuplicate() === undefined)
options.parent.children().forEach(function(child) {
if(child.name() === newChild.name())
options.parent.firstDuplicate([child, newChild]);
});
return newChild;
},
update: function(options) {
console.log(' updating ' + options.data.name);
return options.target;
}
}
};
var vm = {
children: ko.observableArray(),
firstDuplicate: ko.observable()
};
ko.mapping.fromJS(model, mapping, vm);
ko.applyBindings(vm);
model.children.push({
id: 3,
name: 'Billy'
});
setTimeout(function() {
console.log('--remapping--');
ko.mapping.fromJS(model, mapping, vm);
}, 2000);
I read that as, "if we're not updating the record, potentially set the first duplicate." Here's a fiddle: http://jsfiddle.net/ge1abt6a/

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