HTML elements in template strings in JS - javascript

I have problem with adding HTML elements in my template string. I want to add new lines in my <li> element, but <br> is interpreted like string.
let movieDescription = document.createTextNode(`${moviesData[i].title} <br> ${moviesData[i].year} <br> ${moviesData[i].genre} <br>${moviesData[i].summary}`);
How can I add <br> element in template string?

As you have already been informed, <br> is HTML not text. So you'll need to parse the Template Literal in order to render line breaks correctly. The most common way to do it is by using the property .innerHTML, although I've read plenty of posts and blogs about how crappy it is, I've never had a problem with it. In this example, we are using insertAdjacentHTML() (note the template literal has <div>s and <hr>s):
var movieDescription = `
<hr>
<div>Title: ${moviesData[i].title}</div>
<div>Year: ${moviesData[i].year}</div>
<div>Genre: ${moviesData[i].genre}</div>
<div>Summary: ${moviesData[i].summary}</div>
<hr>`;
document.querySelector('.dock').innerHTML = movieDescription;
An alternative method is insertAdjacentHTML(). It's like innerHTML on steroids.
Pros:
it's faster and safer than innerHTML
it allows us to specifically determine where the insertion should be relating to the target element:
beforebegin: inserted HTML <div>target element</div>
afterbegin: <div> inserted HTML target element</div>
beforeend: <div>target element inserted HTML </div>
afterend: <div>target element</div> inserted HTML
It doesn't overwrite content like innerHTML does.
Cons:
It's verbose.
Demo
var dock = document.querySelector('.dock');
var i;
var moviesData = [{
title: 'Pulp Fiction',
year: '1994',
genre: 'Drama-Crime',
summary: "You will know , my name is the Lord, when I lay my vengance upon thee!"
}, {
title: 'Reservoir Dogs',
year: '1992',
genre: 'Drama-Crime',
summary: "Clowns to the left of me, jokers to the right! Here I am stuck in the middle with you"
}];
for (i = 0; i < moviesData.length; i++) {
var movieDescription = `
<hr>
<div>Title: ${moviesData[i].title}</div>
<div>Year: ${moviesData[i].year}</div>
<div>Genre: ${moviesData[i].genre}</div>
<div>Summary: ${moviesData[i].summary}</div>
<hr>`;
dock.insertAdjacentHTML('beforeend', movieDescription);
}
<div class='dock'></div>

A text node contains... well... text. It does not contain other html elements, and thus when you create one it will interpret the <br> as text and display it as is.
What you want would be a collection of TextNodes and HTMLBRElement.
const movieDescription = [
document.createTextNode(moviesData[i].title),
document.createElement('br'),
document.createTextNode(moviesData[i].year),
document.createElement('br'),
document.createTextNode(moviesData[i].genre),
document.createElement('br'),
document.createTextNode(moviesData[i].summary)
];
That is quite awkward to do. Instead, you probably want to use Element.innerHTML on the element you want to add this description to.
const html = `${moviesData[i].title} <br> ${moviesData[i].year} <br> ${moviesData[i].genre} <br>${moviesData[i].summary}`;
document.querySelector('.my-movie-description').innerHTML = html;
A similar method exists to add a single TextNode to an element. This is Element.innerText.

I have witten a html templating engine to render dynamic data at browser.
Codepen example
var moviesData = [];
for(var i = 0; i < 10; i++){
moviesData.push( {
"title" : "title " + i,
"year" : 2000 + i,
"genre" : "action",
"summary" : "summary " + i
});
}
body {
background-color: #a3d5d3;
}
.movie {
margin: 0.5em 1em ;
padding : 0.2em 0.5em;
border: 1px solid;
}
<div jstl-autorun jstl-foreach="${moviesData}" jstl-foreach-var="movieData">
<div class="movie">
${movieData.title}
<br/>
${movieData.year}
<br/>
${movieData.genre}
<br/>
${movieData.summary}
</div>
</div>
here is the link for the template engine
I hope it's useful for you.

Related

How to update some portion of a td title jquery

on ajax success, I have to update some portion of the title.
I am extracting the current td title as:
//with this I could get the current td title
let tdTitle = $('.amenity-review-table').find("td[data-unitid='"+resp.unit.id+"']").attr('title');
and consoling this tdTitle gives:
<div class='unit-title'><strong>Unit: 101</strong></div><span class=''>Washer/Dryer = <span>1</span></span></br><div class='sm-box unit-note-color d-inline-block'></div><span class='unit-note-popup'>note added 3</span>
Now, on ajax success I will receive the new updated title and this can be accessed via:
resp.unit.unit_note, now once I receive the update I have to update the note shown on the title of td. So, in above case:
I have to update the text inside unit-note-popup class to new note which could be received on resp.unit.note. So the final title looks like:
<div class='unit-title'><strong>Unit: 101</strong></div><span class=''>Washer/Dryer = <span>1</span></span></br><div class='sm-box unit-note-color d-inline-block'></div><span class='unit-note-popup'>"+resp.unit.unit_note+"</span> //my syntax could be wrong here, but this is what I needed
Update:
Here, is the jsfiddle to reproduce the scenario:
http://jsfiddle.net/a3t7yfe2/1/
You'll need to parse the HTML in the title attribute into something you can work with (like a jQuery object).
Then you can manipulate the .unit-note-popup text and write the HTML back into the attribute
// Mock data
const resp = {
unit: {
id: 1,
note: "Note added 4!"
}
}
const td = $(`.amenity-review-table td[data-unitid="${resp.unit.id}"]`)
const title = td.attr("title")
const titleEl = $(`<div>${title}</div>`) // parse into an element
titleEl.find(".unit-note-popup").text(resp.unit.note)
td.attr("title", titleEl.html())
/* Make the title attribute visible */
td[data-unitid]:after {
display: block;
color: red;
content: attr(title);
margin: 1rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="amenity-review-table">
<tr>
<td data-unitid="1" title="<div class='unit-title'><strong>Unit: 101</strong></div><span class=''>Washer/Dryer = <span>1</span></span><br/><div class='sm-box unit-note-color d-inline-block'></div><span class='unit-note-popup'>note added 3</span>">
Check out my super awesome HTML title
</td>
</tr>
</table>
Here I've wrapped the title HTML text in a <div> so that it's encapsulated in a single parent element. That way, you can get the inner HTML back for writing the new value.

Get innerHTML from same tags

I am having a trouble for fetching innerHTML of the following two strong tags
<div>
<strong>data 1</strong>
<span class="and">and</span>
<strong>data 2 </strong>
</div>
<div>
<strong>data 3</strong>
<span class="and">and</span>
<strong>data 4 </strong>
</div>
i want to get data1, data2 in console but i'm unable to achieve anything.
I have tried document.querySelector("strong") but it just provide me data1.
How can i fetch data2 data3 & data4 from other strong tag?
Any help is appreciated.
i know i can do
document.getElementsByTagName("strong")['increment_operator'].innerHTML;
and
document.querySelectorAll("strong");
querySelector finds the first result and stop searching whereas querySelectorAll finds all.
Try code below to log html of strong tag:
var elems = document.getElementsByTagName('strong');
for (i=0;i < elems.length;i++{
console.log(elems[i].innerHTML)
}
To get innerHTML of the last strong tag in html run code below:
var elems = document.getElementsByTagName('strong')[:1];
console.log(elems[elems.length-1].innerHTML);
If you have same tag and you want specific tag innerHTML then give unique ids and then try to fetch or if you want to fetch all strong tag innerhtml then use queryselectorall()
As example
<div>
<strong>data 1</strong>
<span class="and">and</span>
<strong>data 2 </strong>
</div>
<div>
<strong>data 3</strong>
<span class="and">and</span>
<strong>data 4 </strong>
</div>
var a = document.querySelectorAll("strong");
for (var i = 0; i < a.length; i++) {
alert(a[i].innerHTML);
}
Summing up the partials:
The document.querySelector(commaSeperatedStringOfSelectors) only finds the first node in the documentsatisfying the selectors it is given. So you need to be more specific with it, need to supply some queryable selectors to your html elements, like id class.
But if you want to select more widely follow:
document.querySelectorAll(commaSeperatedStringOfSelectors) to get an array of all the nodes satisfying the selectors. Then you can select the element you need by index. fiddle
Or you need to use #Andriy Ivaneyko's answer style, use getElementByTagName('tagname'), getElementsByClassName('class'), or getElementById('id').
Note: document.querySelectorAll(commaSeperatedStringOfSelectors) is more versatile, it gives you opportunity to be both more specific or more unspecific. You can use a string like that in it: 'strong, div.animals, a'.
Ok i did my job by doing following.
var divLength = document.getElementsByTagName("div").length;
var z = 0;
for(i=0; i<divLength; i++){
var dataFromFirstStrong = document.getElementsByTagName("strong")[z].innerHTML;
z++;
var dataFromSecondStrong = document.getElementsByTagName("strong")[z].innerHTML;
z++;
}

Replacing divs that can be replaced in html/javascript

Hi i'm trying to replace some divs with other divs, this works fine but when i try to replace the second load of divs they don't change anymore.
Basicaly I'm trying to create a "winetour" that lets a user choose some options and generates the perfect wine to go along with it.
You get presented with a couple of options (img links) and if you click one the div's content changes and presents another set of clickable images taking you deeper in your process of choosing a great wine.
HTML:
<div id"Gelegenheid">
<img src="Images/Ontbijt.jpg" id="ontbijt" alt="Ontbijt">
<img src="Images/Borrel.jpg" id="borrel" alt="Borrel">
<img src="Images/Dinner.jpg" id="feest" alt="Diner">
<img src="Images/Feest.jpg" id="diner" alt="Feest">
</div>
<div id"Ontbijt" style="display: none"> Some content that shows trough the "tour"</div>
<div id"Borrel" style="display: none"> Some content that shows trough the "tour"</div>
<div id"Dinner" style="display: none">
<img src="Images/White.jpeg" id="ontbijt-licht" alt="ontbijt-licht">
</div>
<div id"Dinner-detail-voor" style="display: none"> Some content that shows trough the "tour"</div>
<div id"Dinner-detail-head" style="display: none"> Some content that shows trough the "tour"</div>
JavaScript:
function continueTour(i) {
if (i==1) {
document.getElementById("Gelegenheid").innerHTML = document.getElementById("Ontbijt").innerHTML;
} else if (i==2) {
document.getElementById("Gelegenheid").innerHTML = document.getElementById("Borrel").innerHTML;
} else if (i==3) {
document.getElementById("Gelegenheid").innerHTML = document.getElementById("Diner").innerHTML;
} else if (i==4) {
document.getElementById("Gelegenheid").innerHTML = document.getElementById("Feest").innerHTML;
} else {
document.getElementById("Dinner").innerHTML = document.getElementById("Dinner-detail-voor").innerHTML;
}
}
So basically if you click on a link that's inside the "Gelegenheid" div you will be taken to for example Dinner, but the problem is, inside dinner there are some more links and i want to link them for example to "Dinner-detail-voor"
I want to make this working with core JavaScript (so no JQuery) but i don't know what's going on?
Thanks in advance!
Found the answer.
Added
document.getElementById("from").style.display = "none" ;
document.getElementById("to").style.display = "table" ;
to each of the javscript index functions, now it works where 'from' is the father and 'to' is the child that is being linked to, not very neat but it works,
If someone has a shorter or alternative solution feel free to post!
first we create an array for all the content, array is base 0 so we start from function myFunction(0); next we create a tag with updated variable in them. the if statement is use to reset the variable when hit max. hope this help.
http://jsfiddle.net/xgay3f83/3/
function continueTour(i) {
var content = ['content 1', 'content 2', 'content 3', 'content 4'];
var target = document.getElementById('target');
var next = i + 1;
var end = content.length;
if(next>end) {
i = 0;
next = 1;
}
var openTag = '<a href="#" class="hvr-grow" onClick = "continueTour('+next+')">';
var closeTag = '</a>';
target.innerHTML = openTag+content[i]+closeTag;
}

Recursively get all HTML between two elements - excluding closing tags - in Javascript/Node.js

I need to be able to store certain elements separately in a database, but on retrieval rebuild the HTML for display. Our solution to this (open to suggestions) is to store leadingHTML and trailngHTML properties of the entry.
This should provide us the ability to be as flexible as we want-- but there's just one catch. I'm banging my head against the wall trying to write the code to parse the HTML. Take the following HTML for example:
<h1>this is leadingHTML</h1>
<h2>this is leadingHTML2</h2>
<p class='select' id='1'>A1</p>
<h1 >this is trailngHTML</h1>
<h2>this is trailngHTML2</h2>
<p class='select' id='2'>A2</p>
<h1>this is trailngHTML3</h1>
<h2>this is trailngHTML4</h2>
<p class='select' id='3'>A3</p>
<figure id='fig'>
<figCaption>
this is some text
<span class='select'>B1</span>
<div>some text <span class='select'>B2</span></div>
</figCaption>
<img class='select' alt='test' src='test.jpg'/>
<img class='select' alt='test' src='test.jpg'/>
<img class='select' alt='test' src='test.jpg'/>
</figure>
<p class="select">A4</p>
It's easy to get all the elements with class "select." But I could really use help getting the string of HTML to go between those elements. For the the element <p class='select' id='3'>A3</p> , I need a function that can return to me the following string:
values:
element
<p class='select' id='3'>A3</p>
leadingHTML
leadingHTML= '<h1>this is trailngHTML3</h1><h2>this is trailngHTML4</h2>'
trailingHTML
trailingHTML= '<figure id='fig><figCaption>this is some text'
This way, I can store the elements the way that is required of the project but still reconstruct the HTML for display.
We are using Node.js for a backend, so this will need to be written in Javascript. After lots of frustration, I'm pretty convince there's no way to do this without some ugly code?
Any help is much appreciated.
So far, this is what I've got (can't say I'm proud):
var checkChildren = function walk(node,state,func){
if (state.isPt===false){
var state=func(node,state);
}
else if(state.isPt===true){
return state;
}
node=$(node).children().first();
while (node.length>0 && state.isPt!==true){
state=walk(node,state,func);
node=$(node).next();
}
return state;
};
function getTrailing(start,html){
var checkFind = $(start).find('.pt');
if (checkFind.length>0){
//selector is in the child somewhere
state= { html: html, isPt: false};
var getChildHTML = checkChildren(start,state,function(node,state){
if ($(node).is($(checkFind).first())){
return { html: html, isPt: true,};
} else{
html=html+'<'+$(node)[0].name;
for (var key in $(node)[0].attribs){
html=html+" "+key+"='"+$(node)[0].attribs[key]+"'";
};
html=html+'>';
return { html: html, isPt: false,};
}
});
return getChildHTML;
} else{
return html;
}
}
var start1 = $("#fig");
var html = '';
test=getTrailing(start1,html);
and it's returning this:
{ html: '<figure id=\'fig\' class=\'test\' style=\'color:red;\'><figcaption class=\'test\' style=\'color:red;\'><span><div>',
isPt: true }
Update
To clarify-- the output may be invalid HTML. I simply need string of all the HTML between two elements of interest. If the second element of interest is a descendant, then the result will be invalid HTML (since the string is supposed to stop as soon as it finds the next element).

Representing a div as a Javascript object?

I want to show a list of various pets on my page. Each pet would linked to a javascript object representing that pet. This is the code for my Pet class:
function Pet()
{
var id, name, var color, var photo;
this.getHtml = function()
{
// Should return the html of a div representing the pet.
return html;
}
this.buy = function()
{
//Find out whether pet is for sale, show a buy form, etc
}
// Snip
}
Using this object, I want to do this:
var cat = new Pet();
cat.id = 1;
cat.name = 'Cat';
cat.color = 'Black';
cat.photo = 'http://example.com/cat.jpg';
var dog = new Pet();
dog.id = 2;
dog.name = 'Dog';
dog.color = 'White';
dog.photo = 'http://example.com/dog400.jpg';
$(document).append(cat.getHtml());
$(document).append(dog.getHtml());
By running this code, I want to get the following two divs to be added to my page:
<div id="pet_1">
Pet name: Cat <br>
Color: Black <br>
<img src='http://example.com/cat.jpg' alt='Cat' /><br>
<input type='button' value='Buy This Pet' onclick = 'cat.Buy()';/>
</div>
<div id="pet_2">
Pet name: Dog <br>
Color: White <br>
<img src='http://example.com/dog400.jpg' alt='Dog' /><br>
<input type='button' value='Buy This Pet' onclick = 'dog.Buy()';/>
</div>
The questions I have are:
1) What's the best way to write the pet.getHtml() function so that it would produce the above output? I would really prefer to not store the html inside a string within my javascript, rather I'd prefer if a template div could be stored outside the javascript somewhere, and each time that div's html is retrieved, the necessary info inserted, and the html code of the new div is returned.
2) Also, certain elements within the new div (such as the buy button) should be linked to the object that produced them, e.g the 'Buy now' buttons of the cat/dog div call the cat.buy(); and dog.buy(); methods when clicked.
How can this be accomplished?
There are two options here. You can either try a full blown client side MVC system for this. Personally I would recommend you look at backbone it's minimalistic and has a very lightweight View with no rendering/ui defaults.
Or write your own micro MVC system.
As for the views you can use a templating engine like EJS or jQuery tmpl.
An EJS view would be
<div id="<%= id %>">
Pet name: <%= name %><br>
Color: <%= color %><br>
<img src='<%= url %>' alt='<%= name %>' /><br>
<input type='button' value='Buy This Pet'/>
</div>
Then your code would look like :
function render() {
var container = container || $("<div></div>").appendTo(parent);
new EJS({url: view_url}).update(container[0], {
id: this.id,
color: this.color,
url: this.url,
name: this.name
});
var that = this;
container.find(":button").click(function() {
that.buy();
});
}
As for jQuery tmpl
<script id="petTemplate" type="text/x-jquery-tmpl">
<div id="${id}">
Pet name: ${name}<br>
Color: ${color}<br>
<img src='${url}' alt='${name}' /><br>
<input class="buy" type='button' value='Buy This Pet'/>
</div>
</script>
function render() {
var that = this;
$( "#petTemplate" ).tmpl( [{
id: this.id,
color: this.color,
url: this.url,
name: this.name
}] ).appendTo( parent ).find(".buy:button").click(function() {
that.buy();
});
}
Take a look at javascript templates. jQuery has a plugin in beta to accomplish this. Here are the docs.
There is a really good library called Pure that lets you integrate templates into a bunch of javascript frameworks.
Of course there are lots of docs on the subject on Google

Categories