<ul id="myid">
<li>microsoft</li>
<li>microsoft</li>
<li>apple</li>
<li>apple</li>
</ul>
I want to remove duplicates from li by using jquery.
How can I do that?
example
I find that the script is faster
var liText = '', liList = $('#myid li'), listForRemove = [];
$(liList).each(function () {
var text = $(this).text();
if (liText.indexOf('|'+ text + '|') == -1)
liText += '|'+ text + '|';
else
listForRemove.push($(this));
});
$(listForRemove).each(function () { $(this).remove(); });
uniqueLi = {};
$("#myid li").each(function () {
var thisVal = $(this).text();
if ( !(thisVal in uniqueLi) ) {
uniqueLi[thisVal] = "";
} else {
$(this).remove();
}
})
This build an index (an object) of unique values. For your example, uniqueLi will look like this afterwards:
{
"microsoft": "",
"apple": ""
}
So whenever a value is encountered that has been added to the index before, the associated <li> gets removed.
You could use
var inner = [];
$('li').each( function(index, Element){
if (jQuery.inArray(this.innerHTML, inner) == -1){
inner.push(this.innerHTML);
}
else {
$(this).remove();
}
});
Here's a function that will do it, a slightly different way:
function removeDuplicateItems(id) {
var ul = $('#' + id);
$('li', ul).each(function() {
if($('li:contains("' + $(this).text() + '")', ul).length > 1)
$(this).remove();
});
}
Call with removeDuplicateItems('myid');
I have used #Thariama solution in the past, but I have compatibility problems with IE6 (I still needs to support this dinosaur).
If the item repeats, so remove it from ul. It works with dynamic added li.
var seen = {};
$("ul#emails_exclusion_list").find("li").each(function(index, html_obj) {
txt = $(this).text().toLowerCase();
if(seen[txt]) {
$(this).remove();
} else {
seen[txt] = true;
}
});
Related
I know little about javascript. From what I can see, this shows a set of rows that contain a value (in this case, the author of a WP plugin).
What I'd like to do, instead of finding the data-name value in the row, is find if the first letter of this value is "A". And hopefully I should be able to work on the preceding code to get to this part... :)
Thanks so much.
<script>
var authors = [];
$('.pba-id').each(function () {
var author = $(this).attr('data-author');
if (-1 == $.inArray(author, authors))
authors.push(author);
});
$.each(authors, function (i, author) {
$select.append($('<option>').html(author));
});
$select.change(function(){
var value = $(this).val();
if ('__pba_none' == value) {
$('#the-list tr').show();
return;
}
$('#the-list tr').each(function(){
var $row = $(this);
if ($row.find('.pba-id[data-author="' + value + '"]').length)
$row.show();
else
$row.hide();
});
</script>
Use Attribute Starts With Selector [name^=”value”] selector.
Selects elements that have the specified attribute with a value beginning exactly with a given string.
$('#the-list tr').each(function() {
var value = "A";
var $row = $(this);
if ($row.find('.pba-id[data-name^="' + value + '"]').length) {
//---------------------------^^^
$row.show();
} else {
$row.hide();
}
});
Try this :
$('#the-list tr').each(function() {
// var value = "any value" ;
var $row = $(this);
if ($row.find('.pba-id[data-name^="' + value[0] + '"]').length) {
$row.show();
} else {
$row.hide();
}
});
I am trying to click on links to add it to select with checking if there is the item was not in list before menu but It seems loop part has some issue.
JavaScript code
$(document).ready(function() {
$('.link').click(function(event) {
var this_item_was_not_in_list = true;
var item =$(this).text();
for (var i = 0; i < $('#list').length; i++) {
if ($('#list').options[i].text == item) { this_item_was_not_in_list = false; break;};
};
if (this_item_was_not_in_list) {$('#list').append('<option>' + item + '</option>')};
});
});
HTML Code
Bread
Suger
Tea
<select id="list">
</select>
There are numerous ways to simplify this using jQuery methods.
One example:
$('.link').click(function(event) {
var item = $(this).text();
if(!$('#list option[value=' + item +']').length){
$('#list').append('<option value="' + item +'">' + item + '</option>');
}
});
Instead of using your for loop can easily iterate over a collection of elements using each() which exposes the index and the element
Where you are doing:
for (var i = 0; i < $('#list').length; i++) {
You should be doing:
for (var i = 0; i < $('#list option').length; i++) {
if ($('#list').options[i].text == item)
Aren't some parenthesis missing?
if ($('#list').options[i].text() == item)
The problen is here:
$('#list').options[i].text == item
That is not the way to get option elements from the select element.
Try this:
$('#list').find('options:nth(' + i + ')')).text() == item
Use the following code. Here's the jsfiddle for this.
$(document).ready(function() {
$('.link').click(function(event) {
var this_item_was_not_in_list = true;
var clickedItemName =$(this).text();
var listLength = $('#list option').length;
for (i=0; i<listLength ; i++)
{
if ($('#list option')[i].value == clickedItemName)
{
this_item_was_not_in_list = false;
break;
}
}
if (this_item_was_not_in_list)
{
$('#list').append('<option>' + clickedItemName + '</option>');
}
});
});
<html>
Bread
Sugar
Tea
<select id="list"></select>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</html>
I have this script for searching in table with Highlighting value from "input". But only for first TD in all TR.
Function remove Highlighting
function removeHighlighting(highlightedElements){
highlightedElements.each(function(){
var element = $(this);
element.replaceWith(element.html());
})
}
Function add Highlighting
function addHighlighting(element, textToHighlight){
var text = element.text();
var highlightedText = '<em>' + textToHighlight + '</em>';
var newText = text.replace(textToHighlight, highlightedText);
element.html(newText);
}
Searching in table but only in first TD in TR
$("#search").on("keyup", function() {
var value = $(this).val();
removeHighlighting($("table tr em"));
$("table tr").each(function(index) {
if (index !== 0) {
$row = $(this);
var $tdElement = $row.find('td:first');
var id = $tdElement.text();
var matchedIndex = id.indexOf(value);
if (matchedIndex != 0) {
$row.hide();
}
else {
addHighlighting($tdElement, value);
$row.show();
}
}
});
});
I don´t know how can I searching in all TD and How can I write e.g. some alert if "matchedIndex == -1" (if not found some value from input)
Try looping in all TDs of TR
$("table tr").each(function(index) {
if (index !== 0) {
row = $(this);
$("td", this).each(function(idx) {
var id = $(this).text(); //or $(this).innerText
var matchedIndex = id.indexOf(value);
if (matchedIndex != 0) {
$row.hide();
}
else {
addHighlighting($tdElement, value);
$row.show();
}
}
}
});
A short way
$("table tr > td em").each(function(){
$( this ).replaceWith( $( this ).text() );
});
Adding a span tag with a highlight class is the way to go like suggested in the comments.
Please find a working demo below and in this jsFiddle.
There is a really useful function to remove all the wrapping of the spans. You can do this with $('span.highlight').contents().unwrap().
For finding the text you can use string.search(searchText) or string.match(searchText). The search method will return -1 if nothing is found and the position of the text if found. And match would return occurences in the searchText.
For testing that it finds the first occurence I have added TestY in the table. The flag matched is responsible for this behavior. If you would remove it, it would highlight both TestY elements.
(function () {
var removeHighlight = function () {
$('span.highlight').contents().unwrap();
};
var wrapContent = function (index, $el, text) {
var $highlight = $('<span class="highlight"/>')
.text(text.substring(0, index));
//console.log(text.substring(0, index));
var normalText = document.createTextNode(text.substring(index, text.length));
//console.log(index, $highlight.text(), normalText);
$el.html($highlight).append(normalText);
};
var highlightTextInTable = function ($tableElements, searchText) {
// highlights if text found (during typing)
var matched = false;
//remove spans
removeHighlight();
$.each($tableElements, function (index, item) {
var $el = $(item);
if ($el.text().search(searchText) != -1 && !matched) {
//console.log("matched", $el, $el.html());
wrapContent(searchText.length, $el, $el.html());
//console.log(searchText, $el.text());
if (searchText == $el.text()) {
// found the entry
//console.log("matched");
matched = true;
}
}
});
};
$(function () {
//load table into object
var $tableRows = $('table tr');
var $tableElements = $tableRows.children();
//console.log($tableRows, $tableElements);
$('#search').on('keyup', function (e) {
var searchText = $(this).val();
if (searchText.length == 0) {
// catches false triggers with empty input (e.g. backspace delete or case lock switch would trigger the function)
removeHighlight(); // remove last remaining highlight
return;
}
highlightTextInTable($tableElements, searchText);
});
});
})();
.highlight {
background-color: #00FFFF;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="search" />
<table>
<tr>
<td>TestX</td>
<td>Test1.2</td>
<td>Test1.3</td>
<td>Test1.4</td>
</tr>
<tr>
<td>Test2.1</td>
<td>TestY</td>
<td>Test2.3</td>
<td>Test2.4</td>
</tr>
<tr>
<td>Test3.1</td>
<td>TestY</td>
<td>Test3.3</td>
<td>Test3.4</td>
</tr>
</table>
I'm going to apply a letter-based navigation to filter the content of a table and a list. When clicking one of the letters, filters the list/table to show only the items in the list/table that start with that letter.
But the problem i'm facing is "All List". I need to display "all" link as well, Can any one please help me to add "All" link..
$(function () {
var _alphabets = $('.alphabet > a');
var _contentRows = $('#countries-table tbody tr');
_alphabets.click(function () {
var _letter = $(this), _text = $(this).text(), _count = 0;
_alphabets.removeClass("active");
_letter.addClass("active");
_contentRows.hide();
_contentRows.each(function (i) {
var _cellText = $(this).children('td').eq(0).text();
if (RegExp('^' + _text).test(_cellText)) {
_count += 1;
$(this).fadeIn(400);
}
});
});
});
Here is the Demo link...
Thanks...
Apply the Regex only when the text is not equal to All
$(function () {
var _alphabets = $('.alphabet > a');
var _contentRows = $('#countries-table tbody tr');
_alphabets.click(function () {
var _letter = $(this),
_text = $(this).text(),
_count = 0;
_alphabets.removeClass("active");
_letter.addClass("active");
_contentRows.hide();
_contentRows.each(function (i) {
var _cellText = $(this).children('td').eq(0).text();
if (_text === 'All') {
_count += 1;
$(this).fadeIn(400);
} else {
if (RegExp('^' + _text).test(_cellText)) {
_count += 1;
$(this).fadeIn(400);
}
}
});
});
});
Check Fiddle
Just show all tr onclick()
$('a').first().click(function(){
$('#countries-table tbody tr').fadeIn(400);
});
link to jsfiddle
[updated]
an easy one
Just add this line :
if(_text == 'All') _text = '.';
DEMO
Edit :
according to your wish, this code allows you to fade the letters that don't have words:
_alphabets.not(':first').css('opacity','0.5');
_contentRows.each(function(){
var beg = $(this).children('td:first').text().trim()[0];
$('.alphabet a:eq('+(beg.charCodeAt(0)-64)+')').css('opacity','1.0');
});
DEMO
Explanation: what I did here is getting the first letter of each first td in all trs then convert it to ascii (A=65 ..) then deduct 64 so that the first index starts from 1 (A) and so on (since index 0 is for "All")
Note: you don't have to use regex at all since you are just comparing the first characters, you can increase the efficiency by eleminating the regex .
I have adapted the following code from a tutorial to filter li elements based upon their contents:
$('#_selectSearch_' + index).keyup(function() {
var filter = $(this).val();
if(filter) {
$('#_selectDrop_' + index).find("li:not(:contains(" + filter + "))").slideUp();
$('#_selectDrop_' + index).find("li:contains(" + filter + ")").slideDown();
} else {
$('#_selectDrop_' + index).find("li").slideDown();
}
});
The code works just fine but when working with large lists is very slow bringing the browser to a grinding halt for seconds with every key-press. I have been looking around and have come to the conclusion that the way to improve this is to somehow cache the list and not operate directly on the DOM but have no idea how to implement this.
If your main concern is performance the following code:
caches element containing filter string.
caches li elements.
doesn't show or hide elements that are already in that state.
uses indexOf which is very fast.
if the user types letters under 500 milliseconds apart the showMatches will not run.
var selectSearch = $("#_selectSearch_" + index );
var li = $("#_selectDrop_" + index + " li");
var currentTimeout;
selectSearch.on( "keyup", function( ) {
if( currentTimeout ) { window.clearTimeout( currentTimeout ) };
currentTimeout = setTimeout( showMatches, 500 );
});
function showMatches( ) {
var txt = selectSearch.val();
for( var i = 0, len = li.length; i < len; i++ ) {
var content = li[i].textContent ? li[i].textContent : li[i].innerText;
if( txt && content.indexOf( txt ) > -1) {
if( li[i].style.display !== "block" ) {
li[i].style.display = "block";
}
} else {
if( li[i].style.display !== "none" ) {
li[i].style.display = "none";
}
}
}
}
Fiddle with 400 li elements here
You can cache this element $('#_selectDrop_' + index + ' li');
$('#_selectSearch_' + index).keyup(function() {
var $li = $('#_selectDrop_' + index + ' li');
var filter = $(this).val();
if (filter) {
$li.not(":contains(" + filter + ")").slideUp();
$li.contains(filter).slideDown();
} else {
$li.slideDown();
}
});
drop = $('#_selectDrop_' + index + ' li');
$('#_selectSearch_' + index).keyup(function() {
var filter = $(this).val();
if(filter) {
drop.find(":not(:contains(" + filter + "))").slideUp();
drop.find(":contains(" + filter + ")").slideDown();
} else {
drop.slideDown();
}
});
Drop will be cached just once, and then will be used at every keyup. Also this uses the minimum possible of find
$('#_selectSearch_' + index).keyup(function() {
var filter = $(this).val();
// by combining and cacheing all the way to the li
// we save a lot of time, since it seems that's where you are doing
// all your searching from
var selectDrop = $('#_selectDrop_' + index + ' li');
if (filter) {
selectDrop.not(':contains("' + filter + '")').slideUp();
selectDrop.contains(filter).slideDown();
}
else {
selectDrop.slideDown();
}
});
I'll give it a go with a somewhat modified (and untested) version:
$('#_selectSearch_' + index).on('keyup', function() {
var filter = this.value,
lis = document.getElementById('_selectDrop_' + index).getElementsByTagName('li'),
len = lis.length,
sup = 'textContent' in this;
if (filter.length) {
for (var i = len; i--) {
var text = sup ? lis[i].textContent : lis[i].innerText;
$(lis[i])[text.indexOf(filter) != -1 ? 'slideDown' : 'slideUp']();
}
} else {
$(lis).slideDown();
}
});