Is there a way to use HTML5's localstorage method with Jquery's select2 plugin? Right now when I enter data and close the browser/tab, all entered data is gone, which is not so optimal since it can get confusing if you dont remember what you've entered
My select2 code looks like this:
$(".select").select2({
minimumInputLength: 1,
multiple: true,
query: function(query){
$.getJSON( 'url path to remote API', {
name:query.term,
featured:true
}, function(results){
var data = {results: []};
$.each(results.data, function(index, item){
data.results.push({id: item.artist_id, text: item.name});
});
query.callback(data);
} );
}
});
Any help is very appreciated
give this a try: http://jsfiddle.net/7267rkxy/12/
I commented the code for you for some explanation of what's going on, you should be able to just swap out the data option with your query option and it should still work
PS: I noticed none of your answered questions have been marked 'accepted', if someone gives you an answer that you like or that works for you, you should mark their answer 'accepted' by clicking the checkbox next to the answer
HTML
<!-- setting a hard width for example -->
<input type="text" class="select" style="width:200px;" value="" />
JS
// set value property to local storage value
$(".select").val(localStorage.s2options);
$(".select").select2({
minimumInputLength: 1,
multiple: true,
data: [{id: 1, text: 'option1'},{id: 2, text: 'option2'},{id: 3, text: 'option3'}], //sample data
initSelection: function (element, callback) {
// initSelection only fires when there is something in the value property
callback($.parseJSON(element.val()));
}
}).on('change', function(info){
// checking if we have anything stored in local storage
var s2options = localStorage.s2options ? JSON.parse(localStorage.s2options) : [];
// add / remove options
if (info.added) {
s2options.push(info.added);
} else if (info.removed) {
s2options = s2options.filter(function(opt) {
return opt.id != info.removed.id;
});
}
// save selections to local storage
localStorage.s2options = JSON.stringify(s2options);
});
In addition to #bruchowski 's answer, the newer version of Select2 has a different way of doing this (initSelection and query are still supported for backwards compatibility though):
You have to create a custom DataAdapter and implement current() and query().
Related
I've been using this script: https://github.com/stephjang/placecomplete for many years with no issues. Tonight I received many complaints that users cannot select the address from the drop down menu. Typing in an address will work fine and results will show up but when trying to select an address, it does not do anything. Does anyone know if something has changed with google blocking placecomplete requests ?
My code:
$inputLocationSearch.placecomplete({
placeholderText: "Enter your site location...",
requestParams: {
componentRestrictions: {country: ['ca','us']}
}
});
Screen shot of issue (mouse or keyboard CANNOT select an address found):
Found the issue within the plugin jquery.placecomplete.js code. Replaced default id parameter to use place_id, as id is deprecated with google autocomplete.
I added: apr["id"] = apr["place_id"]; above existing code: apr["text"] = apr["description"];
Here's the whole code block with the addition:
var select2options = $.extend({}, {
query: function(query) {
GooglePlacesAPI.getPredictions(query.term, requestParams)
.done(function(aprs) {
var results = $.map(aprs, function(apr) {
// Select2 needs a "text" and "id" property set
// for each autocomplete list item. "id" is
// already defined on the apr object
apr["id"] = apr["place_id"];
apr["text"] = apr["description"];
return apr;
});
query.callback({results: results});
})
.fail(function(errorMsg) {
$el.trigger(pluginName + ":error", errorMsg);
query.callback({results: []});
});
},
initSelection: function(element, callback) {
// initSelection() was triggered by value being defined directly
// in the input element HTML
var initText = $el.val();
// The id doesn't matter here since we're just trying to prefill
// the input with text for the user to see.
callback({id: 0, text: initText});
},
minimumInputLength: 1,
selectOnBlur: true,
allowClear: true,
multiple: false,
dropdownCssClass: "jquery-placecomplete-google-attribution",
placeholder: this.options.placeholderText
}, this.options);
I'm loading options into an HTML5 datalist element dynamically. However, the browser attempts to show the datalist before the options have loaded. This results in the list not being shown or sometimes a partial list being shown. Is there any way to refresh the list via JavaScript once the options have loaded?
HTML
<input type="text" id="ingredient" list="ingredients">
<datalist id="ingredients"></datalist>
JavaScript
$("#ingredient").on("keyup", function(event) {
var value = $(this).val();
$.ajax({
url: "/api/ingredients",
data: {search: value.length > 0 ? value + "*" : ""},
success: function(ingredients) {
$("#ingredients").empty();
for (var i in ingredients) {
$("<option/>").html(ingredients[i].name).appendTo("#ingredients");
}
// Trigger a refresh of the rendered datalist
}
});
});
Note: In Chrome and Opera, the entire list is only shown if the user clicks on the input after entering text. However, I'd like the entire list to appear as the user types. Firefox is not a problem, as it appears to refresh the list automatically when the options are updated.
UPDATE
I'm not sure this question has a satisfactory answer, as I believe this is simply a shortcoming of certain browsers. If a datalist is updated, the browser should refresh the list, but some browsers (including Chrome and Opera) simply do not do this. Hacks?
Quite a long time after question but I found a workaround for IE and Chrome (not tested on Opera and already OK for Firefox).
The solution is to focus the input at the end of success (or done) function like this :
$("#ingredient").on("keyup", function(event) {
var _this = $(this);
var value = _this.val();
$.ajax({
url: "/api/ingredients",
data: { search: value.length > 0 ? value + "*" : "" },
success: function(ingredients) {
$("#ingredients").empty();
for (var i in ingredients) {
$("<option/>").html(ingredients[i].name).appendTo("#ingredients");
}
// Trigger a refresh of the rendered datalist
// Workaround using focus()
_this.focus();
}
});
It works on Firefox, Chrome and IE 11+ (perhaps 10).
I had the same problem when updating datalist.
The new values would not show until new input event.
I tried every suggested solutions but nothing using Firefox and
updating datalist via AJAX.
However, I solved the problem (for simplicity, I'll use your example):
<input type="text" id="ingredient" list="ingredients" **autocomplete="off"**>
<datalist id="ingredients"></datalist>
$("#ingredient").on("**input**", function(event) { ....}
Autocomplete and input is the couple that solve my problems and it works with Chrome too.
You can probably eliminate the problem if you don't make AJAX request on every key stroke. You can try throttle technique using set/cleatTimeout to issue request after 500ms after the last char typed:
$("#ingredient").on("keyup", function(event) {
clearTimeout($(this).data('timeout'));
$(this).data('timeout', setTimeout($.proxy(function() {
var value = $(this).val();
$.ajax({
url: "/api/ingredients",
data: {search: value.length > 0 ? value + "*" : ""},
success: function(ingredients) {
$("#ingredients").empty();
for (var i = 0; i < ingredients.length; i++) {
$("<option/>").html(ingredients[i].name).appendTo("#ingredients");
}
}
});
}, this), 500));
});
Yoyo gave the correct solution, but here's a better way to structure your inserts into the DOM.
$("#ingredient").on("keyup", function(event) {
var _this = $(this);
var value = _this.val();
$.ajax({
url: "/api/ingredients",
data: { search: value.length > 0 ? value + "*" : "" },
success: function(ingredients) {
var options = ingredients.map(function(ingredient) {
var option = document.createElement('option');
option.value = ingredient.name;
return option;
});
$("#ingredients")
.empty()
.append(options);
// Trigger a refresh of the rendered datalist
// Workaround using focus()
_this.focus();
}
});
Less DOM manipulation
With this refinement, I'm only inserting into the DOM a single time per each successful callback. This cuts down on the browser needing to re-render, and will help improve any "blips" in the view.
Functional Programming and Less Idiomatic jQuery
Here we are using the Array.prototype.map to clean up some of the jQuery and make things a bit less idiomatic. You can see from the ECMA Chart that this function will work in all browsers you are targeting.
Not Hacky
This by no means is hacky. IE appears to be the only browser that doesn't automatically refresh the input to display the new list options. focus() is just a way to ensure the input is refocused which forces a refresh of the view.
This solution works very well in all of the browsers that my company has to support internally, IE10+ Chrome and Firefox.
Place your #ingredients element is inside #container and try this code:
$.ajax({
url: "/api/ingredients",
data: {search: value.length > 0 ? value + "*" : ""},
success: function(ingredients) {
$("#ingredients").remove();
var item = $('<datalist id="ingredients"></datalist>');
for (var i in ingredients) {
item.append("<option>"+ ingredients[i].name +"</option>");
}
item.appendTo('#container');
}
});
even better without #container and using jQuery replaceWith():
$.ajax({
url: "/api/ingredients",
data: {search: value.length > 0 ? value + "*" : ""},
success: function(ingredients) {
var item = $('<datalist id="ingredients"></datalist>');
for (var i in ingredients) {
item.append("<option>"+ ingredients[i].name +"</option>");
}
$("#ingredients").replaceWith(item);
}
});
Your issue is that the AJAX is asynchronous.
You'd actually have to have a callback for the AJAX which you call onSuccess which would then update the datalist. Of course, then you might not have great performance/still have a "skipping" behavior, where your datalist options are lagging behind.
If your list of items from the AJAX isn't too large, you should:
1. load the ENTIRE list into memory array with the first query, then...
1. use a filtering function that is applied to the array each time you have a keyUp event.
I found a solution tested only on GNOME Web (WebKit) that consist on set the 'list' attribute of the input element to empty string and, inmediately after, set it again with the id of the datalist element. Here is the example, supose that your input element is stored in a variable named input_element:
var datalist = document.getElementById(input_element.list.id);
// at this point input_element.list.id is equals to datalist.id
// ... update datalist element here
// And now the trick:
input_element.setAttribute('list','')
input_element.setAttribute('list',datalist.id)
How do get the underlying data from a row click on a grid?
My code looks like this :
isc.ListGrid.create({
ID: "countryList",
width:1500, height:224, alternateRecordStyles:true,
data: sampleData,
fields:[
{name:"id", title:"Id"},
{name:"name", title:"Name"},
{name:"version", title:"Version"},
{name:"release", title:"Release"},
],
canReorderFields: true,
click: function (x) {
alert('hi there' + x)
}
})
If I add a click function, the alert pops up.
If put in a paramater 'x', and that seems to have some kind of value, but i can't decipher it means. What I really want is the underlying JSON data (see below) which is being passed in as sampleData.
{
id:"10621",
name:"PimsPacket020",
version:"0.1",
release:"undefined",},
{
id:"10621",
name:"PimsPacket020",
version:"0.1",
release:"undefined",
}
I haven't been using Smartclient for quite some time, but, I think a better selection event for a grid row would be:
selectionChanged: "someFunction(this.getSelection())"
The this.getSelection() function will return an array of records even for a single selection.
For more information I suggest using the Smartclient on-line documentation( Smartclient 9.1 Documentation) and feature explorer(Smartclient Feature Explorer) together. This code work on earlier versions; from 8.x at least.
I hope this helps.
if your list contains chexbox (selectionAppearance: "checkbox") you have to use this.getSelection() that contain all selected items.
or you make a function with record parameter:
click: function (record) {
isc.say ("ID:" + record.id + "Name:" + record.Name);
}
Use this function to retrieve your record
recordClick: function (viewer, record, recordNum, field, fieldNum, value, rawValue) {
alert('hi there' + record.name);
}
For more information, please refer smartclient documentation
http://www.smartclient.com/docs/8.2/a/b/c/go.html#method..ListGrid.recordClick
I have a table where i sort on the second column. by default i have 8 columns
and the rows can vary, depending on how many things i add.
The sorting works when i have the standard 8 columns but when i mark a checkbox and save which indicates that more info will be generated dynamiclly in my table then the sorting does not work anymore.
code:
$.tablesorter.addParser({
id: 'input_text',
is: function (s) {
// return false so this parser is not auto detected
return false;
},
format: function (s) {
return s;
},
type: 'text'
});
// Tablesorter
if ($(".attendanceList tbody tr").length > 0) {
$(".attendanceList").tablesorter({ headers: { 1: { sorter: false },
2: { sorter: 'input_text' },
3: { sorter: false },
4: { sorter: false },
5: { sorter: false },
6: { sorter: false },
7: { sorter: false },
8: { sorter: false },
9: { sorter: false },
10: { sorter: false }
},
sortList: [[2, 0], [0, 0]]
});
}
I used firebug to see what the problem was and my "s" paramater(check above) is allways an empty string ("").
step by step:
i mark a checkbox and press a save button. when that is done i press on another button that triggers a popup and gets me my table, now the table has 10 columns but the second column will no longer perform the sort as it did before.
Have i missed something? I have read up on the tablesorter plugin and I have not found anyone with similar issues,
Thanks!
I see two issues with what you are describing; and hopefully you're using my fork of tablesorter.
1) To get the value of a checkbox, you'll need to search the cell for an input and check for updates. Note this parser will work with the original tablesorter, but it won't update (using the updateCell method) properly. Note this code is from the parser-input-select.js file, and can be seen working in this demo.
// Custom parser for including checkbox status if using the grouping widget
// updated dynamically using the "change" function below
$.tablesorter.addParser({
id: "checkbox",
is: function(){
return false;
},
format: function(s, table, cell) {
// using plain language here because this is what is shown in the group headers widget
// change it as desired
var $c = $(cell).find('input');
return $c.length ? $c.is(':checked') ? 'checked' : 'unchecked' : s;
},
type: "text"
});
// update select and all input types in the tablesorter cache when the change event fires.
// This method only works with jQuery 1.7+
// you can change it to use delegate (v1.4.3+) or live (v1.3+) as desired
// if this code interferes somehow, target the specific table $('#mytable'), instead of $('table')
$(window).load(function(){
// resort the column after the input/select was modified?
var resort = true,
// this flag prevents the updateCell event from being spammed
// it happens when you modify input text and hit enter
alreadyUpdating = false;
$('table').find('tbody').on('change', 'select, input', function(e){
if (!alreadyUpdating) {
var $tar = $(e.target),
$table = $tar.closest('table');
alreadyUpdating = true;
$table.trigger('updateCell', [ $tar.closest('td'), resort ]);
// updateServer(e, $table, $tar);
setTimeout(function(){ alreadyUpdating = false; }, 10);
}
});
});
2) The only thing that isn't clear from the question is if the table is being built dynamically within the popup, or if the table with the checkbox is being modified, then copied to a popup?
Note that the above method only updates the state of the checkbox within the table. It won't include any dynamically added columns to an already initialized table. In that case, you'll need to use the updateAll method, but it will need to be triggered after the table contents have been updated.
$table.trigger('updateAll', [ resort ]);
If you could share the code that is run between the time of "saving" your checkbox choices and initializing the popup, it would help make the issue more clear.
Update: to parse an input, you need to get the value of the input element. The s within the parser format function only contains the text found within the table cell. When there is only an input within the table cell, no text is returned because the input element doesn't contain text, it has a value. So instead of using the "checkbox" parser I shared above, use this "input" parser; but as stated before, this parser will work with the original version of tablesorter (v2.0.5) but will not work properly if the "updateCell" method is used.
$.tablesorter.addParser({
id: "inputs",
is: function(){
return false;
},
format: function(s, table, cell) {
return $(cell).find('input').val() || s;
},
type: "text"
});
This parser also requires the code within the $(window).load(...) shown above to allow updating the parsed input for sorting when the user changes it.
After inserting the dynamically-generated content, you just need to trigger an update. It looks like your table is identified with the "attendanceList" class, so the command after the dynamic update would be:
$(".attendanceList").trigger("update");
Okay, so in a nutshell, what I need to do is to automatically apply a set of sorting criteria and data filters to the jqGrid when it loads. The intent is that the user will start with about 10 pre-filled filters and then, if they so choose, they can alter those filters or the sorting however they see fit.
So far, with much Google-ing, trial and error and sweat, I have the following working:
-> I can load/save the sort column & sort order in a session cookie.
-> I can load the search dialog with pre-defined search filters. After the grid loads, I can open the modal dialog and see the proper filters and if I click "Find" the appropriate data is posted to the server and the right results are returned to the screen.
The thing that is biting me in the butt right now is, I think, the easy part, but it escapes me. I can't seem to do either of the following:
( A ) The ideal thing would be if I could attach these filters to the grid and it's post data in advance of the initial load so that there is only a single trip to the server.
( B ) The workable solution, though less ideal, would be for the grid to load the first page of the unfiltered data first, and then apply the filters and re-query the server for the filtered data.
Since I can manually click the "find" button today and it works, I thought that "B" would be a good next-step. So, in my gridComplete function, I have the following code:
$('#AccountGrid').clearFilter({gridName:'AccountGrid', pagerName:'AccountPager'});
$('#AccountGrid').addFilter({gridName:'AccountGrid', field:'AccountID', data:1, op:'ne'});
$('#AccountGrid').addFilter({gridName:'AccountGrid', field:'AccountID', data:3, op:'ne'});
// $('#fbox_AccountGrid').searchFilter().search();
// $('#fbox_AccountGrid .ui-search').click();
$('#AccountGrid').trigger('reloadGrid');
NOTE: "clearFilter" and "addFilter" are extension functions I have added to jqGrid to simplify adding and removing filters on the grid. They work exactly as desired at this point.
As you can see with those last three lines of code, I have tried using the built-in function, as well as going after the find button directly and even just forcing the entire grid to refresh. Either way, there is no attempt by the grid to go get new data (I am using Fiddler to watch for it).
What am I doing wrong in trying to force the grid to reload with the new filters?
And, if you know how, can you give me some direction on how to get the initial load of the grid to respect these filters?
TIA
Tony
Here is the full grid configuration (minus the extra columns and some colModel "cruft"):
jQuery('#AccountGrid').jqGrid({
url: '<my URL>',
width: 950,
height: 330,
shrinkToFit: 'true',
datatype: 'json',
mtype: 'POST',
multiselect: true,
multiboxonly: true,
multiselectWidth: 20,
colNames: [
'Account ID'
],
colModel: [
{ name: 'AccountID', index: 'AccountID', sortable: false, hidden:false, search:true }
],
gridComplete: function () {
// add the search criteria to the grid
if (initialLoad == true){
$('#AccountGrid').clearFilter({gridName:'AccountGrid', pagerName:'AccountPager'});
$('#AccountGrid').addFilter({gridName:'AccountGrid', field:'AccountID', data:1, op:'ne'});
$('#AccountGrid').addFilter({gridName:'AccountGrid', field:'AccountID', data:3, op:'ne'});
// $('#fbox_AccountGrid').searchFilter().search();
// $('#fbox_AccountGrid .ui-search').click();
$('#AccountGrid').trigger('reloadGrid');
initialLoad = false;
}
},
jsonReader: {
repeatitems: false,
id: 'AccountID'
},
pager: jQuery('#AccountPager'),
rowNum: 50,
rowList: [10, 15, 25, 50, 75, 100],
onSortCol : function (sortname, indexColumn, sortorder){
$.cookie('AccountGrid_sortname', sortname);
$.cookie('AccountGrid_sortorder' , sortorder);
},
sortname : $.cookie('AccountGrid_sortname') ? $.cookie('AccountGrid_sortname') : 'AccountID',
sortorder: $.cookie('AccountGrid_sortorder') ? $.cookie('AccountGrid_sortorder') : 'asc',
viewrecords: true,
imgpath: ''
});
$('#AccountGrid').jqGrid('navGrid','#AccountPager',
{ view: false, add: false, edit: true, del: false,
alertcap:'No Account Selected',
alerttext: 'Please select an Account from the grid before performing this operation.',
editfunc: showAccountEditDialog },
{}, // default settings for edit
{}, // default settings for add
{}, // delete
{closeOnEscape: true, multipleSearch: true, closeAfterSearch: true }, // search options
{}
);
And, by request, here is the code I have for add/clear filter:
/*
This is a grid extension function that will insert a new filter criteria
on the specified grid with the provided field, operation & data values
*/
(function ($) {
jQuery.jgrid.addSearchFilter =
{
// get/set the parameters
addFilter: function (options) {
var grid = $(this);
// get offset values or assign defaults
var settings = $.extend({
gridName: '',
field: '',
data: '',
op: ''
}, options || {});
// get the column model object from the grid that matches the provided name
var colModel = grid.getGridParam('colModel');
var column;
for (var i = 0; i < colModel.length; i++) {
if (colModel[i].name == options.field){
column = colModel[i];
break;
}
}
colModel = null;
if (column){
// if the last filter has a value, we need to create a new one and not overwrite the existing ones
if ($('#fbox_' + options.gridName + ' .sf .data input').last().val()){
$('#fbox_' + options.gridName).searchFilter().add();
}
// assign the selections to the search dialog
$('#fbox_' + options.gridName + ' .sf .fields select.field').last().val(column.index).change();
$('#fbox_' + options.gridName + ' .sf .data input').last().val(options.data);
$('#fbox_' + options.gridName + ' .sf .ops select.default').last().val(options.op).change();
}
}
}
})(jQuery);
jQuery.fn.extend({ addFilter: jQuery.jgrid.addSearchFilter.addFilter });
/*
This is a grid extension function that will clear & reset the filter criteria
*/
(function ($) {
jQuery.jgrid.clearSearchFilter =
{
// get/set the parameters
clearFilter: function (options) {
var grid = $(this);
// get offset values or assign defaults
var settings = $.extend({
gridName: '',
pagerName: ''
}, options || {});
// clear the filters and "pop" the dialog to force the HTML rendering
$('#fbox_' + options.gridName).searchFilter().reset();
$('#' + options.pagerName + ' .ui-icon-search').click();
$('#fbox_' + options.gridName).searchFilter().close();
}
}
})(jQuery);
jQuery.fn.extend({ clearFilter: jQuery.jgrid.clearSearchFilter.clearFilter });
First of all because you don't post the code which define the jqGrid I make some assumption myself. I try to base on indirect information from your question.
1) I suppose that you use server side datatype parameter of jqGrid like 'json' or 'xml'.
2) You don't use loadonce:true parameter. In general if would be possible to make server reload from the grid having loadonce:true, but in the case you have to reset the value of datatype parameter to initial value (one from the value 'json' or 'xml').
The following three old answer: this (in case of single value searching) and this (in case of advanced searching or the toolbar searching with additional parameter stringResult:true) will give you enough information about setting the searching filters and reloading the grid corresponds to the new filters. Another answer shows how to clear the searching filter if it is no more needed.
Loading of the grid at the first time with the filters is another question. It can be very easy implemented. You should just use datatype:"local" instead of datatype:"json" or datatype:"xml" which you really need. In the case the url parameter of jqGrid will be just ignored at the first load and jqGrid send no request to the server. Then you set the filters like you as need and only then use $("#youGridId").trigger("reloadGrid");
The reason why the reloadGrid didn't work in your case I could not know exactly, but I suppose that you didn't set the search:true parameter of the jqGrid which one confuses frequently with the _search property of the postData parameter (see here).