jQuery remove duplicate but keep last occurance - javascript

SO is full of these questions, I know, but after going through 20+ pages and numerous google searches I end up asking because I can't find the answer.
I want to filter through data attributes and keep the last occurrence. So for instance with this code:
<div data-id="001">Hello</div>
<div data-id="001">World</div>
<div data-id="002">Keep</div>
<div data-id="002">Only</div>
<div data-id="002">Unique</div>
<div data-id="003">Last</div>
<div data-id="003">Word</div>
<div data-id="004">Please</div>
<br><br>
<p>Result should be: World Unique Word Please</p>
I tried numerous ideas from the SO pages and google searches but I have no luck in keeping the last items. First items though work perfectly with this code.
var found = {};
$('[data-id]').each(function(){
var $this = $(this);
if(found[$this.data('id')]){
$this.remove();
}
else{
found[$this.data('id')] = true;
}
});
Here is a fiddle, hopefully that makes things easier http://jsfiddle.net/hx9Lzqf6/

We can find the last index with same id,store them into an array,then call $.each() again to remove elements with index not in the array
let result = {}
$('[data-id]').each(function(i,e){
let id = $(e).attr("data-id")
result[id] = i
});
result = Object.values(result)
$('[data-id]').each(function(i,e){
let id = $(e).attr("data-id")
if(!result.includes(i)){
$(e).remove()
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div data-id="001">Hello</div>
<div data-id="001">World</div>
<div data-id="002">Keep</div>
<div data-id="002">Only</div>
<div data-id="002">Unique</div>
<div data-id="003">Last</div>
<div data-id="003">Word</div>
<div data-id="004">Please</div>
<br><br>
<p>Result should be: World Unique Word Please</p>

Related

How to addEventListener and function with element as a parameter to multiple elements?

My goal is to have a bunch of div with clickable words to pass their ids to a Javascript function when one of them is clicked by the user. It works flawlessly for
<div id="wordbox">
<div id="pd"><h4>pdf</h4><br></div>
<div id="an"><h3>analysis</h3></div>
<div id="ai"><h2>artificial intelligence</h2></div>
<div id="tr"><h4>trends</h4><br><br></div>
<div id="dm"><h3>data mining</a></div>
</div>
var word = document.getElementById("pd");
word.addEventListener("click", function(){ showSlide(word.id) });
but I don't manage to get it working for all elements. This fails:
var wb = document.getElementById("wordbox").children;
wb.forEach(function (element, index){
element.addEventListener("click", function(){
showSlide(element.id);
});
});
Any ideas?
When you select the children from a node, it actually returns an array-like collection which is similar but not quite an array. In order to use forEach you first need to convert it into an array, and in the case below, I used the spread syntax to convert it into an array that allows me to use forEach.
const wb = document.querySelector('#wordbox')
const children = [...wb.children]
children.forEach(child => {
child.addEventListener('click', () => {
console.log(child.id)
})
})
<div id="wordbox">
<div id="pd"><h4>pdf</h4><br></div>
<div id="an"><h3>analysis</h3></div>
<div id="ai"><h2>artificial intelligence</h2></div>
<div id="tr"><h4>trends</h4><br><br></div>
<div id="dm"><h3>data mining</a></div>
</div>
wb is not a real array, it is an array-like object called live HTMLCollection. You can get an array using Array.from(). You can also use document.querySelectorAll() to select the elements
var wb = document.querySelectorAll("#wordbox > div");
// new browsers - https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach#bcd:api.NodeList.forEach
// wb
// To support older browsers
Array.from(wb)
.forEach(function(element, index) {
element.addEventListener("click", function() {
console.log(element.id);
});
});
<div id="wordbox">
<div id="pd">
<h4>pdf</h4><br></div>
<div id="an">
<h3>analysis</h3>
</div>
<div id="ai">
<h2>artificial intelligence</h2>
</div>
<div id="tr">
<h4>trends</h4><br><br></div>
<div id="dm">
<h3>data mining</a>
</div>
</div>

JS Remove all elements except a specific ID and its children

Responses to this:
How to remove elements except any specific id
are close to what I want but not quite.
In my case I am asking how I can remove all elements under parent id except id_n and its children: test1 and test2. The elements need to be removed, not just hidden.
<div id = "parent_id">
<div id = "id_1">
<div id = "id_11"> test</div>
<div id = "id_12">test </div>
</div>
<div id = "id_2"> test</div>
<div id = "id_n">id_n<br>
<div id='test1'>test1<br><div>
<div id='test2'>test2<br><div>
</div>
</div>
The result should be:
<div id = "parent_id">
<div id = "id_n">id_n<br>
<div id='test1'>test1<br><div>
<div id='test2'>test2<br><div>
</div>
</div>
Thanks for looking at this. Your suggestions are appreciated.
Using jQuery's siblings you remove all of it's children:
$('#id_n').siblings().remove();
Okay after thinking about this, there is another approach using Array manipulation:
var parentElement = document.getElementById('#parent_id');
parentElement.innerHtml = [].splice.call(parentElement.children).filter(item, function() {
return item.id === childId;
}).reduce((collatedHtml, item, function() {
return collatedHtml + item.innerHtml;
});
This grabs all the direct children of the parentElement and returns a new array (using Array.filter) before using Array.Reduce to collate the innerHtml of all the children.
Note: the reason i'm not using the ... prefix to convert to an Array is because it is not supported in IE 11 and below

Including the current node in the find scope

Consider the following snippet as an example:
<div class="bar foo">
</div>
<div class="bar">
<div class="foo"></div>
</div>
Given var $set=$('.bar'); I need to select both nodes with foo class. What is the proper way to achieve this. Considering addBack() requires a selector and here we need to use the $set jQuery object and $set.find('.foo') does not select the first node.
use this :
var $set = $(".bar").filters(function () {
var $this = $(this);
if($this.is(".foo") || $this.find(" > .foo").length !== 0){
return true;
} else{
return false;
}
});
Here's one way of going about it:
var set = $('.bar');
var foos = [];
for (var i = 0; i < set.length; i++) {
if ($(set[i]).hasClass('foo')) {
foos.push(set[i]);
}
}
if (set.find('.foo').length !== 0) {
foos.push(set.find('.foo')[0]);
}
console.log(foos);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="bar foo"></div>
<div class="bar">
<div class="foo"></div>
</div>
The for loop checks all elements picked up with jQuery's $('.bar'), and checks if they also have the foo class. If so, it appends them to the array. The if checks if any of the elements picked up in set have any children that have the foo class, and also adds them.
This creates an array that contains both of the DIVs with the foo class, while excluding the one with just bar.
Hope this helps :)
test this :
var $newSet = $set.filter(".foo").add($set.has(".foo"));
You could use the addBack() function
var $set=$('.bar');
console.log($set.find(".foo").addBack(".foo"));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="bar foo">
</div>
<div class="bar">
<div class="foo"></div>
</div>

How to select element has class start and end with specific string using jquery?

I got several divs using classes like
.wrap-1-addon-1
.wrap-2-addon-1
.wrap-3-addon-1
I want to select all of them and use if ( $(this).hasClass() ) to check if its one of them. Currently I only do check for a single class. How can I check all of these, for example .hasClass('wrap-*-addon-1')?
Best regards.
You can combine two jquery Attribute Starts With Selector [name^=”value”] and Attribute Ends With Selector [name$=”value”] to do this work.
$('div[class^="wrap-"][class$="-addon-1"]')
$('div[class^="wrap-"][class$="-addon-1"]').css("color", "red");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrap-1-addon-1">wrap-1-addon-1</div>
<div class="wrap-2-addon-1">wrap-2-addon-1</div>
<div class="wrap-3-addon-1">wrap-3-addon-1</div>
<div class="wrap-3-addon-2">wrap-3-addon-2</div>
You can use starts with selector:
$('div[class^="wrap"]')
JsFiddle demo
You could use .is() which support multiple classes, unfortunately .hasClass() works only for one class at a time.
Example:
element.is('.wrap-1-addon-1, .wrap-2-addon-1, .wrap-2-addon-1')
It is better to add another class and select with this class. You can then test it with regex.
$el = $(".wrap");
$el.each(function() {
var test = /wrap-[1-3]-addon-1/.test($(this).attr("class"));
$(".result").html(test);
console.log(test);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrap-1-addon-1 wrap"></div>
<div class="wrap-2-addon-1 wrap"></div>
<div class="wrap-3-addon-1 wrap"></div>
<div class="result"></div>
Inspiring regex matching from this answer:
var $ele = $("div:first");
alert(matchRule($ele.attr('class'),'wrap-*-addon-1'))
function matchRule(str, rule) {
return new RegExp("^" + rule.split("*").join(".*") + "$").test(str);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="wrap-1-addon-1">
</div>
<div class="wrap-2-addon-1">
</div>
<div class="wrap-3-addon-1">
</div>
This might help you, i used regex to resolve if current element's class(es) suits the desired pattern.
I assume you have more than 3 classes to check.
This pattern is for wrap-1-addon-1 to wrap-n-addon-1, n is some digit
function hasMyClass(elm) {
var regex = /(wrap-)+(\d)+(-addon-1)/i;// this is the regex pattenr for wrap-*-addon-1
var $this = $(elm);
var myClassesStr = $this.attr('class');
if(myClassesStr) { // if this has any class
var myClasses = myClassesStr.split(' '); // split the classes
for(i=0;i<myClasses.length;i++) { // foreach class
var myClass = myClasses[i]; // take one of classes
var found = myClass.match(regex); // check if regex matches the class
if(found) {
return true;
}
}
}
return false;
}
function test() {
$('#container div').each(function(){
var $this = $(this);
$('#pTest').append('<br/>test result for ' + $this.attr('id') + ':' + hasMyClass(this));
// hasMyClass(this) is the sample usage
})
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div id="div1" class="wrap-1-addon-1 anotherClass">div1 (wrap-1-addon-1)</div>
<div id="div2" class="wrap-2-addon-1 anotherClass anotherClass2">div2 (wrap-2-addon-1)</div>
<div id="div3" class="wrap-3-addon-1 anotherClass">div3 (wrap-3-addon-1)</div>
<div id="div4" class="anotherClass">div4 (none)</div>
</div>
<button id="testBtn" onclick="test();" type="button">TEST</button>
<p id="pTest" >...</p>

Javascript Elements with class / variable ID

There's a page with some HTML as follows:
<dd id="fc-gtag-VARIABLENAMEONE" class="fc-content-panel fc-friend">
Then further down the page, the code will repeat with, for example:
<dd id="fc-gtag-VARIABLENAMETWO" class="fc-content-panel fc-friend">
How do I access these elements using an external script?
I can't seem to use document.getElementByID correctly in this instance. Basically, I want to search the whole page using oIE (InternetExplorer.Application Object) created with VBScript and pull through every line (specifically VARIABLENAME(one/two/etc)) that looks like the above two into an array.
I've researched the Javascript and through trial and error haven't gotten anywhere with this specific page, mainly because there's no tag name, and the tag ID always changes at the end. Can someone help? :)
EDIT: I've attempted to use the Javascript provided as an answer to get results, however nothing seems to happen when applied to my page. I think the tag is ALSO in a tag so it's getting complicated - here's a major part of the code from the webpage I will be scanning.
<dd id="fc-gtag-INDIAN701" class="fc-content-panel fc-friend">
<div class="fc-pic">
<img src="http://image.xboxlive.com/global/t.58570942/tile/0/20400" alt="INDIAN701"/>
</div>
<div class="fc-stats">
<div class="fc-gtag">
<a class="fc-gtag-link" href='/en-US/MyXbox/Profile?gamertag=INDIAN701'>INDIAN701</a>
<div class="fc-gscore-icon">3690</div>
</div>
<div class="fc-presence-text">Last seen 9 hours ago playing Halo 3</div>
</div>
<div class="fc-actions">
<div class="fc-icon-actions">
<div class="fc-block">
<span class="fc-buttonlabel">Block User</span>
</div>
</div>
<div class="fc-text-actions">
<div class="fc-action"> </div>
<span class="fc-action">
View Profile
</span>
<span class="separator-icon">|</span>
<span class="fc-action">
Compare Games
</span>
<span class="separator-icon">|</span>
<span class="fc-action">
Send Message
</span>
<span class="separator-icon">|</span>
<span class="fc-action">
Send Friend Request
</span>
</div>
</div>
</dd>
This then REPEATS, with a different username (the above username is INDIAN701).
I tried the following but clicking the button doesn't yield any results:
<script language="vbscript">
Sub window_onLoad
Set oIE = CreateObject("InternetExplorer.Application")
oIE.visible = True
oIE.navigate "http://live.xbox.com/en-US/friendcenter/RecentPlayers?Length=12"
End Sub
</script>
<script type="text/javascript">
var getem = function () {
var nodes = oIE.document.getElementsByTagName('dd'),
a = [];
for (i in nodes) {
(nodes[i].id) && (nodes[i].id.match(/fc\-gtag\-/)) && (a.push(nodes[i]));
}
alert(a[0].id);
alert(a[1].id);
}
</script>
<body>
<input type="BUTTON" value="Try" onClick="getem()">
</body>
Basically I'm trying to get a list of usernames from the recent players list (I was hoping I wouldn't have to explain this though :) ).
var getem = function () {
var nodes = document.getElementsByTagName('dd'),
a = [];
for (var i in nodes) if (nodes[i].id) {
(nodes[i].id.match(/fc\-gtag\-/)) && (a.push(nodes[i].id.split('-')[2]));
}
alert(a[0]);
};
please try it by clicking here!
var getem = function () {
var nodes = document.getElementsByTagName('dd'),
a = [];
for (var i in nodes) if (nodes[i].id) {
(nodes[i].id.match(/fc\-gtag\-/)) && (a.push(nodes[i]));
}
alert(a[0].id);
alert(a[1].id);
};
try it out on jsbin
<body>
<script type="text/javascript">
window.onload = function () {
var outputSpan = document.getElementById('outputSpan'),
iFrame = frames['subjectIFrame'];
iFrame.document.location.href = 'http://live.xbox.com/en-US/friendcenter/RecentPlayers?Length=1';
(function () {
var nodes = iFrame.document.getElementsByTagName('dd'),
a = [];
for (var i in nodes) if (nodes[i].id) {
(nodes[i].id.match(/fc\-gtag\-/)) && (a.push(nodes[i].id.split('-')[2]));
}
for (var j in a) if (a.hasOwnProperty(j)) {
outputSpan.innerHTML += (a[j] + '<br />');
}
})();
};
</script>
<span id="outputSpan"></span>
<iframe id="subjectIFrame" frameborder="0" height="100" width="100" />
</body>
What does "I can't seem to use document.getElementsByID correctly in this instance" mean? Are you referring to the fact that you are misspelling getElementByID?
So...something like this (jQuery)?
var els = [];
$('.fc-content-panel.fc-friend').each(function() {
els.push(this));
});
Now you have an array of all the elements that have both of those classes.

Categories