Make an array case-insensitive [duplicate] - javascript

I'm trying to use "contains" case insensitively. I tried using the solution at the following stackoverflow question, but it didn't work:
Is there a case insensitive jQuery :contains selector?
For convenience, the solution is copied here:
jQuery.extend(
jQuery.expr[':'], {
Contains : "jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase())>=0"
});
Here is the error:
Error: q is not a function
Source File: /js/jquery-1.4.js?ver=1.4
Line: 81
Here's where I'm using it:
$('input.preset').keyup(function() {
$(this).next().find("li").removeClass("bold");
var theMatch = $(this).val();
if (theMatch.length > 1){
theMatch = "li:Contains('" + theMatch + "')";
$(this).next().find(theMatch).addClass("bold");
}
});
My use of the original case sensitive "contains" in the same scenario works without any errors. Does anyone have any ideas? I'd appreciate it.

This is what i'm using in a current project, haven't had any problems. See if you have better luck with this format:
jQuery.expr[':'].Contains = function(a, i, m) {
return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
};
In jQuery 1.8 the API for this changed, the jQuery 1.8+ version of this would be:
jQuery.expr[":"].Contains = jQuery.expr.createPseudo(function(arg) {
return function( elem ) {
return jQuery(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
};
});
You can test it out here. For more detail on 1.8+ custom selectors, check out the Sizzle wiki here.

It's worth noting that the answer is correct but only covers :Contains, and not the alias :contains which could lead to unexpected behavior (or could be used by design for advanced applications that require both sensitive and insensitive search).
This could be resolved by duplicating the extention for the alias:
jQuery.expr[':'].Contains = function(a, i, m) {
return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
};
jQuery.expr[':'].contains = function(a, i, m) {
return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
};
Took me a while to work out why it wasn't working for me.

I would do something like this
$.expr[':'].containsIgnoreCase = function (n, i, m) {
return jQuery(n).text().toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
};
And Leave :contains Alone...
DEMO
So why jQuery doesn't support it in it's library?! if it is that easy...
because Does your code pass the turkey code?

May be late.... but,
I'd prefer to go this way..
$.extend($.expr[":"], {
"MyCaseInsensitiveContains": function(elem, i, match, array) {
return (elem.textContent || elem.innerText || "").toLowerCase().indexOf((match[3] || "").toLowerCase()) >= 0;
}
});
This way, you DO NOT tamper with jQuery's NATIVE '.contains'... You may need the default one later...if tampered with, you might find yourself back to stackOverFlow...

i'll allow myself to add my friends:
$.expr[":"].containsNoCase = function (el, i, m) {
var search = m[3];
if (!search) return false;
return eval("/" + search + "/i").test($(el).text());
};

I was just able to ignore jQuery's case sensitivity altogether to achieve what I want using below code:
$.expr[":"].contains = $.expr.createPseudo(function(arg) {
return function( elem ) {
return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
};
});
You can use this link to find code based on your jQuery versions to ignore case sensitivity,
https://css-tricks.com/snippets/jquery/make-jquery-contains-case-insensitive/
Also if you want to use :contains and make some search you may want to take a look at this: http://technarco.com/jquery/using-jquery-search-html-text-and-show-or-hide-accordingly

Related

Search Engine with jQuery :contains() [duplicate]

Is there a case insensitive version of the :contains jQuery selector or should I do the work manually by looping over all elements and comparing their .text() to my string?
What I ended up doing for jQuery 1.2 is :
jQuery.extend(
jQuery.expr[':'], {
Contains : "jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase())>=0"
});
This will extend jquery to have a :Contains selector that is case insensitive, the :contains selector remains unchanged.
Edit: For jQuery 1.3 (thanks #user95227) and later you need
jQuery.expr[':'].Contains = function(a,i,m){
return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase())>=0;
};
Edit:
Apparently accessing the DOM directly by using
(a.textContent || a.innerText || "")
instead of
jQuery(a).text()
In the previous expression speeds it up considerably so try at your own risk if speed is an issue. (see #John 's question)
Latest edit: For jQuery 1.8 it should be:
jQuery.expr[":"].Contains = jQuery.expr.createPseudo(function(arg) {
return function( elem ) {
return jQuery(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
};
});
To make it optionally case insensitive:
http://bugs.jquery.com/ticket/278
$.extend($.expr[':'], {
'containsi': function(elem, i, match, array)
{
return (elem.textContent || elem.innerText || '').toLowerCase()
.indexOf((match[3] || "").toLowerCase()) >= 0;
}
});
then use :containsi instead of :contains
As of jQuery 1.3, this method is deprecated. To get this to work it needs to be defined as a function:
jQuery.expr[':'].Contains = function(a,i,m){
return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase())>=0;
};
If someone (like me) is interested what do a and m[3] mean in Contains definition.
KEY/LEGEND: Params made available by jQuery for use in the selector definitions:
r = jQuery array of elements being scrutinised. (eg: r.length = Number of elements)
i = index of element currently under scrutiny, within array r.
a = element currently under scrutiny. Selector statement must return true to include it in its matched results.
m[2] = nodeName or * that we a looking for (left of colon).
m[3] = param passed into the :selector(param). Typically an index number, as in :nth-of-type(5), or a string, as in :color(blue).
In jQuery 1.8 you will need to use
jQuery.expr[":"].icontains = jQuery.expr.createPseudo(function (arg) {
return function (elem) {
return jQuery(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
};
});
A variation that seems to perform slightly faster and that also allows regular expressions is:
jQuery.extend (
jQuery.expr[':'].containsCI = function (a, i, m) {
//-- faster than jQuery(a).text()
var sText = (a.textContent || a.innerText || "");
var zRegExp = new RegExp (m[3], 'i');
return zRegExp.test (sText);
}
);
Not only is this case-insensitive, but it allows powerful searches like:
$("p:containsCI('\\bup\\b')") (Matches "Up" or "up", but not "upper", "wakeup", etc.)
$("p:containsCI('(?:Red|Blue) state')") (Matches "red state" or "blue state", but not "up state", etc.)
$("p:containsCI('^\\s*Stocks?')") (Matches "stock" or "stocks", but only at the start of the paragraph (ignoring any leading whitespace).)
May be late.... but,
I'd prefer to go this way..
$.extend($.expr[":"], {
"MyCaseInsensitiveContains": function(elem, i, match, array) {
return (elem.textContent || elem.innerText || "").toLowerCase().indexOf((match[3] || "").toLowerCase()) >= 0;
}
});
This way, you DO NOT tamper with jQuery's NATIVE '.contains'... You may need the default one later...if tampered with, you might find yourself back to stackOverFlow...
jQuery.expr[':'].contains = function(a,i,m){
return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase())>=0;
};
The update code works great in 1.3, but "contains" should be lower case on the first letter unlike the previous example.
Refer below to use ":contains" to find text ignoring its case sensitivity from an HTML code,
$.expr[":"].contains = $.expr.createPseudo(function(arg) {
return function( elem ) {
return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
};
});
$("#searchTextBox").keypress(function() {
if($("#searchTextBox").val().length > 0){
$(".rows").css("display","none");
var userSerarchField = $("#searchTextBox").val();
$(".rows:contains('"+ userSerarchField +"')").css("display","block");
} else {
$(".rows").css("display","block");
}
});
You can also use this link to find case ignoring code based on your jquery version,
Make jQuery :contains Case-Insensitive
A faster version using regular expressions.
$.expr[':'].icontains = function(el, i, m) { // checks for substring (case insensitive)
var search = m[3];
if (!search) return false;
var pattern = new RegExp(search, 'i');
return pattern.test($(el).text());
};
I had a similar problem with the following not working...
// This doesn't catch flac or Flac
$('div.story span.Quality:not(:contains("FLAC"))').css("background-color", 'yellow');
This works and without the need for an extension
$('div.story span.Quality:not([data*="flac"])').css("background-color", 'yellow');
This works too, but probably falls into the "manually looping" category....
$('div.story span.Quality').contents().filter(function()
{
return !/flac/i.test(this.nodeValue);
}).parent().css("background-color", 'yellow');
New a variable I give it name subString and put string you want to search in some elements text. Then using Jquery selector select elements you need like my example $("elementsYouNeed") and filter by .filter(). In the .filter() it will compare each elements in $("elementsYouNeed") with the function.
In the function i using .toLowerCase() for element text also subString that can avoid case sensitive condition and check if there is a subString in it. After that the .filter() method constructs a new jQuery object from a subset of the matching elements.
Now you can get the match elements in matchObjects and do whatever you want.
var subString ="string you want to match".toLowerCase();
var matchObjects = $("elementsYouNeed").filter(function () {return $(this).text().toLowerCase().indexOf(subString) > -1;});

Better method of checking a bunch of conditions

I'm new to javascript and still coming to terms with the language's nuances.
I have a piece of code where I have to check a set of conditions on a particular variable.
if (a=="MAIN_DOMAINNAME" || a=="DOMAIN_SERIAL" || a=="DOMAIN_REFRESH" || a=="DOMAIN_RETRY" || a=="DOMAIN_EXPIRE" || a=="DOMAIN_NEGTTL" || a=="MAIN_NS") {
Is there a better way to do this conditional check, like say:
if a is one of ("DOMAIN_SERIAL", "MAIN_DOMAINNAME", "DOMAIN_REFRESH" ) {?
Assuming a relatively modern browser, you can use Array.indexOf (spec)
if (["DOMAIN_SERIAL", "MAIN_DOMAINNAME", "DOMAIN_REFRESH"].indexOf(a) !== -1)
Note - you can easily shim it for older browsers (see the mdn link on how).
A regex would be shorter and works everywhere :
if ( /^(MAIN_DOMAINNAME|DOMAIN_SERIAL|DOMAIN_REFRESH|..)$/.test(a) ) {
// do stuff
}
FIDDLE
var ars = ["DOMAIN_SERIAL", "MAIN_DOMAINNAME", "DOMAIN_REFRESH"];
if(ars.some(function(ar){ return a === ar; })){
// do smth
}
Should mention the switch statement as it should be working fine with the example given in the question.
switch(a) {
case('MAIN_DOMAINAME'):
case('DOMAIN_SERIAL'):
case('DOMAIN_REFRESH'):
case('DOMAIN_RETRY'):
console.log('Go wild.');
break;
}
Not as lightweight as the other answers, but it's readable and matches (a === b).
I prefer the regex solution already provided by adeneo, but if you want something that matches the
if a is one of (...
wording from the question reasonably closely you can do this:
if (a in list("MAIN_DOMAINNAME", "DOMAIN_SERIAL", "DOMAIN_REFRESH", "DOMAIN_RETRY")) {
// do something (rest of list omitted to avoid scrolling)
}
by providing a helper function to turn the list into an object:
function list() {
var o={}, i;
for (i=0; i < arguments.length; i++) o[arguments[i]] = true;
return o;
}
Of course you can omit the helper function and just use an object literal, but that's ugly:
if (a in {"MAIN_DOMAINNAME":1, "DOMAIN_SERIAL":1, "DOMAIN_REFRESH":1}) {

jQuery support ":invalid" selector

I get the following console message:
[16:04:01.292] Error: Syntax error, unrecognized expression: unsupported pseudo: invalid # http://localhost:8080/assets/js/jquery-1.9.1.min.js:4
When I try something like:
if( $(e.target).is(':invalid') ){ ... }
How do I fix this?
Here's an example: http://jsfiddle.net/L4g99/ - try changing the jQuery version (stops working after 1.9)
Using querySelectorAll as suggested by #JanDvorak (and his answer should be accepted for thinking of that), you can write your own expression, making .is(':invalid') valid ?
jQuery.extend(jQuery.expr[':'], {
invalid : function(elem, index, match){
var invalids = document.querySelectorAll(':invalid'),
result = false,
len = invalids.length;
if (len) {
for (var i=0; i<len; i++) {
if (elem === invalids[i]) {
result = true;
break;
}
}
}
return result;
}
});
now you can do :
if( $(e.target).is(':invalid') ){ ... }
FIDDLE
:invalid is, indeed, not a valid jQuery selector (pseudoclass).
According to the link you posted, however, it is a valid CSS selector (not supported in IE<10).
A fiddle by Adeneo shows that, as suspected, while it doesn't work in jQuery, it can be used via the native querySelector/querySelectorAll methods. So, while this doesn't work:
if($(e.target).is(":invalid")) //SyntaxError
This does (except in IE<10):
if(~[].indexOf.call(document.querySelectorAll(":invalid"),e.target))
This should work as well (in the future or after the neccessary shimming; see caniuse):
if(e.target.matches(":invalid"))
You can use element's validity attribute (see MDN).
Now combining it with #adeneo's idea:
jQuery.extend(jQuery.expr[':'], {
invalid : function(elem, index, match){
return elem.validity !== undefined && elem.validity.valid === false;
},
valid : function(elem, index, match){
return elem.validity !== undefined && elem.validity.valid === true;
}
});

can you use jquery to see if a target contains a <b> tag?

so, i have something like this.
var $list = $("div#item");
I was looking at :contains in the selector, but i wasnt sure if that applied to markup or if i should do something like:
if($list.find("<b>"))return 1;
else return 0;
Reasoning: Adding functionality to a program which uses inline tags, and want to maintain structure.
Goal: if(item contains an inline b, u, i tags) return 1; else return 0;
You can simplify it down to a single selector .find("b,i,u") and return the boolean comparison length > 0. If any of the tags <b><i><u> are found inside #item, the overall length will be > 0:
return $("#item").find("b,i,u").length > 0;
Proof of concept
Edit: If you really want a number zero or one back instead of the boolean, use a ternary:
return $("#item").find("b,i,u").length > 0 ? 1 : 0;
return document.querySelector("#item b, #item u, #item i") ? 1 : 0;
No need for jQuery.
If you need to support browsers IE7 and older, try this:
var elem = document.getElementById('item');
return elem.getElementsByTagName('b').length
+ elem.getElementsByTagName('i').length
+ elem.getElementsByTagName('u').length == 0 ? 0 : 1;
perhaps use the .has() method.
$('li').has('ul')
jquery has
you can also do that with .has() function
I'm not sure it's the most efficient, but I would use .find for this.
function hasInline(targetElement) {
return ($(targetElement).find('b,u,i').length > 0);
}
I'd also recommend expanding the function so you could specify whatever inline tags you wanted to check, like so:
// NOTE: This will return true if the element has ANY of the tags provided.
function hasInlineTags(targetElement, listOfTags) {
return ($(targetElement).find(listOfTags.join(',')).length > 0);
}
// Call it with whatever tags you want.
hasInlineTags($("div#item"), ['b','u','i']);
if you're using jQuery:
var styleElements = $('b,u,i', $list)
Use:
return (styleElements.length) ? 1 : 0;

JavaScript/jQuery equivalent of LINQ Any()

Is there an equivalent of IEnumerable.Any(Predicate<T>) in JavaScript or jQuery?
I am validating a list of items, and want to break early if error is detected. I could do it using $.each, but I need to use an external flag to see if the item was actually found:
var found = false;
$.each(array, function(i) {
if (notValid(array[i])) {
found = true;
}
return !found;
});
What would be a better way? I don't like using plain for with JavaScript arrays because it iterates over all of its members, not just values.
These days you could actually use Array.prototype.some (specced in ES5) to get the same effect:
array.some(function(item) {
return notValid(item);
});
You could use variant of jQuery is function which accepts a predicate:
$(array).is(function(index) {
return notValid(this);
});
Xion's answer is correct. To expand upon his answer:
jQuery's .is(function) has the same behavior as .NET's IEnumerable.Any(Predicate<T>).
From http://docs.jquery.com/is:
Checks the current selection against an expression and returns true, if at least one element of the selection fits the given expression.
You should use an ordinary for loop (not for ... in), which will only loop through array elements.
You might use array.filter (IE 9+ see link below for more detail)
[].filter(function(){ return true|false ;}).length > 0;
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
I would suggest that you try the JavaScript for in loop. However, be aware that the syntax is quite different than what you get with a .net IEnumerable. Here is a small illustrative code sample.
var names = ['Alice','Bob','Charlie','David'];
for (x in names)
{
var name = names[x];
alert('Hello, ' + name);
}
var cards = { HoleCard: 'Ace of Spades', VisibleCard='Five of Hearts' };
for (x in cards)
{
var position = x;
var card = card[x];
alert('I have a card: ' + position + ': ' + card);
}
I suggest you to use the $.grep() method. It's very close to IEnumerable.Any(Predicate<T>):
$.grep(array, function(n, i) {
return (n == 5);
});
Here a working sample to you: http://jsfiddle.net/ErickPetru/BYjcu/.
2021 Update
This answer was posted more than 10 years ago, so it's important to highlight that:
When it was published, it was a solution that made total sense, since there was nothing native to JavaScript to solve this problem with a single function call at that time;
The original question has the jQuery tag, so a jQuery-based answer is not only expected, it's a must. Down voting because of that doesn't makes sense at all.
JavaScript world evolved a lot since then, so if you aren't stuck with jQuery, please use a more updated solution! This one is here for historical purposes, and to be kept as reference for old needs that maybe someone still find useful when working with legacy code.
Necromancing.
If you cannot use array.some, you can create your own function in TypeScript:
interface selectorCallback_t<TSource>
{
(item: TSource): boolean;
}
function Any<TSource>(source: TSource[], predicate: selectorCallback_t<TSource> )
{
if (source == null)
throw new Error("ArgumentNullException: source");
if (predicate == null)
throw new Error("ArgumentNullException: predicate");
for (let i = 0; i < source.length; ++i)
{
if (predicate(source[i]))
return true;
}
return false;
} // End Function Any
Which transpiles down to
function Any(source, predicate)
{
if (source == null)
throw new Error("ArgumentNullException: source");
if (predicate == null)
throw new Error("ArgumentNullException: predicate");
for (var i = 0; i < source.length; ++i)
{
if (predicate(source[i]))
return true;
}
return false;
}
Usage:
var names = ['Alice','Bob','Charlie','David'];
Any(names, x => x === 'Alice');

Categories