I'm a noobie that has been learning by his own and messing around with javascript and I stumbled upon that nightmare called 'regular expressions'...I kinda know a little bit about them and I been doing fancy stuff, but I'm stuck and I'd like you clarify this to me:
I've been reading and looking for a way to create matches and I tripped on with great answer:
How to perform a real time search and filter on a HTML table
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
var $rows = $('#table tr');
$('#search').keyup(function() {
var val = '^(?=.*\\b' + $.trim($(this).val()).split(/\s+/).join('\\b)(?=.*\\b') + ').*$',
reg = RegExp(val, 'i'),
text;
$rows.show().filter(function() {
text = $(this).text().replace(/\s+/g, ' ');
return !reg.test(text);
}).hide();
});
http://jsfiddle.net/dfsq/7BUmG/1133/
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
I kinda understand what is going on there but could somebody break that down and 'translate it in javascript' for me so I can catch the idea better, I barely can do cool stuff with jquery since I'm still studying javascript, I know certain things about the jqueries but not enough to fully understand what he did there and enough about regular expressions to know that the guy who wrote taht code is a genius <3
this is what i understand and please correct me:
var $rows = $('#table tr');
it's the scope, the 'target' in which is gonna be looking for the match
pd:that's the first time I see the'$' to declare variables and for what I've looked it sets it as a jQuery object..it's that right?
var val = '^(?=.*\\b' + $.trim($(this).val()).split(/\s+/).join('\\b)(?=.*\\b') + ').*$',
reg = RegExp(val, 'i'),
text;
the '$.trim($(this).val()' is equal to $.trim($("#user_input").val()); .......right?
reg = RegExp(val, 'i')
the reg variable works as a constructor to find the match that will be case-insensitive, but shouldn't it be 'reg = new RegExp(val, 'i')' or I can set as it is as well?
here is when I get confused the most
$rows.show().filter(function() {
text = $(this).text().replace(/\s+/g, ' ');
return !reg.test(text);
}).hide();
what I can understand is that the matches will be shown only if they pass the filter set by the text variable and the ones who don't will be hidden, I haven't the slightest idea of what the $(this) is equivalent to....in the text variable.. and from there on I have no idea what's going on, I found that .test() returns true or false when it finds a match in the regexp object but why does it have the ! at the beginning?
$ is the jQuery object, it's just a variable name that points to jQuery. Don't worry about $rows, that's just another variable name.
var $rows = $('#table tr');
The right-hand side is basically passing a selector to jQuery and telling it to find all DOM elements that match it. If you know CSS this is the same principle, #table is an element with id="table" and combined with tr means select all rows (tr being the table row html tag) within that element.
In pure javascript this could be written as
var $rows = document.querySelectorAll("#table tr");
The result is a list of elements.
Then you find another element, and attach an event listener:
$('#search').keyup(function() { ... });
Notice this is passing another selector to jQuery, which returns the desired element, onto which you attach a keyup event. In JavaScript this might be:
document.getElementById("search").addEventListener("keyup", function() { ... });
When that keyup event is triggered on the element the function is executed, and you are building a string val which contains:
... + $.trim($(this).val()).split(/\s+/).join('\\b)(?=.*\\b') + ...
this in $(this).val() evaluates to the element which was found by the #search selector, in this case an input field.
This might be the following in pure javascript:
... + document.getElementById("search").value.trim().split(/\s+/).join('\\b)(?=.*\\b') + ...
If you evaluate that expression, it 1) trims whitespace, 2) splits the result into an array of strings on every whitespace character and 3) joins that array with the delimiter \\b)(?=.*\\b
Steps 2) and 3) are basically a String.replace(/\s+/, '\\b)(?=.*\\b') but quicker.
Moving onto the last bit, the jQuery show() method is applied to each element in $rows, which was that list of elements (table rows) found at the beginning. This makes every row visible.
Then the filter method is applied to that list, this is a loop through the list of elements calling the function defined within on each element. Notice, this within the filter function now refers to the table row being tested, not the search field.
If that filter function returns true on a list item that item remains in the resulting list, if false it is removed. Here that prepared RegExp is applied, and if it matches the function returns false. So after filtering you have a list of elements/rows which do not match, and finally .hide() is applied which is a jQuery method to hide all elements on which it is called. So you hide the rows that don't match.
The code may look something like this in "pure" javascript (it should work now, I fixed the problem cjsmith wrote about in the comments).
var $rows = document.querySelectorAll("#table tr");
document.getElementById("search").addEventListener("keyup", function(e) {
var val = '^(?=.*\\b' + e.target.value.trim().split(/\s+/).join('\\b)(?=.*\\b') + ').*$';
var reg = RegExp(val, 'i');
Array.prototype.forEach.call($rows, function(row) {
var text = row.textContent.replace(/\s+/g, ' ');
row.style.display = reg.test(text) ? 'table-row' : 'none';
});
});
PS. Happy New Year!
var $rows = $('#table tr');
it's the scope, the 'target' in which is gonna be looking for the
match
pd:that's the first time i see the'$' to declare variables and for
what I've looked it sets it as a jquery object..it's that right?
Yes, $rows is target, but the '$' of sign is actually meaningless, that is an approach of jquery programmers. It's good for remembering a jquery object, "hımmm, this has a '$' at the start, so that must be a jquery object".
In fact var $rows = $('#table tr'); and var rows = $('#table tr'); -> these are same, there aren't any differences between $rows and rows.
-----------------------------------------------------------------------------------------
var val = '^(?=.\b' +
$.trim($(this).val()).split(/\s+/).join('\b)(?=.\b') + ').*$',
reg = RegExp(val, 'i'),
text; the '$.trim($(this).val()' is equal to $.trim($("#user_input").val()); .......right?
In javascript this refers the event's owner. For the example that you shared, this used in keyup callback function of $('#search') so that means this refers the $("#search").
-----------------------------------------------------------------------------------------
reg = RegExp(val, 'i') the reg variable works as a constructor to find
the match that will be case-insensitive, but shouldn't it be 'reg =
new RegExp(val, 'i')' or I can set as it is as well?
There are nice explanations of new keyword for Javascript in this question, you can check it.
-----------------------------------------------------------------------------------------
$rows.show().filter(function() {
text = $(this).text().replace(/\s+/g, ' ');
return !reg.test(text);
}).hide();
Let's explain it step by step
var $rows = $('#table tr');
$rows is an array of tr objects
$rows.show() means show all tr tags which are in a table that's id is #table.
jQuery is chainable, that means $rows.show() returns $rows again
so $rows.show().filter() = $rows.filter
again $rows is still is an array of tr objects, so $rows.filter() loops through this object like a for loop, the callback function is processed for each objects in $rows.
In a callback function this refers the owner, in this example the owner is the object at that time while filter is looping the $rows.
As you said test() returns a bool value.
! is an inverter,
!true = false
!false = true
I'll have a go! Guten tag, nero!
I'll answer your questions from top to bottom and see if we can get it covered. First, you're understanding of the rows variable is correct. It's a jquery object that contains an array of DOM objects that match your search string. In this case, tr's within a table.
You've also got the #user_input part right. $(this) inside the keyup function is a reference to the DOM object that threw the event in the first place. In this case, the user input.
but shouldn't it be 'reg = new RegExp(val, 'i')' or I can set as it is as well?
Using the new keyword seems safer. For further refernce, see here: http://zeekat.nl/articles/constructors-considered-mildly-confusing.html. This may not be necessary if you're relying on just the 'static' bit of a class - but it's a better safe than sorry move I'd say.
Now for the hard part:
$rows.show().filter(function() {
text = $(this).text().replace(/\s+/g, ' ');
return !reg.test(text);
}).hide();
the $rows.show() is going to make visible all the DOM objects in the rows jquery object.
Then on that same set of objects it's going to 'filter' which means it's going to reduce the DOM objects that are in var rows based on a function that returns a boolean. In this case, that function is:
text = $(this).text().replace(/\s+/g, ' ');
return !reg.test(text);
which replaces all whitespace with a single space, and then tests if it matches your regular expression. So here, if it DOESN'T pass your regular expression (! = logical NOT) it stays in the set.
Lastly - this function will hide everything that passed the filter.
So it shows everything and then hides what doesn't match your regular expression.
Hope that helps! Habst ein guten neue Jahre (how's my German?)
Related
UPDATE: I am no longer specifically in need of the answer to this question - I was able to solve the (larger) problem I had in an entirely different way (see my comment). However, I'll check in occasionally, and if a viable answer arrives, I'll accept it. (It may take a week or three, though, as I'm only here sporadically.)
I have a string. It may or may not have HTML tags in it. So, it could be:
'This is my unspanned string'
or it could be:
'<span class="someclass">This is my spanned string</span>'
or:
'<span class="no-text"></span><span class="some-class"><span class="other-class">This is my spanned string</span></span>'
or:
'<span class="no-text"><span class="silly-example"></span></span><span class="some-class">This is my spanned string</span>'
I want to find the index of a substring, but only in the portion of the string that, if the string were turned into a DOM element, would be (a) TEXT node(s). In the example, only in the part of the string that has the plain text This is my string.
However, I need the location of the substring in the whole string, not only in the plain text portion.
So, if I'm searching for "span" in each of the strings above:
searching the first one will return 13 (0-based),
searching the second will skip the opening span tag in the string and return 35 for the string span in the word spanned
searching the third will skip the empty span tag and the openings of the two nested span tags, and return 91
searching the fourth will skip the nested span tags and the opening of the second span tag, and return 100
I don't want to remove any of the HTML tags, I just don't want them included in the search.
I'm aware that attempting to use regex is almost certainly a bad idea, probably even for simplistic strings as my code will be encountering, so please refrain from suggesting it.
I'm guessing I will need to use an HTML parser (something I've never done before). Is there one with which I can access the original parsed strings (or at least their lengths) for each node?
Might there be a simpler solution than that?
I did search around and wasn't been able to find anyone ask this particular question before, so if someone knows of something I missed, I apologize for faulty search skills.
The search could loop through the string char by char. If inside a tag, skip the tag, search the string only outside tags and remember partial match in case the text is matched partially then interrupted with another tag, continue the search outside the tag.
Here is a little function I came up with:
function customSearch(haysack,needle){
var start = 0;
var a = haysack.indexOf(needle,start);
var b = haysack.indexOf('<',start);
while(b < a && b != -1){
start = haysack.indexOf('>',b) + 1;
a = haysack.indexOf(needle,start);
b = haysack.indexOf('<',start);
}
return a;
}
It returns the results you expected based in your examples. Here is a JSFiddle where the results are logged in the console.
Let's start with your third example:
var desiredSubString = 'span';
var entireString = '<span class="no-text"></span><span class="some-class"><span class="other-class">This is my spanned string</span></span>';
Remove all HTML elements from entireString, above, to establish textString:
var textString = entireString.replace(/(data-([^"]+"[^"]+")/ig,"");
textString = textString.replace(/(<([^>]+)>)/ig,"");
You can then find the index of the start of the textString within the entireString:
var indexOfTextString = entireString.indexOf(textString);
Then you can find the index of the start of the substring you're looking for within the textString:
var indexOfSubStringWithinTextString = textString.indexOf(desiredSubString);
Finally you can add indexOfTextString and indexOfSubStringWithinTextString together:
var indexOfSubString = indexOfTextString + indexOfSubStringWithinTextString;
Putting it all together:
var entireString = '<span class="no-text"></span><span class="some-class"><span class="other-class">This is my spanned string</span></span>';
var desiredSubString = 'span';
var textString = entireString.replace(/(data-([^"]+"[^"]+")/ig,"");
textString = textString.replace(/(<([^>]+)>)/ig,"");
var indexOfTextString = entireString.indexOf(textString);
var indexOfSubStringWithinTextString = textString.indexOf(desiredSubString);
var indexOfSubString = indexOfTextString + indexOfSubStringWithinTextString;
You could use the browser's own HTML parser and XPath engine to search only inside the text nodes and do whatever processing you need.
Here's a partial solution:
var haystack = ' <span class="no-text"></span><span class="some-class"><span class="other-class">This is my spanned string</span></span>';
var needle = 'span';
var elt = document.createElement('elt');
elt.innerHTML = haystack;
var iter = document.evaluate('.//text()[contains(., "' + needle + '")]', elt).iterateNext();
if (iter) {
var position = iter.textContent.indexOf(needle);
var range = document.createRange();
range.setStart(iter, position);
range.setEnd(iter, position + needle.length);
// At this point, range points at the first occurence of `needle`
// in `haystack`. You can now delete it, replace it with something
// else, and so on, and after that, set your original string to the
// innerHTML of the document fragment representing the range.
console.log(range);
}
JSFiddle.
Info's: I have some javascript code that i will show below, who i'm having problem with quotes.
html = [];
style = 'class=odd';
html.push('<li '+style+' onclick=SelectItem("'+ele.id+'","'+idItem+'","'+dsItem+'","'+qtItem+'"); >'+id+' - '+$iObjItensListaVenda.result.ds_item[i]+'</li>');
I have strings that i get from a JSON Object, as you see above.
Problem: But when i'm trying to place it as a Function Parameter on the onClick event of the <li> element, my resulting html <li> element becomes totally unformatted like that:
<li natural,"150");="" white="" american="" onclick="SelectItem("descItem1","2",TELHA" class="odd">00002 - TELHA AMERICAN WHITE NATURAL</li>
What do i want: i need a solution like a function, maybe already exists in jQuery, to Quote my String. Like a QuoteStr("s t r i n g"); to become ""s t r i n g"".
Maybe you're complaining about:
The variable ele is a html <input> element.
The variable idItem contains only numbers, they come from a JSON Object.
The variable dsItem its a string containing Item Description, it comes from the JSON Object too.
The variable qtItem contains only numbers, it is the quantity of the items, it comes from the JSON too.
The sane solution would be to use jQuery to build the element and bind the event handler, not building an HTML string:
var $li = $('<li />', {
"class": "odd",
on: {
click: function() {
SelectItem(ele.id, idItem, dsItem, qtItem);
}
},
text: id + ' - ' + $iObjItensListaVenda.result.ds_item[i]
});
If you are doing this in a loop and the variables end up having the wrong values, please see JavaScript closure inside loops – simple practical example. Alternative you could use jQuery's .data API to set and get those values.
Try \" instead of ' in onClick
$(".container").append("Edit");
You can use quotes in a string by escaping them with a backslash.
var text = "s t r i n g";
"\"" + text + "\"" === "\"s t r i n g\"";
Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
You can always use backslash to escape quotes:
console.log('te\'st'); // te'st
console.log("te\"st"); // te"st
You can do the same thing for your string, but I'd suggest you rewrite the whole thing into something more usable. By that I mean not using strings to build objects, but building objects directly.
For example:
var li = document.createElement('li');
li.className = myClass;
li.onclick = function(){/*...*/};
It gets even easier with jQuery.
Here's what I have. A SharePoint 2010 custom view in a list web part. I have 6 categories and 4 sub-categories. Items do not have to have sub-category but do have to have a category.
The view shows the a blank sub-category witha number next to it. I'm trying to bind a click event to all of them but the ID increases on every page refresh. The base ID is titl[0-9]*[0-9]. Then there is another ID underneath that I want to check as well, it is titl[0-9]*_[0-9]1.
So I've tried using the regex selector for jQuery and it doesn't bind correctly. It finds the object but doesn't bind correctly.
I need it to bind to the id and then be able to trigger the onclick event of the next tbody which is the 1_. Then check if the text of it is " " and if so hide the tbody.
My code:
$(":regex(id,titl[0-9]*-[0-9]_) td a").bind('click', function(){
var parent = $(this);
var child = $(this).next("tbody");
var grandchild = $(this).next("tbody td a");
//alert(parent + " | " + child + " | " + grandchild ); //always return undefined??
// Everything below works if I can get the IDs correct for child and grandchild
if($(grandchild).css('display')!='none'){
$(grandchild).click();
if($(grandchild).text()==" "){
$(child).hide();
};
};
});
I'd strongly suggest you need to re-think your IDs - they should be consistent, really.
If you absolutely must work with a variable ID, you can use the "id" attribute in a selector as with any other attribute:
// Any element, ID starts with "titl"
$('[id^="titl"]')
To capture that and re-use it, I'd really suggest you're doing something wrong with your IDs. However, for completeness (although I can't stress enough how much you should try to avoid having to use this), something based on this should be a good (haha, yeah right) starting point
// Long-winded messy hideous foul code
var $title = $('[id^="titl"]'),
title = $title.length && $title.eq(0).attr('id');
if (title !== 0)
{
$('#' + title + ' #' + title + '1 td a').html('Ow.');
}
I'm not sure I get this, but you can target any ID starting with titl, and then filter based on the ID in many other ways inside the function:
$('[id^="titl["]').on('click', function() {
var check = this.id.charAt(10) == '_', //tenth character is underscore ?
parent = $(this),
child = $(this).next("tbody"),
grandchild = $(this).next("tbody td a");
if (check) {
//element matching second selectortype clicked
}else{
if (grandchild.is(':visible')){
grandchild.trigger('click');
if (grandchild.text()==" ") child.hide();
}
}
});
I agree about rethinking your ids if you have control over them. Even if you don't, the StartsWith selector will get you all of the higher level elements, and you can traverse to the lower level ones. Remember that chaining the selectors means that you can match on similar patterns in ids, not paying any attention to the actual values.
One other note: I've never needed to resort to a regex match with jQuery. The CSS3-like selectors are just far too powerful for that.
I'm making a highlighting plugin for a client to find things in a page and I decided to test it with a help viewer im still building but I'm having an issue that'll (probably) require some regex.
I do not want to parse HTML, and im totally open on how to do this differently, this just seems like the the best/right way.
http://oscargodson.com/labs/help-viewer
http://oscargodson.com/labs/help-viewer/js/jquery.jhighlight.js
Type something in the search... ok, refresh the page, now type, like, class or class=" or type <a you'll notice it'll search the actual HTML (as expected). How can I only search the text?
If i do .text() it'll vaporize all the HTML and what i get back will just be a big blob of text, but i still want the HTML so I dont lose formatting, links, images, etc. I want this to work like CMD/CTRL+F.
You'd use this plugin like:
$('article').jhighlight({find:'class'});
To remove them:
.jhighlight('remove')
==UPDATE==
While Mike Samuel's idea below does in fact work, it's a tad heavy for this plugin. It's mainly for a client looking to erase bad words and/or MS Word characters during a "publishing" process of a form. I'm looking for a more lightweight fix, any ideas?
You really don't want to use eval, mess with innerHTML or parse the markup "manually". The best way, in my opinion, is to deal with text nodes directly and keep a cache of the original html to erase the highlights. Quick rewrite, with comments:
(function($){
$.fn.jhighlight = function(opt) {
var options = $.extend($.fn.jhighlight.defaults, opt)
, txtProp = this[0].textContent ? 'textContent' : 'innerText';
if ($.trim(options.find.length) < 1) return this;
return this.each(function(){
var self = $(this);
// use a cache to clear the highlights
if (!self.data('htmlCache'))
self.data('htmlCache', self.html());
if(opt === 'remove'){
return self.html( self.data('htmlCache') );
}
// create Tree Walker
// https://developer.mozilla.org/en/DOM/treeWalker
var walker = document.createTreeWalker(
this, // walk only on target element
NodeFilter.SHOW_TEXT,
null,
false
);
var node
, matches
, flags = 'g' + (!options.caseSensitive ? 'i' : '')
, exp = new RegExp('('+options.find+')', flags) // capturing
, expSplit = new RegExp(options.find, flags) // no capturing
, highlights = [];
// walk this wayy
// and save matched nodes for later
while(node = walker.nextNode()){
if (matches = node.nodeValue.match(exp)){
highlights.push([node, matches]);
}
}
// must replace stuff after the walker is finished
// otherwise replacing a node will halt the walker
for(var nn=0,hln=highlights.length; nn<hln; nn++){
var node = highlights[nn][0]
, matches = highlights[nn][1]
, parts = node.nodeValue.split(expSplit) // split on matches
, frag = document.createDocumentFragment(); // temporary holder
// add text + highlighted parts in between
// like a .join() but with elements :)
for(var i=0,ln=parts.length; i<ln; i++){
// non-highlighted text
if (parts[i].length)
frag.appendChild(document.createTextNode(parts[i]));
// highlighted text
// skip last iteration
if (i < ln-1){
var h = document.createElement('span');
h.className = options.className;
h[txtProp] = matches[i];
frag.appendChild(h);
}
}
// replace the original text node
node.parentNode.replaceChild(frag, node);
};
});
};
$.fn.jhighlight.defaults = {
find:'',
className:'jhighlight',
color:'#FFF77B',
caseSensitive:false,
wrappingTag:'span'
};
})(jQuery);
If you're doing any manipulation on the page, you might want to replace the caching with another clean-up mechanism, not trivial though.
You can see the code working here: http://jsbin.com/anace5/2/
You also need to add display:block to your new html elements, the layout is broken on a few browsers.
In the javascript code prettifier, I had this problem. I wanted to search the text but preserve tags.
What I did was start with HTML, and decompose that into two bits.
The text content
Pairs of (index into text content where a tag occurs, the tag content)
So given
Lorem <b>ipsum</b>
I end up with
text = 'Lorem ipsum'
tags = [6, '<b>', 10, '</b>']
which allows me to search on the text, and then based on the result start and end indices, produce HTML including only the tags (and only balanced tags) in that range.
Have a look here: getElementsByTagName() equivalent for textNodes.
You can probably adapt one of the proposed solutions to your needs (i.e. iterate over all text nodes, replacing the words as you go - this won't work in cases such as <tag>wo</tag>rd but it's better than nothing, I guess).
I believe you could just do:
$('#article :not(:has(*))').jhighlight({find : 'class'});
Since it grabs all leaf nodes in the article it would require valid xhtml, that is, it would only match link in the following example:
<p>This is some paragraph content with a link</p>
DOM traversal / selector application could slow things down a bit so it might be good to do:
article_nodes = article_nodes || $('#article :not(:has(*))');
article_nodes.jhighlight({find : 'class'});
May be something like that could be helpful
>+[^<]*?(s(<[\s\S]*?>)?e(<[\s\S]*?>)?e)[^>]*?<+
The first part >+[^<]*? finds > of the last preceding tag
The third part [^>]*?<+ finds < of the first subsequent tag
In the middle we have (<[\s\S]*?>)? between characters of our search phrase (in this case - "see").
After regular expression searching you could use the result of the middle part to highlight search phrase for user.
I'm looking for a concise way to compare two arrays for any match.
I am using this comparison to apply a particular style to any table cell that has matching content. One array is a static list of content that should be contained in at least one table cell on the page. The other array is being generated by JQuery, and is the text of all table cells.
The reason why I have to compare content to apply style is that the HTML document will semantically change over time, is being generated by different versions of excel (pretty awful looking code), and this script needs to accommodate that. I know that the content I'm looking to apply the style to in this document will never change, so I need to detect all matches for this content to apply styles to them.
So, the code should be something like (in english):
for each table cell, compare cell text to contents of array. If there is any match, apply this css to the table cell.
This is what I have so far (and I know it's wrong):
$(document).ready(function(){
$("a.loader").click(function(event){
event.preventDefault();
var fileToLoad = $(this).attr("href");
var fileType = $(this).text();
var makes = new Array("ACURA","ALFA ROMEO","AMC","ASTON MARTIN","ASUNA","AUDI","BENTLEY","BMW","BRITISH LEYLAND","BUICK","CADILLAC","CHEVROLET","CHRYSLER","CITROEN","COLT","DACIA","DAEWOO","DELOREAN","DODGE","EAGLE","FERRARI","FIAT","FORD","GEO","GMC","HONDA","HUMMER","HYUNDAI","INFINITI","INNOCENTI","ISUZU","JAGUAR","JEEP","KIA","LADA","LAMBORGHINI","LANCIA","LAND ROVER","LEXUS","LINCOLN","LOTUS","M.G.B.","MASERATI","MAYBACH","MAZDA","MERCEDES BENZ","MERCURY","MG","MINI","MITSUBISHI","MORGAN","NISSAN (Datsun)","OLDSMOBILE","PASSPORT","PEUGEOT","PLYMOUTH","PONTIAC","PORSCHE","RANGE ROVER","RENAULT","ROLLS-ROYCE / BENTLEY","SAAB","SATURN","SCION","SHELBY","SKODA","SMART","SUBARU","SUZUKI","TOYOTA","TRIUMPH","VOLKSWAGEN","VOLVO","YUGO","Acura","Alfa Romeo","Amc","Aston Martin","Asuna","Audi","Bentley","Bmw","British Leyland","Buick","Cadillac","Chevrolet","Chrysler","Citroen","Colt","Dacia","Daewoo","Delorean","Dodge","Eagle","Ferrari","Fiat","Ford","Geo","Gmc","Honda","Hummer","Hyundai","Infiniti","Innocenti","Isuzu","Jaguar","Jeep","Kia","Lada","Lamborghini","Lancia","Land Rover","Lexus","Lincoln","Lotus","M.G.B.","Maserati","Maybach","Mazda","Mercedes Benz","Mercury","Mg","Mini","Mitsubishi","Morgan","Nissan (Datsun)","Oldsmobile","Passport","Peugeot","Plymouth","Pontiac","Porsche","Range Rover","Renault","Rolls-Royce / Bentley","Saab","Saturn","Scion","Shelby","Skoda","Smart","Subaru","Suzuki","Toyota","Triumph","Volkswagen","Volvo","Yugo");
$("div#carApp").html("<img src='images/loadingAnimation.gif' alt='LOADING...' />");
$("div#carApp").load(fileToLoad, function(){
$("#carApp style").children().remove();
$('#carApp td').removeAttr('style');
$('#carApp td').removeAttr('class');
$('#carApp table').removeAttr('class');
$('#carApp table').removeAttr('style');
$('#carApp table').removeAttr('width');
$('#carApp tr').removeAttr('style');
$('#carApp tr').removeAttr('class');
$('#carApp col').remove();
$('#carApp table').width('90%');
var content = $("#carApp table td");
jQuery.each(content, function() {
var textValue = $(this).text();
if (jQuery.inArray(textValue, makes)==true)
$(this).css("color","red");
});
});
});
});
Any ideas?
You're checking $.inArray(...) == true. inArray actually returns an integer with the index of the item in the array (otherwise -1.) So you want to check if it is greater than or equal to 0.
Here's how you can change your each loop.
$('#carApp td').each(function () {
var cell = $(this);
if ($.inArray(cell.text(), makes) >= 0) {
cell.addClass('selected-make');
}
});
I use a CSS class instead of the style attribute, because it's better practice to put styling in a CSS file rather than in your JavaScript code. Easier to update that way (especially when you want to apply the same style in multiple places in your code.)
Other points worth noting:
jQuery selections have the each(...) function as well. So you can do $(...).each(...) instead of jQuery.each($(...), ...)
jQuery and $ are the same object as long as you don't have other frameworks that redefine the $ variable. Therefore you can do $.inArray(...) instead of jQuery.inArray(...). It's a matter of taste, though.
Have you had a look at $.grep() ?
Finds the elements of an array which
satisfy a filter function. The
original array is not affected. The
filter function will be passed two
arguments: the current array item and
its index. The filter function must
return 'true' to include the item in
the result array.
An optimization would be to make makes a hash (aka dictionary):
var makes = { "ACURA": 1,"ALFA ROMEO": 1,"AMC": 1, ...};
Then you don't have to iterate makes every time with inArray.
...
var textValue = $(this).text();
if (makes[textValue] == 1)
$(this).css("color","red");
}
...