Javascript Delete Method? - javascript

In this code snippet from AdvancED DOM Scripting:
The call to delete(classes[i]); is this an array or object method? I'm unable to Google an answer.
/**
* remove a class from an element
*/
function removeClassName(element, className) {
if(!(element = $(element))) return false;
var classes = getClassNames(element);
var length = classes.length
//loop through the array in reverse, deleting matching items
// You loop in reverse as you're deleting items from
// the array which will shorten it.
for (var i = length-1; i >= 0; i--) {
if (classes[i] === className) { delete(classes[i]); }
}
element.className = classes.join(' ');
return (length == classes.length ? false : true);
};
window['ADS']['removeClassName'] = removeClassName;

The Mozilla Reference Docs says the following regarding the delete operator:
The delete operator deletes an object, an object's property, or an element at a specified index in an array.
For more information, see the following article:
http://perfectionkills.com/understanding-delete/

delete will set the value of the specified member (variable/array/object) to undefined
array/object example...
since classes[i] is actually referencing the i index of the array. It will set that specific index position to undefined, reserving the position in the array...

I think you can use simply $('p').removeClass('myClass yourClass') with jquery and put together a function to do so for any element

Related

Using parent() in a for loop

I am creating a chrome extension that blocks all porn results on all torrent search engine sites.
So I am trying to retrieve the name of the torrents and check them against the array of strings containing blocked (adult/porn) words that I created. If it matches the array word then it should set the display of the parent element to none. But parent() from jQuery doesn't seem to work around this in a for loop. This is the code that I am using.
// 'blockedWords' is the array.
// '$("dl dt")' contains the words that I am checking against strings from
// the array 'blockedWords'.
for (var i = 0; i < $("dl dt").length; i++) {
for (var j = 0; j < blockedWords.length; j++) {
if($("dl dt")[i].innerText.indexOf(blockedWords[j]) > -1){
$(this).parent().style.display= "none"; // 1st Method or
$("dl dt")[i].parent().style.display= "none"; // 2nd Method
}
}
}
// 1st Method shows the error 'Cannot set property 'display' of undefined'
// 2nd Method shows the error '$(...)[i].parent is not a function'
// '$("dl dt")[i].parent().style.display' doesn't work but
// '$("dl dt").parent().style.display' doesn't work either
// '$("dl dt")[i].style.display' works perfectly without parent().
I have also tried 'parents()'.
Any help will be appreciated :).
As a newbie, I am also open to any other suggestions or recommendations.
And I would be really grateful if you could explain your code as well :)
And by the way, can you believe there are more than 500 porn companies out there :o :P :D
Since you have jQuery, you can avoid using nested for-loops using jQuery's filter() and JavaScript reduce(s,v):
// Filter function removes elements that return a false/falsey value like 0
$("dl dt").filter(function() {
// Save current element's innerText so we can use it within the reduce function
var str = $(this).text();
// Return sum of reduce function
return blockedWords.reduce(function(s, v) {
// For each item in blockedWords array, check whether it exists in the string. Add to total number of matches.
return s + !!~str.indexOf(v);
}, 0); // 0 = intial value of reduce function (number of matches)
}).parent().hide(); // Hide elements which pass through the filter function
Demo:
var blockedWords = [
'shit', 'fuck', 'sex'
];
$("dl dt").filter(function() {
var str = $(this).text();
return blockedWords.reduce(function(s, v) {
return s + !!~str.indexOf(v);
}, 0);
}).parent().hide();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<dl><dt>this is shit</dt></dl>
<dl><dt>this is okay</dt></dl>
<dl><dt>fuck this</dt></dl>
<dl><dt>no problem</dt></dl>
<dl><dt>sex videos</dt></dl>
EDIT: I apologize for the earlier answer if you saw it, as it was incomplete. I have also added a snippet for demonstration purposes. For further explanation of the reduce algorithm, check this answer out (basically it converts the value of indexOf to either a 0 or 1, because indexOf returns -1 if not found, or another 0-indexed integer of the position if found).
JQuery's parent function returns a JQuery object with the parent element inside of it. If you want to access the element from this object you need to retrieve the element from the object using the bracket notation.
If you were to provide some HTML I would be able to test this and make sure it works, but here is some code that could get you pointed in the right direction to use mostly JQuery instead of relying on for loops with JavaScript.
JQuery Rewrite
$("dl dt").each(function(index, element){
if($.inArray(blockedWords,$(element).text()) > -1) {
$(this).parent().css("display", "block");
$(element).parent().css("display", "block");
}
})
The Answer To Your Specific Question
Change this:
$(this).parent().style.display= "none"; // 1st Method or
$("dl dt")[i].parent().style.display= "none"; // 2nd Method
to this:
$(this).parent()[0].style.display= "none"; // 1st Method or
$($("dl dt")[i]).parent()[0].style.display= "none"; // 2nd Method
optionally, you can instead use JQuery's css function like this:
$(this).parent().css("display", "none"); // 1st Method or
$($("dl dt")[i]).parent().css("display","none"); // 2nd Method

Javascript TypeError: Cannot read property 'indexOf' of undefined

In this code I want to remove an element from the cart_products array.
var cart_products = ["17^1", "19^1", "18^1"];
var product = 17;
$.each(cart_products,function(key, item) {
if(item.indexOf(product+"^") !== -1){
cart_products.splice(key, 1);
}
});
But I get this error in Google Chrome console:
Uncaught TypeError: Cannot read property 'indexOf' of undefined
Is there something wrong with the code?
Thanks for your help.
The problem is that you're modifying the array while jQuery's $.each is looping over it, so by the time it gets to the end, the entry that used to be at index 2 is no longer there. (I admit I'm a bit surprised $.each behaves that way, but I haven't used $.each in at least five years, so...)
If the goal is to remove matches from the array, the better choice is filter:
var cart_products = ["17^1", "19^1", "18^1"];
var product = 17;
cart_products = cart_products.filter(function(item) {
return item.indexOf(product+"^") === -1;
});
console.log(cart_products);
...or alternately if it's important to modify the array in-place rather than creating a new one use a boring for loop as Andreas points out looping backward through the array so it doesn't matter when you remove things:
var cart_products = ["17^1", "19^1", "18^1"];
var product = 17;
var target = product + "^";
for (var index = cart_products.length - 1; index >= 0; --index) {
if (cart_products[index].indexOf(target) !== -1) {
cart_products.splice(index, 1);
}
}
console.log(cart_products);
First of all, you don't need to use a jQuery each for this. Second, it's not a great idea to alter an array that you are operating on. If you're trying to remove elements from an array, use filter. Filter has the following signature:
someArray.filter(function(item, index, array) {
// return a value that is truthy to keep an item or falsey to remove it
})
Filter returns a new array with only the values that match what you want. That means you don't mess with your original array, which is a good idea anyways. In your case it would look like this:
var filteredProducst = cart_products.filter(function(item) {
return item.indexOf(product + "^")
})

Removing Multiple Objects from Javascript Array Breaks Half Way Through

I have an Array of a few hundred JSON Objects...
var self.collection = [Object, Object, Object, Object, Object, Object…]
Each one looks like this...
0: Object
id: "25093712"
name: "John Haberstich"
I'm iterating through the Array searching each Array.id to see if it matches any ids in a second Array...
var fbContactIDs = ["1072980313", "2502342", "2509374", "2524864", "2531941"]
$.each(self.collection, function(index, k) {
if (fbContactIDs.indexOf(k.id) > -1) {
self.collection.splice(index, 1);
};
});
However this code only works to splice three of the Objects from the self.collection array and then it breaks and gives the following error:
Uncaught TypeError: Cannot read property 'id' of undefined
The line that is causing the error is this one...
if (fbContactIDs.indexOf(k.id) > -1) {
Could anyone tell me what I'm dong wrong here?
Because the length of collection will change, the trick is to loop from rear to front
for (var index = self.collection.length - 1; index >= 0; index--) {
k = self.collection[index];
if (fbContactIDs.indexOf(k.id) > -1) {
self.collection.splice(index, 1);
};
}
You should not change the length of an array while iterating over it.
What you're trying to do is filtering and there's a specific function for that. For example:
[1,2,3,4,5,6,7,8,9,10].filter(function(x){ return (x&1) == 0; })
will return only even numbers.
In your case the solution could then simply be:
self.collection = self.collection.filter(function(k){
return fbContactIDs.indexOf(k.id) > -1;
});
or, if others are keeping a reference to self.collection and you need to mutate it inplace:
self.collection.splice(0, self.collection.length,
self.collection.filter(function(k){
return fbContactIDs.indexOf(k.id) > -1;
}));
If for some reason you like to process elements one at a time instead of using filter and you need to do this inplace a simple approach is the read-write one:
var wp = 0; // Write ptr
for (var rp=0; rp<L.length; rp++) {
if (... i want to keep L[x] ...) {
L[wp++] = L[rp];
}
}
L.splice(wp);
removing elements from an array one at a time is an O(n**2) operation (because for each element you remove also all the following ones must be slided down a place), the read-write approach is instead O(n).

Is it possible to get element's numerical index in its parent node without looping?

Normally I'm doing it this way:
for(i=0;i<elem.parentNode.length;i++) {
if (elem.parentNode[i] == elem) //.... etc.. etc...
}
function getChildIndex(node) {
return Array.prototype.indexOf.call(node.parentNode.childNodes, node);
}
This seems to work in Opera 11, Firefox 4, Chromium 10. Other browsers untested. It will throw TypeError if node has no parent (add a check for node.parentNode !== undefined if you care about that case).
Of course, Array.prototype.indexOf does still loop, just within the function call. It's impossible to do this without looping.
Note: If you want to obtain the index of a child Element, you can modify the function above by changing childNodes to children.
function getChildElementIndex(node) {
return Array.prototype.indexOf.call(node.parentNode.children, node);
}
Option #1
You can use the Array.from() method to convert an HTMLCollection of elements to an array. From there, you can use the native .indexOf() method in order to get the index:
function getElementIndex (element) {
return Array.from(element.parentNode.children).indexOf(element);
}
If you want the node index (as oppose to the element's index), then replace the children property with the childNodes property:
function getNodeIndex (element) {
return Array.from(element.parentNode.childNodes).indexOf(element);
}
Option #2
You can use the .call() method to invoke the array type's native .indexOf() method. This is how the .index() method is implemented in jQuery if you look at the source code.
function getElementIndex(element) {
return [].indexOf.call(element.parentNode.children, element);
}
Likewise, using the childNodes property in place of the children property:
function getNodeIndex (element) {
return [].indexOf.call(element.parentNode.childNodes, element);
}
Option #3
You can also use the spread operator:
function getElementIndex (element) {
return [...element.parentNode.children].indexOf(element);
}
function getNodeIndex (element) {
return [...element.parentNode.childNodes].indexOf(element);
}
You could count siblings...
The childNodes list includes text and element nodes-
function whichChild(elem){
var i= 0;
while((elem=elem.previousSibling)!=null) ++i;
return i;
}
There is no way to get the index of a node within its parent without looping in some manner, be that a for-loop, an Array method like indexOf or forEach, or something else. An index-of operation in the DOM is linear-time, not constant-time.
More generally, if list mutations are possible (and the DOM certainly supports mutation), it's generally impossible to provide an index-of operation that runs in constant time. There are two common implementation tactics: linked lists (usually doubly) and arrays. Finding an index using a linked list requires a walk. Finding an index using an array requires a scan. Some engines will cache indexes to reduce time needed to compute node.childNodes[i], but this won't help you if you're searching for a node. Not asking the question is the best policy.
I think you've got it, but:
make sure that variable "i" is declared with var
use === instead of == in the comparison
If you have a collection input elements with the same name (like <textarea name="text_field[]"…) in your form and you want to get the exact numeric index of the field that triggered an event:
function getElementIdxFromName(elem, parent) {
var elms = parent[elem.name];
var i = 0;
if (elms.length === undefined) // there is only one element with this name in the document
return 0;
while((elem!=elms[i])) i++;
return i;
}
Getting numeric id of an element from a collection of elements with the same class name:
function getElementIdxFromClass(elem, cl) {
var elems = document.getElementsByClassName(cl);
var i = 0;
if (elems.length > 0) {
while((elem!=elems[i])) i++;
return i;
}
return 0;
}
Try this:
let element = document.getElementById("your-element-id");
let indexInParent = Array.prototype.slice.call(element.parentNode.parentNode.children).indexOf(element.parentNode));

Call a function if a string contains any items in an array

How can I call a JavaScript function if a string contains any of the items in an array?
Yes, I can use jQuery :)
You could use the grep function to find if there are any elements that satisfy the condition:
// get all elements that satisfy the condition
var elements = $.grep(someArray, function(el, index) {
// This assumes that you have an array of strings
// Test if someString contains the current element of the array
return someString.indexOf(el) > -1;
});
if (elements.length > 0) {
callSomeFunction();
}
You could use some(), a Mozilla extension which has been added to ECMAScript 5:
var haystack = 'I like eggs!';
if(['spam', 'eggs'].some(function(needle) {
return haystack.indexOf(needle) >= 0;
})) alert('spam or eggs');
Simply loop over the items in the array and look for the value. That's what you have to do anyway even if you use some method to do it for you. By looping yourself you can easily break out of the loop as soon as you find a match, that will by average cut the number of items you need to check in half.
for (var i=0; i<theArray.length; i++) {
if (theArray[i] == theString) {
theFunction();
break;
}
}

Categories