Case insensitive search in search2.js - javascript

I am using select2.js in my project for drop down functionality. By default behaviour this is case sensitive i.e tag and Tag will be consider different.
But as per my requirement i required result populate is case insensitive i.e. when writing tag or Tag both need to considered to be small like in capital. I have tried many solution for this but non of that seems to working. I need to deal this client side only.
Issue is like this "https://groups.google.com/forum/#!topic/select2/vk86jUMfJTk"
$('#Taging').select2({
tags : true,
tokenSeparators : [ ',' ],
createSearchChoice : function(term) {
return {
id : term,
text : term,
n : "new",
s : ""
};
},
ajax : {
},
// Take default tags from the input value
initSelection : function(element, callback) {
var data = [];
$(splitVal(element.val(), ",")).each(function() {
data.push({
id : this,
text : this
});
});
callback(data);
},
});
sample Code

I modified my code and that works
createSearchChoice : function(term,data) {
if (term.trim().length > 0) {
if ($(data).filter(function () {
return this.text.toLowerCase().localeCompare(term.toLowerCase()) === 0;
}).length === 0) {
return {
id: term,
text: term,
n : "new",
s : "",
isNew: true // this is necessary to check if the item is newly added or not
};
}
}
},

Related

What I m missing to implement case insensitive search?

Here is my js file. I 've done everything in the server side. And implemented all basic and some advance feature of Datatable plugins. But the search function is case sensitive. If I search for "oil" it shows oil only but not OIL.
$(document).ready(function () {
var oTable = $('#myDataTable').dataTable({
"bServerSide": true,
"sPaginationType": "full_numbers",
"sAjaxSource": "/DB/AjaxOil",
"bProcessing": true,
"Search": {
"caseInsensitive": true
},
"aoColumns": [
{
"sName": "OilId",
"aTargets": [0], //Edit column
"mData": "OilId",
"bSearchable": false,
"bSortable": false,
"mRender": function (data, type, full) {
var id = full[0]; //row id in the first column
return "<a>"+id+"</a>";
}
},
{ "sName": "CommonName" },
{ "sName": "BotanicalName" },
{ "sName": "PlantParts" },
{ "sName": "Distillation" }
],
"columnDefs": [
{
"targets": [0],
className: "hide_column",
"searchable": false
}
]
});
});
And Here is my ajax function
public ActionResult AjaxOil(JQueryDataTableParamModel param)
{
IEnumerable<Oil> allOils = _context.Oils.ToList();
IEnumerable<Oil> filteredOils;
if (!string.IsNullOrEmpty(param.sSearch))
{
filteredOils = allOils
.Where(c => c.CommonName.Contains(param.sSearch)
||
c.BotanicalName.Contains(param.sSearch)
||
c.PlantParts.Contains(param.sSearch)
||
c.Distillation.Contains(param.sSearch));
}
else
{
filteredOils = allOils;
}
var sortColumnIndex = Convert.ToInt32(Request["iSortCol_0"]);
Func<Oil, string> orderingFunction = (c => sortColumnIndex == 1 ? c.CommonName :
sortColumnIndex == 2 ? c.BotanicalName :
c.PlantParts);
var distillationFilter = Convert.ToString(Request["sSearch_4"]);
var commonFilter = Convert.ToString(Request["sSearch_1"]);
var botanicalFilter = Convert.ToString(Request["sSearch_2"]);
var plantFilter = Convert.ToString(Request["sSearch_3"]);
if (!string.IsNullOrEmpty(commonFilter))
{
filteredOils = filteredOils.Where(c => c.CommonName.Contains(commonFilter));
}
if (!string.IsNullOrEmpty(botanicalFilter))
{
filteredOils = filteredOils.Where(c => c.BotanicalName.Contains(botanicalFilter));
}
if (!string.IsNullOrEmpty(plantFilter))
{
filteredOils = filteredOils.Where(c => c.PlantParts.Contains(plantFilter));
}
if (!string.IsNullOrEmpty(distillationFilter))
{
filteredOils = filteredOils.Where(c => c.Distillation.Contains(distillationFilter));
}
var sortDirection = Request["sSortDir_0"];
if (sortDirection == "asc")
filteredOils = filteredOils.OrderBy(orderingFunction);
else
filteredOils = filteredOils.OrderByDescending(orderingFunction);
var displayedOils = filteredOils
.Skip(param.iDisplayStart)
.Take(param.iDisplayLength);
var result = from c in displayedOils
select new[] { Convert.ToString(c.OilId), c.CommonName, c.BotanicalName, c.PlantParts, c.Distillation };
return Json(new
{
sEcho = param.sEcho,
iTotalRecords = allOils.Count(),
iTotalDisplayRecords = filteredOils.Count(),
aaData = result
},
JsonRequestBehavior.AllowGet);
}
P.s. The database has 5million row so please suggest with performance point of view too.
First of all you should not use _context.Oils.ToList(); then you will retrieve all your records from the database before filtering them. If you place the ToList() after .Take(param.iDisplayLength) all your selection code will be translated to a query in your database and only the relevant records will be retrieved. There is a difference between Contains executed by the Linq extension (case sensitve; see also this SO question) and the Contains that will we translated by the Entity Framework to a LIKE SQL statement (see this SO question and this video about tracing the SQL statements generated by your code).
As Shyju mentioned, refer to this post:
Case insensitive 'Contains(string)'
This will give you a wholistic idea of what to expect.
Here is a small excerpt from the post for your reference:
To test if the string paragraph contains the string word (thanks #QuarterMeister)
culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0
Where culture is the instance of CultureInfo describing the language that the text is written in.
In addition, I encourage you to visit this article which has an exhaustive comparison of various methods’ performances while checking if a string occurs within a string. This should help you decide what approach to take for better performance.
http://cc.davelozinski.com/c-sharp/fastest-way-to-check-if-a-string-occurs-within-a-string
Based on your question, you may have to create an extension method which will use different approach to preform check based on the type of input to achieve best performance.
Hope this helps!

how to call query call back data to data attribute select2

$('#placeSelect').select2({
width: '100%',
allowClear: true,
multiple: true,
maximumSelectionSize: 1,
placeholder: "Click here and start typing to search.",
data: function(query) {
queryData{!randomJsIden}(query);
},
matcher: function (term, text) {if (text.toUpperCase().indexOf(term.toUpperCase()) == 0){return true;}return false;}
});
function queryData{!randomJsIden}(query){
Visualforce.remoting.Manager.invokeAction(
'{!$RemoteAction.AutoCompleteV2_Con.getData}','{!sObjVal}','{!labelFieldVar}','{!valueFieldVar}',query.term,
function(result, event){
//if success
if(event.status){
var data = {results:[{ id: 1, text: "Ford" },
{ id: 2, text: "Dodge" },
{ id: 3, text: "Mercedes" },
{ id: 4, text: "Jaguar" }]}
query.callback( data);
}
},
{escape: true}
);
}
</script>
How to initialize query call back data to data attribute in select2 .
I cannot use data directly .In above example i am using sample data .
query : function(query){
queryData{!randomJsIden}(query);
}
I want to replace this by data attribute like this : the below one is not working
data : function(query){
queryData{!randomJsIden}(query);
}
here is the fiddle :
http://jsfiddle.net/Lnf8j/303/
Let me know any ideas from you
There are couple of issues in your code
you cannot name a function using flower braces as it is reserved notation symbol in javascript function queryData{!randomJsIden}(query), instead name it as function queryData(query){ ... }
if your adding a callback for data of your select2 then you need to return that data constructed from queryData() function.
data: function(query) {
return queryData(query);
},
function queryData(query){
...
return data;
}
If i'am not wrong,data is sourced to select2 via asynchronous call inside queryData(), which means the data is returned at unpredictable time,so you need to restrict the user from accessing the select2 component until data is feeded to it.
which means you either need to prefetch the data or disable the select2 field until data is returned from remote call.
Working Demo # JSFiddle

Filter using Underscore - roots and children

Well, it's probably very basic for experienced ppl. It's my 1st time with underscore. I've this json.
{
"especiais" : {
"text" : {
"pt" : "Especiais"
},
"active" : true
},
"conjuntos" : {
"text" : {
"pt" : "Conjuntos"
},
"active" : true,
"subItems" : {
"saiaEcamiseta" : {
"text" : {
"pt" : "Saia e Camiseta"
},
"active" : true
},
"sandalhas" : {
"text" : {
"pt" : "Sandalhas"
},
"active" : true
}
}
},
"macacoes" : {
"text" : {
"pt" : "Macacões"
},
"active" : true
},
"roupasBasicas" : {
"text" : {
"pt" : "Roupas Básicas"
},
"active" : true,
"subItems" : {
"xortes" : {
"text" : {
"pt" : "Xortes"
},
"active" : true
},
"camiseta" : {
"text" : {
"pt" : "Camisetas"
},
"active" : true
}
}
},
"enxoval" : {
"text" : {
"pt" : "Enxoval"
},
"active" : true
}
}
And I want to list only active roots of itens and subitems. So, in the example above, macacoes and his children will not be listed and Xortes (child of roupasBasicas) will not be listed as well and it's includes possible grandchildren if appliable.
I made my 1st attempt:
result = _und.filter(data.productCategories, function (item) {
return item && item.active.indexOf(true) != -1;
});
but it's not working :( Can anybody help me ?
Due to lack of reputation I cannot ask for clarification so I will take my best stab at an answer for you.
var children = [];
//Get all of the subitems that are active so we can merge with the primary result set
_.each(data.pt, function(item){
if(item.subItems){
_.each(item.subItems, function(child){
if(child.active) children.push(child);
});
}
});
//Gather all active items in the primary result set
var result = _.filter(data.pt, function(item){
return item.active;
});
//Add each active subItem to our results
_.each(children, function(child){
result.push(child);
});
Here is a plunkr of my understanding:
http://plnkr.co/edit/qx6U6ZcmcfhqJxmNulzP?p=preview
-- Take a look at the script.js since it will provide the core implementation.
From my understanding you wanted to gather all "active" items within the context of that pt object?
If that is the case, the filter I provide via the link will be fine though you will still have the items underneath the parent.
If those need to be filtered you could simply null out the field that attaches that data to the object (or more clever ways if you so choose).
The _.filter function seems the best fit for this since you are allowed to filter a dataset given a predicate. The function in the second part of the query I provided in aforementioned code narrows the scope of the original data set down based on whether or not they are active.

Set jsTree Node to "Undetermined" State

I'm using jsTree to show a tree with checkboxes. Each level of nodes is loaded on-demand using the json_data plugin.
If a node's descendent is checked, then that node should be in an "undetermined state" (like ACME and USA).
The problem is, the tree starts out collapsed. ACME looks unchecked but should be undetermined. When I finally expand to a checked node, jsTree realizes the ancestors should be undetermined.
So I need to be able to put a checkbox in the undetermined state without loading its children.
With jsTree you can pre-check a box by adding the jstree-checked class to the <li>. I tried adding the jstree-undetermined class, but it doesn't work. It just puts them in a checked state.
Here's my code:
$("#tree").jstree({
plugins: ["json_data", "checkbox"],
json_data: {
ajax: {
url: '/api/group/node',
success: function (groups) {
var nodes = [];
for (var i=0; i<groups.length; i++) {
var group = groups[i];
var cssClass = "";
if(group.isSelected)
cssClass = "jstree-checked";
else if(group.isDecendantSelected)
cssClass = "jstree-undetermined";
nodes.push({
data: group.name,
attr: { 'class': cssClass }
});
}
return nodes;
}
}
}
})
My Question
How do I set a node to the undetermined state?
I had the same problem and the solution I found was this one:
var tree = $("#tree").jstree({
plugins: ["json_data", "checkbox"],
json_data: {
ajax: {
url: '/api/group/node',
success: function(groups) {
var nodes = [];
for (var i = 0; i < groups.length; i++) {
var group = groups[i];
var checkedState = "false";
if (group.isSelected)
checkedState = "true";
else if (group.isDecendantSelected)
checkedState = "undetermined";
nodes.push({
data: group.name,
attr: { 'checkedNode': checkedState }
});
}
return nodes;
},
complete: function () {
$('li[checkedNode="undetermined"]', tree).each(function () {
$(this).removeClass('jstree-unchecked').removeClass('jstree-checked').addClass('jstree-undetermined');
});
$('li[checkedNode="true"]', tree).each(function () {
$(this).removeClass('jstree-unchecked').removeClass('jstree-undetermined').addClass('jstree-checked');
});
$('li[checkedNode="false"]', tree).each(function () {
$(this).removeClass('jstree-checked').removeClass('jstree-undetermined').addClass('jstree-unchecked');
});
}
}
}
});
Hope it helps you!
Maybe this changed in the meanwhile...
But now (version 3.0.0) the really simple solution works:
{
id : "string" // will be autogenerated if omitted
text : "string" // node text
icon : "string" // string for custom
state : {
opened : boolean // is the node open
disabled : boolean // is the node disabled
selected : boolean // is the node selected
undetermined : boolean // is the node undetermined <<==== HERE: JUST SET THIS
},
children : [] // array of strings or objects
li_attr : {} // attributes for the generated LI node
a_attr : {} // attributes for the generated A node
}
Learned directly from the source code at: https://github.com/vakata/jstree/blob/6507d5d71272bc754eb1d198e4a0317725d771af/src/jstree.checkbox.js#L318
Thank you guys, and I found an additional trick which makes life a little better, but it requires a code change in jstree.js. Looks like an oversight:
Look at the get_undetermined function, and scan for the keyword break. That break should be a continue.
If you make that one change, then all you need to do is provide the state (for the main object and its children), and jstree will automatically take care of cascading upwards for undetermined state. It was bailing out early from the scripting and failing to catch all the undetermined nodes properly, requiring the above ugly workarounds for styling and such.
Here's my config (no special attrs or complete() function required) using AJAX:
var tree = $('#jstree').jstree({
"core": {
"themes": {
"variant": "large"
},
'data': {
'url': function (node) {
return "{{API}}/" + node.id + "?product_id={{Product.ID}}"
},
'dataType': 'json',
'type': 'GET',
'success': function (data) {
if (data.length == 0) {
data = rootStub
}
return {
'id': data.id,
'text': data.text,
'children': data.children,
'state': data.state,
}
}
}
},
"checkbox": {
// "keep_selected_style": false,
"three_state": false,
"cascade": "undetermined"
},
"plugins": ["wholerow", "checkbox"],
});

JEditable, how to handle a JSON response?

Right now, the server response I'm working with sends back a JSON response like this:
{"status":1}
After saving, jeditable places the actual response: {"status":1} on the page. Anyway to get around this issue?
A better solution is to post-process the returned json data before it hits the page.
Suppose your server returns the following json string:
{ "status": 1, "result": "value to be displayed", "other": "some other data" }
and you would like to process the "status" and "other" fields, and display the "result" field in the jeditable input field.
Add the following 2 lines to jquery.jeditable.js:
(around line 95):
var intercept = settings.intercept || function(s) {return s; };
(around line 350, right after " success : function(result, status) {"
result = intercept.apply(self,[result]);
Then, in your own code, do something like the following:
$(some_field).editable(
'/some_url_on_your_server',
{
indicator : "<img src='/images/spinner.gif'>",
tooltip: "Click to edit.",
indicator: "Saving...",
onblur: "submit",
intercept: function (jsondata) {
obj = jQuery.parseJSON(jsondata);
// do something with obj.status and obj.other
return(obj.result);
},
etc.
This allows you do cool stuff like having your server convert abbreviations to full strings etc.
Enjoy!
There's a simple way of doing this by using the callback. .editable() converts any response to a string, so the response has to be converted to a JSON variable. The values can then be retrieved and then written using a '.text()' method. Check the code:
$("#myField").editable("http://www.example.com/save.php", {
submit : 'Save',
cancel : 'Cancel',
onblur : "ignore",
name : "sentText",
callback : function(value, settings) {
var json = $.parseJSON(value);
$("#myField").text(json.sentText);
}
});
This is how I handled the json response.
First, set the datatype using ajaxoptions. Then, handle your data in the callback function. Therein, this.revert is your original value.
oTable.$('td:eq(3)').editable('/admin/products/add_quantity_used', {
"callback" : function(sValue, y) {
var aPos = oTable.fnGetPosition(this);
if($("#dialog-message").length != 0){
$("#dialog-message").remove();
}
if(!sValue.status){
$("body").append('<div id="dialog-message" style="display:none;">'+sValue.value+'</div>');
$( "#dialog-message" ).dialog({
modal: true,
buttons: {
Ok: function() {
$( this ).dialog( "close" );
}
}
});
if(this.revert != '')
oTable.fnUpdate(this.revert, aPos[0], aPos[1]);
else
oTable.fnUpdate("click to edit", aPos[0], aPos[1]);
}else
if(sValue.status)
oTable.fnUpdate(sValue.value, aPos[0], aPos[1]);
},
"submitdata" : function(value, settings) {
return {
"data[users_to_products][users_to_products_id]" : this.parentNode.getAttribute('id'),
"column" : oTable.fnGetPosition(this)[2]
};
},
"height" : "30px",
"width" : "30px",
"maxlength" : "3",
"name" : "data[users_to_products][quantity_used]",
"ajaxoptions": {"dataType":"json"}
}).attr('align', 'center');
So the solution I came up with is similar to what madcapnmckay answered here.
var editableTextArea = $('.editable-textarea');
editableTextArea.editable(submitEditableTextArea, {
type : 'textarea',
cancel : 'Cancel',
submit : 'Save',
name : editableTextArea.attr('id'),
method : 'post',
data : function(value, settings) {
return $.fn.stripHTMLforAJAX(value);
},
event : "dblclick",
onsubmit : function(value, settings) {
//jquery bug: on callback reset display from block to inline
$('.btn-edit').show(0, function(){$(this).css('display','inline');});
},
onreset : function(value, settings) {
//jquery bug: on callback reset display from block to inline
$('.btn-edit').show(0, function(){$(this).css('display','inline');});
}
});
Then the url function is
function submitEditableTextArea(value, settings) {
var edits = new Object();
var result = $.fn.addHTMLfromAJAX(value);
edits[settings.name] = [value];
var returned = $.ajax({
type : "POST",
data : edits,
dataType : "json",
success : function(_data) {
var json = eval( _data );
if ( json.status == 1 ) {
console.log('success');
}
}
});
return(result);
}

Categories