Finding value within javascript array - javascript

I'm trying to set up an IF statement if a value is contained within an array.
I've found some code which claimed to work but it doesn't seem to be.
var myAsi = ['01','02','24OR01','30De01','9thC01','A.Hu01','A01','AACAMSTE','ABBo01','ABBo02','ABC-01','ACCE01','Acce02','AceR01','h+dm01','Merr02','Ofak01','Wage01','Youn01'];
Array.prototype.find = function(searchStr) {
var returnArray = false;
for (i=0; i<this.length; i++) {
if (typeof(searchStr) == 'function') {
if (searchStr.test(this[i])) {
if (!returnArray) { returnArray = [] }
returnArray.push(i);
}
} else {
if (this[i]===searchStr) {
if (!returnArray) { returnArray = [] }
returnArray.push(i);
}
}
}
return returnArray;
}
var resultHtml = '';
resultHtml+='<table style ="width: 400px">';
resultHtml+='<tr colspan="2">';
resultHtml+='<td colspan="2">';
resultHtml+='<b><font color = "Red">(Client Code)</font><br><font color = "green">(Company Name)</font></b>';
resultHtml+='</td>';
resultHtml+='</tr>';
$.each(data, function(i,item){
resultHtml+='<div class="result">';
resultHtml+='<tr>';
if (notFound=myAsi.find("'"+item.code+"'") == false) {
resultHtml+='<td>';
}
else {
resultHtml+='<td bgcolor=#D8D8D8>';
}
resultHtml+='<font color = "red">'+item.code+'</font><br>';
resultHtml+='<font color = "green">'+item.content+'</font></td>';
resultHtml+='<td style ="width: 80px">Remove - ';
resultHtml+='Add';
resultHtml+='</td>';
resultHtml+='</tr>';
resultHtml+='</div>';
});
resultHtml+='</table>';
The item.code cycles through and I need an IF statement to tell me if it appears within the array.
Any help would be great.

If you only want to find if an item is in an array you could use a simpler function than that. For eg. the jQuery implementation:
// returns index of the element or -1 if element not present
function( elem, array ) {
if ( array.indexOf ) {
return array.indexOf( elem );
}
for ( var i = 0, length = array.length; i < length; i++ ) {
if ( array[ i ] === elem ) {
return i;
}
}
return -1;
},
This uses the native browser implementation of indexOf if available (all browsers except IE I think), otherwise a manual loop.

Try removing the apostrophes from your find() call. eg
notFound=myAsi.find(item.code)
Though actually, for your purposes see this example which uses this function....
Array.prototype.find = function(searchStr) {
for (var i=0; i<this.length; i++) {
if (this[i]==searchStr) return true;
};
return false;
};
And as an aside - Be very careful about using var before using a variable - otherwise you create a global variable (which you probably don't want). ie the line in your original function....
for (i=0; i<this.length; i++)
i is now global...

Array.prototype.contains = function(value, matcher) {
if (!matcher || typeof matcher !== 'function') {
matcher = function(item) {
return item == value;
}
}
for (var i = 0, len = this.length; i < len; i++) {
if (matcher(this[i])) {
return true;
}
}
return false;
};
This returns true for elements in the array that statisfy the conditions defined in matcher. Implement like this:
var arr = ['abc', 'def', 'ghi']; // the array
var valueToFind= 'xyz'; // a value to find in the array
// a function that compares an array item to match
var matcher = function(item) {
return item === matchThis;
};
// is the value found?
if (arr.contains(valueToFind, matcher)) {
// item found
} else {
// item not found
}
UPDATES:
Changed the contains method to take a value and an optional matcher function. If no matcher is included, it will do a simple equality check.
Test this on jsFiddle.net: http://jsfiddle.net/silkster/wgkru/3/

You could just use the builtin function
['a','b','c'].indexOf('d') == -1
This behavior was mandated in the javascript specification from over 6 years ago. Though I gave up on Internet Explorer for these reasons at around IE8, because of this incredibly poor support for standards. If you care about supporting very old browsers, you can use http://soledadpenades.com/2007/05/17/arrayindexof-in-internet-explorer/ to tack on your own custom Array.indexOf
I don't recall IE9 supporting [].indexOf, but Microsoft claims it does: http://msdn.microsoft.com/en-us/library/ff679977(v=VS.94).aspx

The standard way to determine the index of the first occurence of a given value in an array is the indexOf method of Array objects.
This code checks if it this method is supported, and implements it if not, so that it is available on any Array object:
if(Array.prototype.indexOf==null)
Array.prototype.indexOf = function(x){
for(var i=0, n=this.length; i<n; i++)if(this[i]===x)return i;
return -1;
};
Now myArray.indexOf(myValue) returns the first index of myValue in myArray, or -1 if not found.

Related

Split a String Array and Store Values for each Iteration

So the variable classList stores all classes for the body. I then created a variable classListLength that has the length of classList so I can iterate through each index and then split each class. I do not know how to store the splits for each index as it loops through classList. Help me please.
var classList = jQuery('body').attr('class').split(' ');
var classListLength = classList.length;
var keyWords = function(array) {
for (var i = 0; i < classListLength; i++ ) {
classList[i].split('-');
}
}
if i do the following in the console
var keyWords = function(array) {
for (var i = 0; i < classListLength; i++ ) {
console.log(classList[i].split('-'));
}
}
I can see exactly what I want but I want to be able to store that and check it later on with a conditional.
var splitClassList = classList.map(function (class) {
return class.split('-');
});
So I solved what I needed. The below code allows me to iterate through my split classList. I then check the the specific class I want within the classList using .includes method and execute what I need done. If you guys know how to make this a bit more modular please chime in.
var brandClass
// Iterate though split classes
jQuery.each( classList, function(i) {
if ( classList[i].includes('product-wildridge') ) {
brandClass = classList[i];
}
});
// check specific class for certin keywords
var customTab = function(brandClass) {
if (brandClass.includes('wildridge') && brandClass.includes('deep') ) {
return true;
} else {
jQuery('#tab-fabric').css('display', 'none');
}
}
customTab(brandClass);

How to write Javascript to search nodes - without getElementsByClassName

I'm very new at recursion, and have been tasked with writing getElementsByClassName in JavaScript without libraries or the DOM API.
There are two matching classes, one of which is in the body tag itself, the other is in a p tag.
The code I wrote isn't working, and there must be a better way to do this. Your insight would be greatly appreciated.
var elemByClass = function(className) {
var result = [];
var nodes = document.body; //<body> is a node w/className, it needs to check itself.
var childNodes = document.body.childNodes; //then there's a <p> w/className
var goFetchClass = function(nodes) {
for (var i = 0; i <= nodes; i++) { // check the parent
if (nodes.classList == className) {
result.push(i);
console.log(result);
}
for (var j = 0; j <= childNodes; j++) { // check the children
if (childNodes.classList == className) {
result.push(j);
console.log(result);
}
goFetchClass(nodes); // recursion for childNodes
}
goFetchClass(nodes); // recursion for nodes (body)
}
return result;
};
};
There are some errors, mostly logical, in your code, here's what it should have looked like
var elemByClass = function(className) {
var result = [];
var pattern = new RegExp("(^|\\s)" + className + "(\\s|$)");
(function goFetchClass(nodes) {
for (var i = 0; i < nodes.length; i++) {
if ( pattern.test(nodes[i].className) ) {
result.push(nodes[i]);
}
goFetchClass(nodes[i].children);
}
})([document.body]);
return result;
};
Note the use of a regex instead of classList, as it makes no sense to use classList which is IE10+ to polyfill getElementsByClassName
Firstly, you'd start with the body, and check it's className property.
Then you'd get the children, not the childNodes as the latter includes text-nodes and comments, which can't have classes.
To recursively call the function, you'd pass the children in, and do the same with them, check for a class, get the children of the children, and call the function again, until there are no more children.
Here are some reasons:
goFetchClass needs an initial call after you've defined it - for example, you need a return goFetchClass(nodes) statement at the end of elemByClass function
the line for (var i = 0; i <= nodes; i++) { will not enter the for loop - did you mean i <= nodes.length ?
nodes.classList will return an array of classNames, so a direct equality such as nodes.classList == className will not work. A contains method is better.
Lastly, you may want to reconsider having 2 for loops for the parent and children. Why not have 1 for loop and then call goFetchClass on the children? such as, goFetchClass(nodes[i])?
Hope this helps.

How can I make these two index-locating filters into one generic one?

I have two filters, findEdited and getUnitIndex. They both do exactly the same thing (find the index of an element in an array), but in different parts of an array. I would like to combine them into one filter, getIndex.
Here's the first one:
myApp.filter('findEdited', function(){
return function(food, foods) {
for (var index in foods) {
if (foods[index].uid == food.uid) {
return index;
}
}
return -1;
}
});
In the controller:
var index = $filter('findEdited')(food, $scope.editedFood);
And the second one:
myApp.filter('getUnitIndex', function () {
return function(list, item) {
for( var i = 0; i < list.length; i++ ) {
if( list[i].gram == item.gram ) {
return(i);
}
}
return(-1);
}
});
Controller:
var unitIndex = $filter('getUnitIndex')(food.unit, $scope.editedFood[index].unit.selected);
As near as I can tell, the only functional difference between them is the .uid & .gram identifier, which is telling the loop which part of the object to match. I've tried to rewrite these into one filter, like this, with ref standing in for this identifier:
myApp.filter('findIndex', function () {
return function(list, item, ref) {
for( var i = 0; i < list.length; i++ ) {
if( list[i].ref == item.ref ) {
return(i);
}
}
return(-1);
}
});
And called like this, if I want ref to be uid:
var unitIndex = $filter('findIndex')(food.unit, $scope.editedFood[index].unit.selected, 'uid');
This doesn't work. The example above returns 0 on every run. Any suggestions on how to pass the desired reference to this filter so that I can use it generically to find the index of any array item in any array?
Plunkr
Update
I can't get this to work for the filter "findEdited". I have written my generic filter like this:
myApp.filter('getIndex', function(){
return function(list, item, ref) {
for (var index in list) {
if (list[index][ref] == item[ref]) {
return index;
}
}
return -1;
}
});
Which works if call it like this, to find the index of a food unit by matching 'gram':
var unitIndex = $filter('getIndex')(food.unit, $scope.editedFood[index].unit.selected, 'gram');
But it doesn't work if I call it like this, to find out if a food unit exists in the array editedFood:
var foodIndex = $filter('getIndex')(food, $scope.editedFood, 'uid');
I can see that I am passing in different search objects & search contexts, but the foodIndex search works if I pass it to the almost-identical filter findEdited filter above. Any ideas why?
Here's an updated Plunkr.
You must use the array-like notation here (you can use it for objects as well). item.ref would mean the property called ref, while item[ref] will mean the property called whatever the expression in the [] evaluates to (in this case, whatever is stored in the variable called ref).
if( list[i][ref] == item[ref] ) {
In other words, writing item.ref is equivalent to writing item['ref'].

Find a value in an array of objects using Jquery

I have a array of objects say items. I want to find item having name xyz.
Currently, I wrote a for loop
for(var i = 0; i < items.length; i++)
{
if( items[i].name == "xyz" )
{
found = true;
break;
}
}
Is it possible to shorten this loop to one line statement using jquery? something like this:
$.find(items, "name", "xyz");
You might use
var matchingItems = items.filter(function(v){return v.name=="xyz"});
or using jQuery (for greater compatibility, as like many Array functions, filter or some aren't available on IE8) :
var matchingItems = $.grep(items, function(v){return v.name=="xyz"});
Something like:
$.grep(yourArray, function(n) {
return n.name == "xyz";
});
Use the native some method:
items.some(function(el) { return el.name == "xyz"; })
With jQuery, you would need to do something like $.grep and then check the length ($.grep(items, function(el){ return el.name=="xyz"; }).length > 1) - not an optimal solution. If you want to use a library solution for those browsers that don't support some (and don't want to use the polyfill), use Underscore's any.
var arr = ["abc", "xyz" ];
if($.inArray("abc",arr) > 0){
return true;
}
else
return false
​
this will return the index of "searching string"
if not found, it will return -1.
Use jQuerys inArray Example
http://api.jquery.com/jQuery.inArray/
might helps you
(function( $ ) {
$.find = function( array, property, key ) {
var found = false;
for(var i = 0; i < array.length; i++)
{
if( array[i][property] == key )
{
found = true;
break;
}
}
return found ? i : -1;
};
})( jQuery );
Usage: $.find(items, "name", "xyz");

javascript not removing undefined objects from array

I've got an in page text search using JS, which is here:
$.fn.eoTextSearch = function(pat) {
var out = []
var textNodes = function(n) {
if (!window['Node']) {
window.Node = new Object();
Node.ELEMENT_NODE = 1;
Node.ATTRIBUTE_NODE = 2;
Node.TEXT_NODE = 3;
Node.CDATA_SECTION_NODE = 4;
Node.ENTITY_REFERENCE_NODE = 5;
Node.ENTITY_NODE = 6;
Node.PROCESSING_INSTRUCTION_NODE = 7;
Node.COMMENT_NODE = 8;
Node.DOCUMENT_NODE = 9;
Node.DOCUMENT_TYPE_NODE = 10;
Node.DOCUMENT_FRAGMENT_NODE = 11;
Node.NOTATION_NODE = 12;
}
if (n.nodeType == Node.TEXT_NODE) {
var t = typeof pat == 'string' ?
n.nodeValue.indexOf(pat) != -1 :
pat.test(n.nodeValue);
if (t) {
out.push(n.parentNode)
}
}
else {
$.each(n.childNodes, function(a, b) {
textNodes(b)
})
}
}
this.each(function() {
textNodes(this)
})
return out
};
And I've got the ability to hide columns and rows in a table. When I submit a search and get the highlighted results, there would be in this case, the array length of the text nodes found would be 6, but there would only be 3 highlighted on the page. When you output the array to the console you get this:
So you get the 3 tags which I was expecting, but you see that the array is actually consisting of a [span,undefined,span,undefined,undefined,span]. Thus giving me the length of 6.
<span>
<span>
<span>
[span, undefined, span, undefined, undefined, span]
I don't know why it's not stripping out all of the undefined text nodes when I do the check for them. Here's what I've got for the function.
performTextSearch = function(currentObj){
if($.trim(currentObj.val()).length > 0){
var n = $("body").eoTextSearch($.trim(currentObj.val())),
recordTitle = "matches",
arrayRecheck = new Array(),
genericElemArray = new Array()
if(n.length == 1){
recordTitle = "match"
}
//check to see if we need to do a recount on the array length.
//if it's more than 0, then they're doing a compare and we need to strip out all of the text nodes that don't have a visible parent.
if($(".rows:checked").length > 0){
$.each(n,function(i,currElem){
if($(currElem).length != 0 && typeof currElem != 'undefined'){
if($(currElem).closest("tr").is(":visible") || $(currElem).is(":visible")){
//remove the element from the array
console.log(currElem)
arrayRecheck[i] = currElem
}
}
})
}
if(arrayRecheck.length > 0){
genericElemArray.push(arrayRecheck)
console.log(arrayRecheck)
}
else{
genericElemArray.push(n)
}
genericElemArray = genericElemArray[0]
$("#recordCount").text(genericElemArray.length + " " +recordTitle)
$(".searchResults").show()
for(var i = 0; i < genericElemArray.length; ++i){
void($(genericElemArray[i]).addClass("yellowBkgd").addClass("highLighted"))
}
}
else{
$(".highLighted").css("background","none")
}
}
If you look at the code below "//check to see if we need to do a recount on the array length. ", you'll see where I'm stripping out the text nodes based off of the display and whether or not the object is defined. I'm checking the length instead of undefined because the typeof == undefined wasn't working at all for some reason. Apparently, things are still slipping by though.
Any idea why I'm still getting undefined objects in the array?
My apologies for such a big post!
Thanks in advance
I've modified your eoTextSearch() function to remove dependencies on global variables in exchange for closures:
$.fn.extend({
// helper function
// recurses into a DOM object and calls a custom function for every descendant
eachDescendant: function (callback) {
for (var i=0, j=this.length; i<j; i++) {
callback.call(this[i]);
$.fn.eachDescendant.call(this[i].childNodes, callback);
}
return this;
},
// your text search function, revised
eoTextSearch: function () {
var text = document.createTextNode("test").textContent
? "textContent" : "innerText";
// the "matches" function uses an out param instead of a return value
var matches = function (pat, outArray) {
var isRe = typeof pat.test == "function";
return function() {
if (this.nodeType != 3) return; // ...text nodes only
if (isRe && pat.test(this[text]) || this[text].indexOf(pat) > -1) {
outArray.push(this.parentNode);
}
}
};
// this is the function that will *actually* become eoTextSearch()
return function (stringOrPattern) {
var result = $(); // start with an empty jQuery object
this.eachDescendant( matches(stringOrPattern, result) );
return result;
}
}() // <- instant calling is important here
});
And then you can do something like this:
$("body").eoTextSearch("foo").filter(function () {
return $(this).closest("tr").is(":visible");
});
To remove unwanted elements from the search result. No "recounting the array length" necessary. Or you use each() directly and decide within what to do.
I cannot entirely get my head around your code, but the most likely issue is that you are removing items from the array, but not shrinking the array afterwards. Simply removing items will return you "undefined", and will not collapse the array.
I would suggest that you do one of the following:
Copy the array to a new array, but only copying those items that are not undefined
Only use those array items that are not undefined.
I hope this is something of a help.
Found the answer in another post.
Remove empty elements from an array in Javascript
Ended up using the answer's second option and it worked alright.

Categories

Resources