Delete divs by 2 classes and node attribute - javascript

Imagine that we have some divs like that
<div class="row chapter" node="1">Chapter 1</div>
<div class="row section" node="1">Section 1</div>
Ajax accepts array of nodes that must be deleted. I got few questions about this
1) I'm using following function
$.each(result['nodes'], function(column, node)){
$(".row."+column).slideUp("slow").remove();
}
I can't figure out how to delete by 2 classes and node atribute. How to do that?
2) AFAIK $.each function deletes one by one. Is it possible to delete all at once?
3) How to deal with validation issues? I mean,

Since an object only has key-value pairs, in order to handle two classes and one attribute, you'll have to change the structure of your JSON. I suggest changing it to [{"class1":"foo","class2":"bar","node":1}]. With that format, this will work to collect the nodes:
$($.map(result['nodes'], function(o) {
return "."+o.class1+"."+o.class2+"[node="+o.node+"]";
}).join(","))
As Joseph stated, your original code will remove the nodes too soon, so you'll need to put the remove() in a parameter to slideUp():
$($.map(result['nodes'], function(o) {
return "."+o.class1+"."+o.class2+"[node="+o.node+"]";
}).join(",")).slideUp("slow", function() {
$(this).remove()
});
Sample jsFiddle: http://jsfiddle.net/tSu8z/
Note that there's really no "one by one" vs. "all at once" distinction. With the code above, jQuery gets the order to slide the nodes up all at once, but internally it will iterate through the nodes. Likewise, the nodes will most likely all appear to be deleted simultaneously, but jQuery is actually iterating through them. The only requirement for it to look simultaneous is for slideUp to be asynchronous, which it is.

You can collect the selectors using an array, join them and use remove all at once.
var toRemove = [];
$.each(result['nodes'], function(index, value){
toRemove.push('.row.'+index+'[node='+value+']');
}
//$('.row.chapter[node=1], .row.section[node=1]')
$(toRemove.join(',')).slideUp("slow",function(){
$(this).remove()
});

Related

jquery match multiple data groups (only if they are all true)

I have data groups on elements
data-foo
data-bar
I'd like to have a jquery selector that selects items where foo and bar BOTH match, e.g.
$("[data-foo='blah'],[data-bar='quax']")
would select the elements where data-foo = 'blah' and data-bar='quax'
It seems right now I'm getting results where data-foo=blah OR data-bar=quax. I need this to be data-foo=blah AND data-bar=quax
Just take out the comma. In essence, that is an OR selector. Without the comma, it looks for both.
console.log($("[data-foo='blah'],[data-bar='quax']").length) // 3 = not what you want
console.log($("[data-foo='blah'][data-bar='quax']").length) // 1 = what you want
console.log($("[data-foo='blah'][data-bar='quax']").html()) // Just to make sure its the right one
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div data-foo="blah" data-bar="quax">Both</div>
<div data-foo="blah">Foo</div>
<div data-bar="quax">Bar</div>
Another possible solution is to use filter:
$("[data-foo='blah']").filter("[data-bar='quax']")
However, this isn't terribly efficient, compared to #jamiec's answer which uses a single selector.

Using arrays to store multiple IDs or classes, and then manipulating them in functions

I have a set of classes stored in a JavaScript array called 'targets' as follows:
HTML
<div id="one">1</div>
<div id="two">2</div>
<div id="three">3</div>
<div id="four">4</div>
<div id="five">5</div>
<div id="six">6</div>
<div id="seven">7</div>
<div id="eight">8</div>
<div id="nine">9</div>
<div id="ten">10</div>
JavaScript — Array
var targets = ["#one", "#two", "#three", "#four", "#five", "#six", "#seven", "#eight", "#nine", "#ten"];
I would then like to manipulate them to use in functions. Depending on my situation, I'd either want to target one specific ID from the array, or all entries in the array at once. I do understand that each entry into an array is given a unique index number, starting with 0. Therefore, #one is index 0, and #ten is index 9.
I also understand that I can use for loops with arrays, that will cycle through each entry. My issue is that I can't seem to get my function working when it is called from a click event (on an input type="button" element).
Here are two examples of my code. One targets one specific entry, the other targets them all. Or at least, that is what it should be doing. Chrome's console shows no errors with my code, and I have never really worked with arrays, so this is a first for me.
JavaScript — Attempting to Target a Single Entry (Working)
$(targets[0]).addClass('hide').removeClass('show');
JavaScript - Attempting to Target All Entries I
$(targets).each(function() {
$(this).addClass('hide').removeClass('show');
});
JavaScript - Attempting to Target All Entries II
targets.forEach(function() {
$(targets).addClass('hide').removeClass('show');
});
JavaScript - Attempting to Target All Entries III
var i;
for ( i = 0; i < targets.length; ++i ) {
$(targets).addClass('hide').removeClass('show');
}
Also, I know that jQuery allows you to manipulate multiple classes and/or IDs at once by passing multiple values through the $() part of the code, but I'm in a predicament where the entries of the array will be different, depending on user input, and I feel that I will be manipulating in excess of 250 different IDs and classes in total. I've simply omitted the HTML code to the first 10 elements.
The majority of the 250 IDs/classes, are located on <option> elements. The .show and .hide classes used in the code are not applied directly to the <option> elements themselves, but to <select> elements that contain these options. Each <select> element has a unique ID.
If I can just figure out how to do this with arrays, everything will be fine.
Thanks.
You have to join the array in to a string that is a valid jQuery selector
$(targets.join(', ')).addClass('hide').removeClass('show');
This will give you
$("#one, #two, #three ...")
which is valid, an array of ID's is not a valid selector
Also note that showing and hiding option elements is not cross browser
Commenting on your approaches in order:
JavaScript — Attempting to Target a Single Entry (Working)
This one is working (as you say). You can use similar techniques to get at ALL elements in the array of id-s:
$(targets[0]).addClass('hide').removeClass('show');
$(targets.join(",")).addClass('hide').removeClass('show');
However the common way is to add a class attribute rather than an id. After all - remember - that's what classes are for. Any DOM element can (and usually does) have a multitude of classes.
<div id="one" class="number">1</div>
<div id="two" class="number">2</div>
<!-- ... and so on -->
The above two lines become equivalent to:
// These two lines are each equivalent to $(target[0])
$(".number").eq(0).addClass('hide').removeClass('show'); // or even...
$(".number")[0].addClass('hide').removeClass('show');
// This is equivalent to $(target.join(","))
$(".number").addClass('hide').removeClass('show');
JavaScript - Attempting to Target All Entries I
The .each function can only be called on jQuery objects. You can't use it on an array, but you can use $.each instead:
$.each(targets, function(idx, obj) {
$(obj).addClass('hide').removeClass('show');
});
JavaScript - Attempting to Target All Entries II
When using forEach, you need to (ok, not need to, but at least should) make use of the parameters passed to your callback:
targets.forEach(function(elt, idx, arr) {
$(elt).addClass('hide').removeClass('show');
// ... OR ...
$(arr[idx]).addClass('hide').removeClass('show');
// ... OR ...
$(targets[idx]).addClass('hide').removeClass('show');
});
JavaScript - Attempting to Target All Entries III
$(targets) selects nothing. It doesn't throw an error (though it probably ought to). You access array elements with the [index] notation:
for (var i = 0; i < targets.length; ++i ) {
$(targets[i]).addClass('hide').removeClass('show');
}
In your for-loop you're query-ing the whole list everytime and not specific elements, (add [i] to targets)
var i;
for ( i = 0; i < targets.length; ++i ) {
$(targets[i]).addClass('hide').removeClass('show');
}

Create unique buttons dynamically

I'm new to jQuery and am trying to create jQuery UI buttons dynamically and them to a list. I can create one list item but no more are appended after it. What am I doing wrong?
$('#buttonList').append('<li><button>'+ username + '</button>')
.button()
.data('type', userType)
.click(function(e) { alert($(this).data('type')); })
.append('<button>Edit</button></li>');
<div>
<ul id="buttonList">
</ul>
</div>
This only creates one list item with two buttons (although the second button seems to be encased in the first one, but I can probably figure that issue out). How do I get it to create multiple list items with their own unique 'data' values (i.e. I can't do a find() on a particular button class and give it data values as all buttons would then have the same data)?
I suggest to exchange the position of what you are appending and where you are appending to. This way, you retain the appended object, and should be able to work with it as a standard jQuery selector. From your code i commented out the .button() and the .append() lines, because i'm not sure what you want to do with them. Should you need help adding those lines, just drop a comment to my answer ;)
Oh, i almost forgot: i use var i to simulate different contents for username and userType data.
A JSFiddle for you is here: http://jsfiddle.net/cRjh9/1/
Example code (html part):
<div>
<p id="addButton">add button</p>
<ul id="buttonList">
</ul>
</div>
Example code (js part):
var i = 0;
$('#addButton').on('click', function()
{
$('<li><button class="itemButton">'+ 'username' + i + '</button></li>').appendTo('#buttonList')
//.button()
.find('.itemButton')
.data('type', 'userType'+i)
.click(function(e) { alert($(this).data('type'));
})
//.append('<button>Edit</button></li>')
;
i++;
});
You need complete tags when you wrap any html in a method argument. You can't treat the DOM like a text editor and append a start tag, append some more tags and then append the end tag.
Anything insterted into the DOM has to be complete and valid html.
You are also not understanding the context of what is returned from append(). It is not the element(s) within the arguments it is the element collection you are appending to. You are calling button() on the whole <UL>.
I suggest you get a better understanding of jQuery before trying to chain so many methods together
Just a very simplistic approach that you can modify - FIDDLE.
I haven't added the data attributes, nor the click function (I'm not really sure I like the
inline "click" functions - I generally do them in jQuery and try to figure out how to make
the code efficient. Probably not very rational, but I'm often so).
JS
var names = ['Washington', 'Adams', 'Jefferson', 'Lincoln', 'Roosevelt'];
for( r=0; r < names.length; r++ )
{
$('#buttonList').append('<li><button>'+ names[r] + '</button></li>');
}
$('#buttonList').append('<li><button>Edit</button></li>');

multiple selectors not seems to work

I have following HTML
<div id="finalTree">
<ul>
<li class="last" style="display: list-item;">
<a id="DataSheets" href="#">Data Sheets</a>
</li></u>...........</div>
and I am first hiding all these li and then trying to show those li which match to selector. Here is my JavaScript. Here filterData is id of links.
function filterLeftNavTree(filterData){
jQuery("ul.treeview").find("li").hide();
var selectors =[];
if(filterData.indexOf("|")!=-1){
var filterData = filterData.split("|");
for(i=0;i<filterData.length;i++){
selectors.push('#'+filterData[i]);
}
var filtered = selectors.join(',');
$(filtered ).show();
}else{
$('#'+filterData+).show();
} }
the last two line doesn't works...
any one can tell me what can be possible reason. Actually I tried to show li with :has, :contains, find().filter() but all these are taking too much time if I have large tree.
Do I am trying to show it by using multiple selector, but it's not showing any thing. Any alternative having faster way to show it will be highly appreciated.
What you have (aside from the syntax error #verrerby mentioned) should be working, but why not cut down on that code a bit?
You can slim things down by adding the # on every element after the first as part of the .join(), this also greatly simplifies the logic. You can reduce it down to:
function filterLeftNavTree(filterData) {
$("ul.treeview li").hide();
$('#'+filterData.split('|').join(',#')).show();
}
Also note the change removing .find(), it's faster in browser that support it to use a single selector, and just as fast in all the others.
The only other possible reason I see for your code not working is jQuery is used for the hide and $ is used on the show, is it possible $ refers to something else? (e.g. ptototype?) To test just replace $ with jQuery on the .show() call.
You have an extra +' in the last statement, and you could do it in multiple statements instead of one (the #{id} selector is very fast):
if(filterData.indexOf("|")!=-1){
var filterData = filterData.split("|");
for(i=0;i<filterData.length;i++){
$('#'+filterData[i]).show();
}
}else{
$('#'+filterData).show();
}

Sort Unordered List with Javascript

I have been looking at the stackoverflow thread:
How may I sort a list alphabetically using jQuery?
but for my scenario, I have the hierachy:
<ul><li>NAME_TO_SORT_ON</li></ul>
Based on this set-up, how can I modify the solution from thread mentioned here to cater for my scenario which has a tag as I would like to sort on all the name found in NAME_TO_SORT_ON?
Thanks.
I would recommend using a jQuery-based solution for this, because once you start getting into multiple DOM levels (e.g. sorting siblings at one level based on the contents of elements at a deeper level) the simple sort mechanism breaks down. It's an extremely rough solution - essentially blowing away the existing HTML and replacing it in raw text mode with other HTML. We can do better by actually shuffling the DOM elements around:
function sort(list, key) {
$($(list).get().reverse()).each(function(outer) {
var sorting = this;
$($(list).get().reverse()).each(function(inner) {
if($(key, this).text().localeCompare($(key, sorting).text()) > 0) {
this.parentNode.insertBefore(sorting.parentNode.removeChild(sorting), this);
}
});
});
}
To use it, we pass in a selector to the list and a selector to use to locate the key we want to sort on:
<ul class="toBeSorted">
<li>sort me</li>
</ul>
<script type="text/javascript">
sort('ul.toBeSorted>li', 'a');
//we want to sort the <li>'s in ul.toBeSorted;
//and we want to use the text of the first and only <a>
//in each item as the sort key
</script>

Categories