I'm trying to integrate select2 for JqGrid filter form. I'm using JqGrid min 4.6 & Select2 min 4.0.1. The filter works fine but I'm unable to retrieve the value that has been set through select2 once the filter form is closed and reopened. i.e. dataInit e1 does not return the existing value of the select input. I must be doing something wrong?
JqGrid Column Model:
{
name: 'CurrencyID', hidden: true, search: true, stype: 'select', searchtype: 'number', searchoptions: {
searchhidden: true,
sopt: ['eq', 'ne'],
dataInit: function (el) {
intiGridFilterSelecr2Field(el, paramFromView.CurrencyOptions);
}
},
searchrules: { required: true }
},
Parameters:
#section scripts{
<script>
var paramFromView = {
CurrencyOptions: {
searchURL: '#Url.Action("GetCurrency", "Controller")',
detailURL: '#Url.Action("CurrencyDetailsJson", "Controller")',
idField: 'CurrencyID',
txtField: 'Description'
}
};
</script>
}
Select2 Helper:
function intiGridFilterSelecr2Field(element, options) {
var comboPageSize = 15;
var quietMillis = 200;
var placeHolderText = 'Choose...'
var defaults = {
searchURL: '',
detailURL: '',
idField: '',
txtField: ''
};
var options = $.extend({}, defaults, options);
var select2Element = $(element);
select2Element.select2({
width: 'element',
minimumInputLength: 1,
placeholder: placeHolderText,
ajax: {
url: options.searchURL,
dataType: 'json',
quietMillis: quietMillis,
cache: false,
data: function (params) {
return {
name: params.term,
page: params.page,
pageSize: comboPageSize
};
},
processResults: function (data) {
var more = (data.page * comboPageSize) < data.total;
var resultsArr = [];
for (var i = 0; i < data.result.length; i++) {
resultsArr.push({ id: data.result[i][options.idField], text: data.result[i][options.txtField] });
}
return { results: resultsArr, more: more };
}
},
}).each(function (index, element) {
var idCombo = $(this);
// The problem is that idCombo.val() is always empty.
// element:select2-hidden-accessible
if (idCombo.val() != null && idCombo.val().length > 0) {
$.ajax(options.detailURL, {
data: {
id: idCombo.val()
},
dataType: 'json',
cache: false
}).done(function (data) {
var optselected = select2Element.find('option').filter(function () { return this.value == data[idField] && this.text == data[txtField] && this.selected })
if (optselected == undefined || optselected.length == 0) {
var $optionContact = $("<option selected></option>").val(data[idField].toString()).text(data[txtField]);
var toBeRemoved = select2Element.find('option').filter(function () { return this.value == data[idField] });
if (toBeRemoved != undefined) {
toBeRemoved.remove();
}
select2Element.append($optionContact).trigger('change.select2');
}
});
}
});
}
When the filter is being set...
When Loading the existing filter. How do I pass this CurrencyID = 1 to select2 helper?
Update:
With Oleg's answer, I updated my code as below.
{
name: 'CurrencyID', hidden: true, searchtype: 'number', search: true,
stype: "select", searchoptions: {
searchhidden: true,
sopt: ["eq", "ne"],
dataUrl: paramFromView.CurrencyOptions.searchURL,
buildSelect: function (data) {
var obj = jQuery.parseJSON(data);
var i, options = [];
for (i = 0; i < obj.result.length; i++) {
options.push("<option value='" + obj.result[i][paramFromView.CurrencyOptions.idField] + "'>" +
obj.result[i][paramFromView.CurrencyOptions.txtField] + "</option>");
}
return "<select>" + options.join("") + "</select>";
},
noFilterText: "Any",
selectFilled: function (options) {
setTimeout(function () {
$(options.elem).select2({
width: 'element',
});
}, 0);
}
},
searchrules: { required: true }
},
I'm almost there with what I wanted to achieve. However I'm still facing some difficulties.
When the filter is initially loaded, value is selected on the dropdown but query value is empty. i.e. if the user clicks on the find button soon after the filter form is loaded, no filter will be set.
I still cannot get select2 styles working.
I can demonstrate how to use select2 with free jqGrid fork of jqGrid, which I develop. I get the demo from the README of the old version 4.14.1 (the current released version is 4.15.3) and modified it to demonstrate the usage of select2.
The main part of the code could be
stype: "select",
searchoptions: {
sopt: ["eq", "ne"],
...
selectFilled: function (options) {
setTimeout(function () {
$(options.elem).select2({
width: "100%"
});
}, 0);
}
}
See https://jsfiddle.net/Lae6kee7/2/. You can try to choose an option in the filter toolbar in "Shipped via" column and the open the search dialog. You will see that the select2 will have the same option selected.
If you would load the data via Ajax request posted by select2 than your code will be much more complex as it could be. It's important to understand that such way is really required only for really large set of possible value. I means the number of items larger as 100000 items for example. On the other side, the most use cases required less as 1000 options. In the case it would be more effective to load all the data as options of select and then convert the select to select2. select2, which uses local select works much more quickly from the users point of view.
The code will be easier in my opinion if you will use dataUrl instead of ajax option of select2. You can use dataUrl to return from the server all different values, which can be used in select2 and to use buildSelect to build <select> from JSON data returned from the server. The demo https://jsfiddle.net/Lae6kee7/23/ demonstrates that. I made the demo for JSFiddle, which supports Echo service (see here), which allows to simulate server responses. Your real code should contains mostly only dataUrl, buildSelect and the code of selectFilled, which I included above.
Additionally, I'd recommend you to consider to use <datalist> (see here for example), which could be good alternative to select2. All modern web browsers contains native support of <datalist> and thus <datalist> works very quickly. Try to search in the first Client column of my demos. You will see control, which will be very close to select2. Additional advantage of <datalist>: one will be able not search for only exact predefined values like test10, test11 or test12, but for substrings like 1. Compare
with
or
with
Related
I created a Kendo UI Grid view and it displays data correctly , now what I am trying to achieve is that ; When i Click on a row I want to get the primary key of that row and use it elsewhere I tried many solution in net but I did not work. does anyone knows how to achieve this.
here is my code :
function FondsGrid() {
var sharedDataSource = new kendo.data.DataSource({
transport: {
read: {
url:
"http://localhost:...........",
dataType: "json"
}
},
pageSize: 20
});
var accountGrid = $("#grid-fonds").kendoGrid({
dataSource: sharedDataSource,
sortable: true,
pageable: false,
columns: [
{
field: "CodIsin",
title: " ",
template: '<span class="categ #= CodIsin #"></span>',
attributes: {
class: "text-center"
},
headerattributes: {
style: "text-align:center"
},
width: 35
},
{
field: "LIBELLEPDT",
title: "Nom du fonds",
template: '<div id="#: IdProduitSP #" class="title-fonds #:
IdProduitSP #" data-toggle="popover" ><span class="desc-
fonds">#: LibClassificationNiv2 #</span>#: LIBELLEPDT #
.
.
.
dataBound: function () {
var widthGrid = $('.k-grid-content').width();
$(".k-grid-header").width(widthGrid);
$(".title-fonds").popover({
trigger: 'hover',
html: true,
template: '<div class="popover HalfBaked" role="tooltip">
<div class="arrow"></div><h3 class="popover-header"></h3><div
class="popover-body"></div></div>',
content: function () {
return $('#popover-content').html();
}
});
}
}).getKendoGrid();
/* Initialisation */
$(document).ready(function ($) {
FondsGrid();
});
Your own answer is perfectly valid and is a good example of how you can use jquery to directly target the dom elements that kendo generates. This approach is always valuable when kendo does not offer the functionality you need.
However in this case, the grid widget offers the change event. You can set the grid to be 'selectable' and subscribe to the 'change' event which fires when one or more rows are selected:
selectable: "multiple, row",
change: function(e) {
var selectedRows = this.select();
var selectedDataItems = [];
for (var i = 0; i < selectedRows.length; i++) {
var dataItem = this.dataItem(selectedRows[i]);
selectedDataItems.push(dataItem);
}
// selectedDataItems contains all selected data items
}
Within the handler function, 'this' refers to the grid widget instance and calling the select() function on it returns the selected rows. From those rows, you can then retrieve the datasource items that are bound to them giving you access to the id and any other properties.
See here for more details: https://docs.telerik.com/kendo-ui/api/javascript/ui/grid/events/change
This how I fixed It.
$("#grid-fonds").on("click", "td", function (e) {
var row = $(this).closest("tr");
var value = row.find("td:first").text();
console.log(value);
});
I am using select2 select box to populate and show some server data. Most of it works fine as I am able to get the results and populate the combo box. But when I type in the search box, the selection doesn't narrow down the the closest match.
I found the problem was because the backend URL doesn't support searching based on the string provided, while select2 keeps making multiple search request to backend, based on user entered text. The legacy backend code returns results in one shot, which is populated into the combobox the first time.
My question is, how do I get the the select box to focus to the closest matching result, without making multiple Ajax calls. I want the search to happen in the results which are already fetched.
Thanx to anyone helping me out on this.
My ajax call is like below, if this helps...
select2: {
placeholder: 'Select Next Plan Id',
allowClear: true,
id: function (item) {
return item.id;
},
ajax: {
type: 'GET',
dataType: "jsonp",
url: "http://172.16.7.248:8480/app/gui?action=1&type=11",
data: function (term, page) {
return { search: term };
},
results: function (data, page) {
return { results: data.aaData };
},
success : function(data, status, xhr) {
var html = "<option value=''>None</option>";
$.each(data.aaData, function(i, item) {
html += "<option data=" + JSON.stringify(item.id) + " value=" + item.id + "'>" + item.id + "</option>";
});
$('#nextplanid').html(html);
self.prop('data-loaded', 'true');
},
error : function(data, status, xhr) {
}
},
formatResult: function (item) {
return item.id;
},
formatSelection: function (item) {
return item.id;
},
initSelection: function (element, callback) {
return $.get('/getText', { query: element.val() }, function (data) {
callback(data);
});
}
},
In my jquery autocomplete select function, I need to use the event.preventDefault() method to prevent the default ui.item.value from populating the input text box the autocomplete is wired too. This works great in Chrome, however in IE 8 (which is in use by a majority of our users) the .preventDefault() line throws the following error:
Unexpected call to method or property access
Here is the jQuery for good measure. Does anyone know of a work-around for this method in IE 8?
var tempResults = [];
$(function () {
$('#DRMCompanyName').autocomplete({
source: function (request, response) {
$.ajax({
url: '#Url.Action("compSearchByName", "AgentTransmission")',
type: 'GET',
dataType: 'json',
data: request,
success: function (data) {
tempResults = data;
response($.map(data, function (value, key) {
return {
label: value + " " + key,
value: key
};
}));
},
});
},
minLength: 2,
select: function (event, ui) {
event.preventDefault(); // <-Causing a problem in IE 8...
$('#DRMCompanyName').val(tempResults[ui.item.value]);
$('#DRMCompanyName').text(tempResults[ui.item.value]);
if ($('#DRMCompanyId').text() == '') {
$('#DRMCompanyId').val(ui.item.value);
$('#DRMCompanyId').text(ui.item.value);
}
}
});
});
You could use return false instead but as i said in comment: return false = event.preventDefault() + event.stopPropagation() But in your case, should fit your needs.
I am migrating my app to twitter-bootstrap and i would like to replace my jquery-ui autocomplete with typeahead.js.
It would be better to use the feature embedded in twitter-bootstrap but i am ok with the extra typeahead plugin if necessary.
My problem is that i have trouble reproducing the current behaviour especially with the absence of results.
How would you do something like that?
$("#search").autocomplete({
source : myUrl,
delay : 100,
minLength : 2,
select : function(event, ui) {
// do whatever i want with the selected item
},
response : function(event, ui) {
if (ui.content.length === 0) {
ui.content.push({
label : "No result",
value : customValue
});
}
}
});
Basically, if there is no result, i want to display a custom message in the component.
Thanks!
The migration to Bootstrap typeahead would look something like..
$('.typeahead').typeahead({
minLength:2,
updater: function (item) {
/* do whatever you want with the selected item */
},
source: function (typeahead, query) {
/* put your ajax call here..
return $.get('/typeahead', { query: query }, function (data) {
return typeahead.process(data);
});
*/
}
});
EDIT:
I've updated the demo to include a sorter and highlighter. I think this will get you the results you want..
sorter: function(items) {
if (items.length == 0) {
var noResult = new Object();
items.push(noResult);
}
return items;
},
highlighter: function(item) {
if (dataSource.indexOf(item) == -1) {
return "<span>No Match Found.</span>";
}
else {
return "<span>"+item+"</span>";
}
},
Bootstrap Typeahead Demo
I don't think the typeahead has an equivalent to delay, but there are some jquery workarounds for this.
With the latest version of Typeahead.js (0.10) it is now possible to specify an empty template to display when no results are found.
$('.typeahead').typeahead({
hint: true,
highlight: true,
minLength: 2
},{
name: 'examples',
source: examples.ttAdapter(),
templates: {
empty: [
'<div class="empty-message">',
'unable to find any results that match the current query',
'</div>'
].join('\n')
}
});
I have the following code and am curious as how to force the input to match the contents of the autocomplete:
$("#foo").autocomplete({
source: function( request, response ) {
$.ajax({
url: "index.pl",
dataType: "json",
data: {
type: 'foo',
term: request.term
},
success: function( data ) {
response( $.map( data.items, function( item ) {
return {
value: item.id
}
}));
}
});
},
minLength: 1
});
Answering this question for the benefit of anyone who stumbles upon this problem in 2013(yeah right!)
$("#my_input").autocomplete({
source: '/get_data/',
change: function(event, ui) {
var source = $(this).val();
var temp = $(".ui-autocomplete li").map(function () { return $(this).text()}).get();
var found = $.inArray(source, temp);
if(found < 0) {
$(this).val(''); //this clears out the field if non-existing value in <select><options> is typed.
}
}
});
Explanation:
The map() method creates a jQuery object populated with whatever is returned from the function (in this case, the text content of each <li> element).
The get() method (when passed no argument) converts that jQuery object into an actual Array.
Here is the original link of where I saw the solution.
I hope this helps. Thanks!