Read HTML snippet from DOM and add custom data to it - javascript

I'm used to use jQuery to query elements by their id and place inside them or in their attributes some custom data retrieved from a webservice.
But now the data I'll retrieve is an array of objects. So it's not just a matter of adding one data into one element. I need to read a li which has some HTML inside, then replace some elements on this HTML with data from one object.
This has to be done for each object in the array, so I'd need to create a new li from that "template", populate it, then add it to the ul.
I'm able to query the ul, find its li and remove it from DOM, and append multiple lis to it.
But I don't know how, having the li in a jQuery object, make changes on its innerHTML. This is the part I'm lost, as I was still unable to find some solution on Google.
Here's an example: https://jsfiddle.net/r76vpLdg/
How can I create a new object based on template and replace the contents of those 2 spans? I added a second list, with an example of the desired result.

Here's a Vanilla JS solution using a JSON object as data source and template strings.
Unless using jQuery is a must, there is no reason to use it in this case.
<p>template:</p>
<ul id="myListContainer">
</ul>
<button onclick="createTemplateStrings()">
START
</button>
function createTemplateStrings (){
var obj = [
{"name": "John", "weekday" : "Wednesday"},
{"name": "Marry", "weekday" : "Sunday"},
{"name": "Edward", "weekday" : "Friday"},
{"name": "Jack", "weekday" : "Tuesday"}
]
let ul = document.getElementById('myListContainer')
for(let row of obj){
let li = document.createElement('LI')
li.innerHTML = `Hello, ${row.name}, how's your ${row.weekday} ?`
ul.append(li)
}
}

You can create elements "in memory" without them being part of the DOM, build them up, then add them to the DOM as required, eg:
var li = `$("<li>");
li.html(innerHTML);
ul.append(li);
Working example:
var ul = $("ul");
$("button").click(function() {
var li = $("<li>");
li.text("new item");
ul.append(li);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>item</li>
</ul>
<hr/>
<button type='button'>add</button>
To work with an existing "template", you can .clone() an existing li and make changes, one possible solution/example:
var ul = $("ul");
$("button").click(function() {
// create a copy of the "template"
var li = ul.find("li.template").clone().removeClass("template");
// make changes
li.find("span").removeClass("first").addClass("new").text("new");
ul.append(li);
});
li>span.first { color: blue; }
li>span.new { color: green; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li class='template'>This is the <span class='first'>first</span> item</li>
</ul>
<hr/>
<button type='button'>add</button>

Related

Closing one element when opening another within the same loop using Javascript

first time on here so i'll try my best to explain what I'm asking.
So I have 3 list items with the same class name. I've put them in a looping function so that when you click on one it will display a sub set of list items for that specific list item. I also have them inside an if statement that adds a new class name to the specific list item that was clicked. It allows opening and closing of the sub list items when you click the corresponding parent element.
My question is; how can I use this same principle of checking for the additional class name, when the user clicks any of the list items. In other words, I am trying to code it in a way that will allow me to close any of the open sub list items when the user clicks a new list item.
This is what I came up with but it doesn't know what button[i] is when I include it within the "click" function. What I was trying to do with this code is to take whatever list item was clicked, and then check the previous and next iterations of the class name "button" to see if any of the contain also contain the class name "clicked.
HTML
<div class="main">
<ul>
<li>One
<ul>
<li>One-1</li>
<li>One-2</li>
</ul>
</li>
<li>Two
<ul>
<li>Two-1</li>
<li>Two-2</li>
</ul>
</li>
<li>Three
<ul>
<li>Three-1</li>
<li>Three-2</li>
</ul>
</li>
</ul>
</div>
CSS
.main ul ul {
display: none;
}
.main ul ul li {
display: block;
}
Javascript
var button = document.getElementsByClassName("button");
for (i = 0; i < button.length; i++) {
button[i].addEventListener("click", function() {
var prevItem = button[i - 1];
var nextItem = button[i + 1];
if (prevItem.className !== "button") {
prevItem.className = "button";
prevItem.nextElementSibling.style.display = "none";
}
if (nextItem.className !== "button") {
nextItem.className = "button";
nextItem.nextElementSibling.style.display = "none";
}
if (this.className === "button") {
this.className += " clicked";
this.nextElementSibling.style.display = "block";
}
});
}
I am wanting to make this code usable no matter how many list items you add. So checking exactly button[0] button[1] and button[2] wasn't really an option, but I can see how button[i + 1] might not check every list item after it but rather just the next one. I tried adding another loop but ran into similar issues. anyway that's why I'm here. Thanks for any help in advance.
Since I am not sure whether I understood your question correctly, I quickly rephrase it in my own words.
Question: "I have an arbitrary number of list elements, of which each contains a button and a nested list. The button is always visible, the nested list is hidden by default. When the user clicks on a button, the corresponding nested list should be shown. At the same time, all other shown nested lists should be hidden again. How can I achieve this?"
The original HTML looks fine:
<div class="main">
<ul>
<li>One
<ul>
<li>One-1</li>
<li>One-2</li>
</ul>
</li>
<li>Two
<ul>
<li>Two-1</li>
<li>Two-2</li>
</ul>
</li>
<li>Three
<ul>
<li>Three-1</li>
<li>Three-2</li>
</ul>
</li>
</ul>
</div>
The CSS I did not fully understand, but I suggest the following:
.main ul ul {
display: none;
}
.main li.is-active ul {
display: block;
}
.main ul ul li {
display: block;
}
By adding the "is-active" class to an LI element, it is shown. This way, the CSS controls the visibility.
For the JavaScript part, I suggest this:
const buttonElements = Array.from(document.querySelectorAll('.button'));
buttonElements.forEach(buttonElement => {
buttonElement.addEventListener('click', () => {
const activeElements = Array.from(document.querySelectorAll('.is-active'));
activeElements.forEach(activeElement => {
activeElement.classList.remove('is-active');
});
buttonElement.parentElement.classList.add('is-active');
});
});
This solution assumes you can use newer versions of JavaScript/ECMAScript. Overall, it makes use of const and arrow functions.
First, we get all elements with the class "button" by using document.querySelectorAll(). Since the result is a NodeList and no array, we convert it using Array.from(). Afterwards, we loop through the array by using Array.prototpye.forEach(). We add an event listener for the "click" event. When a button is clicked, we search for all elements with the "is-active" class and for each one remove it. Finally, we add the "is-active" class to the parent element of the clicked button using Node.prototype.parentElement().
Here is another solution that works in older browsers:
var buttonElements = document.getElementsByClassName('button');
for (var i = 0; i < buttonElements.length; i++) {
buttonElements[i].addEventListener('click', function(event) {
var activeListElements = document.getElementsByClassName('is-active');
for (var i = 0; i < activeListElements.length; i++) {
activeListElements[i].setAttribute('class', '');
}
event.target.parentNode.setAttribute('class', 'is-active');
});
}
This is pretty much the same as the other approach but works with older versions of JavaScript.
Generally, the idea is to focus on an arbitrary sum of elements instead of an array with a specific length. In natural language something like: "Give me all buttons. For every button, add an event listener. When a button is clicked, give me all active list elements and remove their active status. Then, mark the list item above the button as active".
Hope this helps

Javascript DOM,accesing the textnode of the <li>element using nextsibling property

<body>
<div id="li-container">
<ul>
<li class="hot">item1</li>
<li id="secLi" class="cool">item2</li>
<li class="cool">item3</li>
<li class="cool">item4</li>
</ul>
</div>
<script language="javascript" type="text/javascript">
var secLi = document.getElementById("secLi");
var sib = secLi.nextSibling;
document.write(sib);
//OR //OR //OR //OR //OR //OR //OR //OR
var secLi = document.getElementById("secLi");
var sib = secLi.nextSibling;
document.write((sib).textContent);
</script>
</body>
I want to get the textnode of the third list(li) item using nextSibling property and write in the document.I know I can use "li.textContent" to access it but I want it this way.
No,I am not looking for "nextElementSibling",I want to acess the "textNode" of "secondli" using "nextSibling" property and that is because if I want to get to the "third li",I must use "nextSibling.nextSibling"twice to get to the "third li".(1)First "nextSibling" is for the "text-node" of the "2nd li" and (2)Second "nextSibling" is for the "3rd li".So I am not able to get the text-node of "2nd li" using "next-sibling" once.
I used text-fixer.com to remove other white-spaces and line breaks even then it dosent work.
Are you perhaps looking for nextElementSibling?
var secLi = document.getElementById('secLi');
secLi.nextSibling; // Is a text node.
secLi.nextElementSibling; // Is the <li> you're looking for, so..
secLi.nextElementSibling.textContent; // Gives you "item3"
Update
To better understand why you want nextElementSibling instead of nextSibling look at what the parent <ul> says its childNodes are:
secLi.parentElement.childNodes;
// [#text, <li>, #text, <li>, #text, <li>, #text, <li>, #text]
You don't want the nextSibling because it's just the empty text between list items. You want the next element (list item).
See https://developer.mozilla.org/en-US/docs/Web/API/NonDocumentTypeChildNode/nextElementSibling
the textnode of the li element is a child of 2nd li element.
So the code would be
var sib = secLi.firstChild.textContent;
document.write(sib);
#brianvaughn

how to append data from stating in js tree using jquery?

I Found one example of js tree in jquery ? in this user can add new data inside after selecting the
the row.
here http://jsfiddle.net/fuu94/
But When I remove all row (remove ul and li from mark up)and start making from first it will not work why ?
http://jsfiddle.net/fuu94/1/
$('#tree').jstree({
"core": {
"check_callback": true
},
"plugins": ["dnd"]
});
$('button').click(function () {
var ref = $('#tree').jstree(true),
sel = ref.get_selected();
if (!sel.length) {
return false;
}
sel = sel[0];
sel = ref.create_node(sel);
if (sel) {
ref.edit(sel);
}
});
According to the jstree documentation
"The minimal required markup is a < ul > node with some nested < li > nodes with some text inside."
-> http://www.jstree.com/docs/html/
As long as you make the menu using UL and LI it should do the rest for you (as in creating the tree).
So basically, if you remove the text from the LI and UL nodes and make your own text, duplicate the structure, you could make something like this:
-> http://jsfiddle.net/fuu94/3/
but the minimum requirements is something like:
<ul>
<li></li>
</ul>
and if you want to use a submenu, add one of these :
<li> Title Here
<ul>
<li></li>
<li></li>
</ul>
</li>

How to get the items inserted in the DOM using DOMNodeInserted

I want to get the values of items in a Dynamically generated DOM using DOMNodeInserted.
Here is my code.The items #I want to get the values are li eg
<div id="demo">
<ul>
<li class="req">Chemistry</li>
<li class="req">English</li>
<li class="req">Maths</li>
</ul>
</div>
Here is the code
$('#demo').on('DOMNodeInserted', function(e) {
var that = $(this);
if ($(e.target).is('.req')) {
alert(oneoftheitemsintheli);
}
});
I want to get on of the items in the li eg Maths, Chemistry etc. I need to know how to get the items.
Thanks
Given that each li has the class req, you can use each to iterate over them and get the text value - or any other property you need.
$('#demo').on('DOMNodeInserted', function(e) {
$('.req').each(function() {
alert($(this).text());
});
});
Example fiddle

Access Elements After Append

I need to access DOM elements after JQuery append. Let's say I have this:
<ul id="items">
<li class="item">one</li>
<li class="item">two</li>
</ul>
Then is Javascript:
var addItems = function(html) {
$('#items').append(html);
//How do I access the new items here?
}
Let's say that html is:
<li class="item">three</li>
<li class="item">four</li>
I need to do something to the two new items. This something includes binding events to them. So I cannot simply use $('.item') because that will add double events to the existing items. Once the new items are part of the DOM, there is nothing about them that distinguishes them from the existing items.
What's the best way to do this?
Make a jQuery collection of the html before appending it:
var addItems = function(html) {
var $items = $(html);
$('#items').append($items);
$items.foo();
}
Here's a working example: http://jsfiddle.net/hunter/7UTA2/
var addItems = function(html) {
var $html = $(html);
$('#items').append($html);
$html.text("test");
}
This showcases that you still can manipulate the text (or whatever attribute) of the items since you still have a reference to the collection.

Categories

Resources