jquery exclude array elements - javascript

I have an array of elements which I want to maintain efficiently, adding and removing arrays of elements over time.
var myElements = $('.initial');
jquery's merge() seems perfect for adding items as it doesn't create a new array and just adds to the existing one:
$.merge(myElements, $('.to-add'));
Is there an equivalent for removing, that also modifies the array in-place? Something like:
$.exclude(myElements, $('.to-remove'));
I do actually have arrays of DOM elements, and the selectors are just used as examples.

Assuming that you're after the relative complement of b in a.
And you don't want to create additional objects while process.
The function is for both plain Array and jQuery set.
(thus used $.each, $.inArray instead of Array.prototype.forEach Array.prototype.indexOf)
I wrote a function that fits your requirement.
$.exclude = function(a,b) {
var idx;
$.each(b, function(i, val) {
while((idx = $.inArray(val, a)) !== -1) {
a.splice(idx, 1);
}
})
return a;
}
test this code here
https://jsfiddle.net/happyhj/uwd4L1dm/8/
and you can use like this.
$.exclude(myElements, $('.to-remove'));

use jquery not method,
var filtered = $(myElements).not($('.to-remove'));

You can use delete to remove an element from an array and then use $.grep to remove the empty space.
//[0] since $("#id") will be a jquery Object
//[0] will return the particular DOM element
var orgArray = [$("#merge1")[0],$("#merge2")[0],$("#merge3")[0]];
var secArray = [$("#merge4")[0],$("#merge5")[0]]
// Will merge other two values;
// jQuery merge will merge contents of
//two array into first array
var merArray = $.merge(secArray, orgArray);
// Want to remove $("#merge2");
var getIndex = merArray.indexOf($("#merge2")[0]);
if(getIndex >-1){
delete merArray[getIndex]
}
// length before filtering
$("#l1").text(merArray.length);
//Now will remove Empty Space
merArray = $.grep(merArray,function(n){
return n==0 || n
});
$("#l2").text(merArray.length);
JSFIDDLE

You are using methods that are meant for array literals. jQuery already has method add() which will return a modified jQuery object that includes the elements matching the selector
var myElements = $('.initial');
var newCollection = myElements.add('.to-add');
newCollection.not('.to-remove').doSomething();
Don't think of jQuery objects as arrays although they are array like.
Reference add()
It's not clear what your overall objective really is but most likely you can manage it with any number of filtering methods that already exist within the api

Related

add and remove specific array elements using array.splice()

Is it possible to add to a specific part of an array, and then deleting a specific part of the array, in this case the end value using arr.splice()?
i currently do this like so:
var arr = [1,2,3,4,5,6,7,8,9];
arr.splice(0,0,"test");
which should return:
"test",1,2,3,4,5,6,7,8,9
i then do:
arr.pop();
which should return:
"test",1,2,3,4,5,6,7,8
I was wondering if it's possible to do this via the arr.splice() method or if there is any cleaner method to do the same, as potentially i'll be doing this a few times, so i would end up with something like:
arr.splice(0,0,"test");
arr.pop();
arr.splice(1,0,"test2");
arr.pop();
looking at the array.splice documentation it suggests i can only delete the element in the position i'm putting the new element into, not a different one.
In answer to my original question as confirmed in the comments. It is not possible to provide a separate index to insert and another to remove in an array using the splice method or potentially any other single statement in javascript. The best approach to try to achieve this in a single statement if i really needed it would be to create your own function, which really seems counter productive for the most part.
You can use Array.from() to set the .length and values of specific indexes of an array in a single call
var arr = [1,2,3,4,5,6,7,8,9];
arr = Array.from({length:arr.length - 1, ...arr, 0:"test"});
console.log(arr);
To achieve the pattern described at Question you can alternatively use a loop and Object.assign()
var arr = [1,2,3,4,5,6,7,8,9];
var n = 0;
var prop = "test";
while (arr.length > 1) {
Object.assign(arr, {length:arr.length -1,...arr, [n]:!n ? prop : prop+n});
++n;
console.log(arr);
}

How to efficiently remove the duplicate valued object from an array?

To simplify my question, suppose the objects are jqlite objects, using the angular.equals function, I can check whether they are equal. My question is: How do we use this function to remove duplicate item from an array of jqLite objects?
Here is what I tried:
// Suppose jqArr is the array stated above:
var result = [];
angular.forEach(jqArr, function(v_i){
if(result.length === 0){
result.push(v_i);
} else {
var isPushed = false;
angular.forEach(result, function(v_j){
if(angualr.equals(v_i, v_j)){
isPushed = true;
}
});
if(isPushed === false){
result.push(v_i);
}
}
})
console.log(result);
Suppose jqArr = [e_1, e_2, e_3, e_1, e_2], where e_i(s) are jQLite elements.
output should be:
[e_1, e_2, e_3]
*Please answer using only javascript and angularJs.
You can use ES6 Set like so:
let arr = [1,1,2,2,2,3,4,5,6,6,6,6,6];
let uniq = [...new Set(arr)];
The uniq array will contain unique values. If the aray is filled with object references, it will naturally work too.
In a more abstract form, you are performing an O(n^2) algorithm (same with indexOf and Set) but you can reduce the complexity to O(nlogn) by adding all the elements to the list without checks, after all the elements have been collected remove the duplicates be sorting (needs only one pass over the array to remove duplicates after sort).
This solution works only if you can store all the duplicates, for a "duplication factor" above 100% this is not efficient.
If you cannot perform a logic sort, hash function can give the same result.

why document.getElementsByClassName("className") returns object

I have a some dom objects that are selected with :
var elems = document.getElementsByClassName("royal") ;
and also another objects
var collapsedElems = document.getElementsByClassName("collapsed");
my problem occured when i tried to concat elems and collapsedElems with array concat() method
elems.concat(collapsedElems)
but the return type of getElementsByClassName() is not array actually it is
object. I checked it at chrome console with typeof operator. that seems weird to me how can i combine this two group of object. ?
getElementsByClassName() returns an HTMLcollection object which is similar to an array but not really an array so you can't call array methods using the returned value.
One hack is to use Array's prorotype methods along with .call()/.apply() to pass the returned object as the context.
var elems = document.getElementsByClassName("royal") ;
var collapsedElems = document.getElementsByClassName("collapsed");
var earray = Array.prototype.slice.call(elems, 0);
var concatenated = earray.concat.apply(earray, collapsedElems) ;
console.log(concatenated)
Demo: Fiddle
It returns an HTML Collection which does things that arrays do not (such as getting live updates when the DOM changes).
If you want to get an array with elements from both collections in it, then you could:
Create an array and then populate it by looping over each of the collections and pushing each member into it (which will give you an array) or
Use document.querySelectorAll(".royal, .collapsed"); (gets a NodeList)
From the MDN:
Returns an array-like object of all child elements which have all of
the given class names. When called on the document object, the complete
document is searched, including the root node. You may also call
getElementsByClassName() on any element; it will return only elements
which are descendants of the specified root element with the given
class names.
You can try this:
function getElementsByClassName(className)
{
if (document.getElementsByClassName)
{
return document.getElementsByClassName(className);
}
else
{
return document.querySelectorAll('.' + className);
}
}

call a function with a specific index value of nodelist

Is it possible to call a function on specific index value of nodelist which is storing div like following :
var txtElem = txtdiv.getElementsByTagName("div");
the thing i want is that i am storing list of divisions in txtElem nodelist now i want to call a function on click event of the 3rd div stored in nodelist. The divisions are created dynamically and they don't have any id so they are not accessible by id.
from what you asked, it seems like this will do:
function toPseudoArray(nodeList) {
var ar = [];
for(var i in nodeList)
if(nodeList[i].nextSibling) // or for that case any other way to find if this is an element
ar.push(nodeList[i]);
return ar;
}
Pass your nodeList to this function, use what it returns as an array that contains your elements, and only your elements.
By the way, you could directly call function on a specific element simply using my_fab_function(txtElem[0]); -- of course, until you don't exceed the count.
The question is quite unclear. Seeing the jQuery tag, these come to my mind:
A way to call a jQuery function on a specified index using .eq():
var n = 1; //the index you need
$(txtElem).eq(n).css('color', 'red');
Simple Javascript to get the DOM element:
var n = 1; //the index you need
var elem = txtElem[n]; //elem will hold the DOM element
//call simple DOM methods on it:
var s = elem.innerHTML;
//you can also call jQuery functions on it:
$(elem).css('color', 'red');
By the way txtElem is not an object, it is a NodeList, an "array-like object".

how to use $.makeArray() with jQuery

Can anyone explain me how to do this, jquery's api is really lacking on this. What is wrong in the following code?
var arr = $(value).filter(function() { return $(this).is("TD"); } ).html();
alert(arr[1]);
I just want to grab the innerHTML/text of the td and put it in an array
Using .map() with .get() is one way to go:
var arr = $(value).map(function() {
var $th = $(this);
if($th.is("TD")) return $th.html();
}).get();
alert(arr);
I'm not sure what value represents, but if you change the selector to match only td elements, you could simplify the return statement with return $(this).html();.
.map() iterates over the elements, and adds the return value to the jQuery object. .get() retrieves just the array out of the jQuery object.
http://api.jquery.com/map/
http://api.jquery.com/get/
Sounds like value is a tr. Then you could do this:
var arr = $(value).children('td').map(function() {
return $(this).html();
}).get();
alert(arr);
To create an array with each item containing an array of that row's td element's html, you could do this:
var arr = [];
$('tr').each(function() {
arr.push($(this).children('td').map(function() {
return $(this).html();
}));
}).get();
console.log(arr);
This uses the standard .push() since I don't think that using .map() inside .map() would work. I think when you pass the inner array into the jQuery object, it just adds it to the main array (or something).
The html() function, and similar functions like text() and width() return a scalar value for the first matched element.
If you want an array with the HTML contents of every matched element, you should call map(), like this:
var arr = $(value).children('td').map(function() { return $(this).html(); }).get();
alert(arr[0]); //Alerts HTML of first <td> element
The .html() function:
Description: Get the HTML contents of
the first element in the set of
matched elements.
This is true of many jQuery functions that are retrieving values. So what's happening is that your filter function is returning a set of jQuery elements, but your .html() function is causing arr to just be assigned the html from the first element in the set.

Categories