jquery $.each is non-blocking? - javascript

$("<ol>").appendTo(some_div);
$.each(map, function(i,example){
$("<li>" + example + "</li>").appendTo(some_div)
});
$("</ol>").appendTo(some_div);
expected:
<ol><li>example1</li><li>example2</li></ol>
actual:
<ol></ol><li>example1</li><li>example2</li>
Any idea why this happens?

You are doing DOM operations and not string operations. And $("<ol>") does already create an OL element and not just a string containing <ol>.
You need to append the LI elements to the newly created OL element:
var ol = $("<ol>").appendTo(some_div);
$.each(map, function(i,example){
$("<li>" + example + "</li>").appendTo(ol);
});

You should append your <li> entries to your <ol>. Otherwise you can't know how browser is going to handle your code. Additionally, you should append <ol></ol> instead of separate <ol> and </ol>. jQuery's .append and .appendTo are not string operations, those are modifying page DOM tree.
$("<ol></ol>").appendTo(some_div);
olelement = $(some_div).find("<ol>")
$.each(map, function(i,example){
$("<li>" + example + "</li>").appendTo(olelement);
});

This line
$("<ol>").appendTo(some_div);
isn't simply adding an open tag as you think it is. jQuery is building an ordered list element and adding it to some_div. Likewise, your $.each is appending list item elements to some_div, so they're ending up as siblings of the list. You need to append the list items to the list element.

I believe $("<ol>").appendTo creates the full <ol></ol> tag. Either append the li items to the OL you've created, or create a long string and then do one append. Append is an expensive operation, if you're going to have 10s or more list items you should do the latter.

Related

Parent cannot .append() .prepend() the same created element

Interested to know if anyone can help describe the internals for the behaviour I am seeing.
Essentially, when creating a new dom element (then storing in a const) this element cannot be appened and prepended to the same parent element.
Example:
const ul = document.querySelector('ul');
const button = document.querySelector('button');
button.addEventListener('click', () => {
const li = document.createElement('li');
li.textContent = 'new li';
ul.prepend(li);
ul.append(li);
});
It seems the last call to either append or prepend, note if you call prepend last the new element is only added to start of the ul.
Digging into this it seems the cloning the node works prior to the subsequent append/prepend call.
const li = document.createElement('li');
li.textContent = 'something new to do';
ul.prepend(li);
const newLi = li.cloneNode(true);
ul.append(newLi);
However I'm interested to know the inner workings of this and why you can't seem to call against the same element? Can anyone shed any light on this as the mozilla docs don't seem to shed any light on this.
Fiddle: https://jsfiddle.net/gf7b0pom
Thanks everyone!
I think the confusion here is perhaps your understanding of what is stored created and stored in the line const li = document.createElement('li');. In this case, li doesn't contain a template that can be used over and over- when you use document.createElement() you are creating a single instance of an element of your choice. That single instance can only be in one place at a time.
As an analogy, I believe you are imagining li to be something like a rubber stamp, that can be used anywhere on a sheet of paper to make a list item. In reality, li is more like a sticker -- it can only be in one place on the paper at a time. When you run:
ul.prepend(li);
ul.append(li);
...it is like you stick your list item sticker to the front of the list, then you peel it off and stick it to the back of the list. This is why you need to call .cloneNode(true)-- it is essentially giving you a duplicate sticker to use elsewhere.
The reason is actually simple. When you create a new element, you create only one element. In your event listener, you first prepend that element then you append the same element.
ul.prepend(li);
ul.append(li);
So code is doing what you ask. It is moving the element but it is using the same element because you don't have a 2nd element.
On the other hand you want to append and prepend total of 2 elements which contains the same shape/data.
So you need 2 DOM elements for that.
If you also clone an element, you can also use it once. So if you want to append that element to multiple places, then every-time you need to clone then append.

How do I read this function?

function showTweet(username) {
$( "<ul/>", {
"class": "my-user-list",
html: usertweets[username].join( "<li/>" )
}).appendTo( $("#tweets") );
}
So I see that the selector is targeting an unordered list, but what comes after the comma and why is it in curly brackets?
I understand the .append portion. I do not understand what "class": "my-user-list" and html: usertweets[username].join( "<li/>") do. Note that usertweets is an array.
Any insight would be greatly appreciated!
The selector is not targeting a ul - it is creating one. The second parameter is an object that contains the properties to set on the new ul element. It is then added to the DOM by appending it to the #tweets element.
To show the difference:
// to create a ul element in memory
$('<ul></ul>'); // or...
$('<ul />');
// select all ul elements currently in the DOM
$('ul');
The curly brackets are for PlainObject which is plain JavaScript object. From that I would read
Please create me a <ul> with class my-user-list with html of lists of usertweets joined with <li/> and append that to <ul> and append the ul to an element with id tweets
Here's the example
http://jsfiddle.net/xz6a0yqy/
It's not targeting ul, it first creates a <ul> element, and set the <ul>'s class to "my-user-list", then set its the html inside it to usertweets[username].join("<li/>"), which should creates some <li>, and finally append the newly created <ul> and the <li>s inside it to $("#tweets").
You can see more from jQuery#.jQuery().

Accessing children of div and appending span

I am accessing my children like this, i am trying to set the span title for the each div container.
$(".div-container").children().each(function(n, i){
console.log("Is it coming" + this.id);
$(this.id).before($('<span />').css('margin-left' , '60px').attr({'class':'progress-title' }).html('Title'));
$(this.id).before($('<span />').attr({'class':'progress-title-after' }).html('25% Usage'));
});
I am getting the corresponding the id's, but the span element is not getting added to my div containers.
this refers to the element, so you don't need to reselect it by ID. Just wrap this in a jQuery object.
$(this).before($('<span />').css('margin-left' , '60px').attr({'class':'progress-title' }).html('Title'));
Why not
$(this).before($('<span />').... // rest of code
instead of concatenating those IDs like
$(this.id).before($('<span />').... // rest of code
Because you're fetching IDs of each children so ultimately you're getting the object itself

Using javascript or jQuery to hide all list elements after a specific one

What would be the quickest way to go through all of the list items in one unordered list and remove all of the items after a specified list item?
Example: Let's say the list will always contain an item with the text "Hobbies." The javascript bit will have to find that item and remove all of the li items after it.
Using :contains and .nextAll:
$('li:contains("Hobbies.")').nextAll().hide();
Grab your item using the :contains selector to look for "Hobbies". Then you can grab all li items after it with nextAll() and remove() them.
This will hide all the li elements after the specific one
$('li').filter(function(index) { return $(this).text() === "Hobbies"; }).nextAll().hide();

Jquery - Get xth element

For example, I have a div with an id (lets say "the_div"). This div contains an unordered list, and this list has 5 items in it.
How would I add a class to the third list item, without any of the list items having a class attached to them?
Edit: Even better, how would I change the list item text to equal what number element it was?
Thanks.
Or...
$('#the_div ul li:eq(2)').addClass('className');
You can combine the selectors together - if you prefer :)
For your first problem, you can use eq, which is 0 based:
$('ul li', '#thediv').eq(2).addClass('whatever'); // add class to 3rd item
For your second problem, you can use each to iterate through all the list items. The callback function passes an argument containing the index of the current element in the set:
$('ul li', '#thediv').each(function(i) {
$(this).text(i); // update each list item with its index, 0 based.
});

Categories