Jquery Clone() inner HTML attributes not changing - javascript

I have the following code, and when the function Add2List() is executed, it appends the template without having the changes made.
Whats wrong here?
<script type="text/javascript">
function Add2List(data, index){
var $list_item = $('#list-template').clone();
$list_item.find('.box-list').attr("id", "list_"+data.id);
$list_item.find('a.list_link').attr("href", data.link);
$list_item.find('.list_photo').attr("src", data.photo);
$('#listings_list').append($list_item.html());
console.log($list_item.html());
}
</script>
<script id="list-template" type="text/x-custom-template">
<div class="box-list">
<a class="list_link" href="#">
<img src="" class="list_photo">
</a>
</div>
</script>

You're cloning the <script> tag instead of the html inside. Use $( $('#list-template').html() ) instead (demo)
function Add2List(data, index){
var $list_item = $($('#list-template').html());
$list_item.attr("id", "list_"+data.id);
$list_item.find('a.list_link').attr("href", data.link);
$list_item.find('.list_photo').attr("src", data.photo);
$('#listings_list').append($list_item);
console.log(data, $list_item.html());
}

I believe the issue is with jquery not handling the html correctly because it is inside the script tag (or it is a DOM issue).
Doing
var $list_item = $('<div>', {
html: $('#list-template').html()
});
instead of cloning it fixes the problem.
What it does is to create a div element in memory that holds the contents of the template (and work on that thereafter).

Use .filter('#list-template') before find will solve the problem since you're trying to find the current root element in your $list_item variable that is a .box-list :
function Add2List(data, index){
var $list_item = $('#list-template').clone();
$list_item.filter('#list-template').find('.box-list').attr("id", "list_"+data.id);
$list_item.filter('#list-template').find('a.list_link').attr("href", data.link);
$list_item.filter('#list-template').find('.list_photo').attr("src", data.photo);
$('#listings_list').append($list_item.html());
console.log($list_item.html());
}
Hope this helps.

This is because your cloned object is not attached to anything. jQuery's .find runs on an object that exists.
You can do this via a preg_match but since you are templating - the best thing to use is Handlebars.

Related

Why can't I retrieve "this" dom element without onclick?

I have a very basic question about using the "this" keyword to retrieve a DOM element.
Consider the following HTML/Javascript:
<div class="container">
<div class="regular-div">
<script type="text/javascript">
console.log(this);
</script>
Here is a div withOUT onclick
</div>
<div class="onclick-div" onclick="console.log(this)">
Here is a div with onclick
</div>
</div>
While clicking the "onclick-div" it does return the DOM object for that div. However, the console.log event calls 'this' indirectly in the "regular-div" and returns window.
Is it possible to get "this" DOM object when 'this' is called indirectly? My purpose is I want to fire a function in line in the HTML, but need to send the function "this". Here's an example of what i'm trying to do:
<div class="container">
<div class="regular-div">
<script type="text/javascript">
loadSomeHTML(this, varA, varB, varC);
</script>
</div>
</div>
Thanks everyone for any clarification of how "this" works in the above context.
In your first example, the script isn't in any way associated with the div. It's just been output within the div, but it's not connected to it. The script runs as the page is being parsed.
Is it possible to get "this" DOM object without a user interaction?
If you mean inline with the parsing of the HTML, you could do this:
<div class="container">
<div class="regular-div">
Here is a div withOUT onclick
</div>
<script type="text/javascript">
(function() {
var list = document.querySelectorAll('div');
console.log(list[list.length - 1]);
})();
</script>
</div>
Note that the script tag is immediately after the ending </div> tag for the div you're trying to target. The script gets what's currently the last div in the document as of when the script runs. Or of course you could identify the div in some way (a class, for instance) and use that (and then potentially remove it so you could do it again later in the document).
It looks dodgy, but it's perfectly valid cross-browser, and was even recommended at one stage by the Google Closure Library engineers.
Live Example:
<div class="container">
<div class="regular-div">
Here is a div withOUT onclick (look in console for result)
</div>
<script type="text/javascript">
(function() {
var list = document.querySelectorAll('div');
console.log(list[list.length - 1]);
})();
</script>
</div>
Example using a class we move:
<div class="container">
<div class="target-me">
The first div
</div>
<script type="text/javascript">
(function() {
var div = document.querySelector(".target-me");
div.classList.remove("target-me");
console.log(div);
})();
</script>
<div class="target-me">
The second div
</div>
<script type="text/javascript">
(function() {
var div = document.querySelector(".target-me");
div.classList.remove("target-me");
console.log(div);
})();
</script>
</div>
Note I didn't use id, because if we used an id and JavaScript wasn't enabled, we'd end up with an invalid document (because it would have multiple elements with the same id). It'd be fine if JavaScript were enabled (because we'd remove the id from earlier ones before later ones were created), but...
Javascript has no implicit connection to the HTML DOM. The reason why onclick works the way you want is because the HTML DOM implementation passes the element to the js callback. You need to do something similar in your other case. One way to do this is:
<div class="container">
<div class="regular-div" id="mydiv">
<script type="text/javascript">
loadSomeHTML("#mydiv", varA, varB, varC);
</script>
</div>
</div>
Then your js implementation does the lookup to find the element:
function loadSomeHTML(selector, varA, varB, varC) {
var el = document.querySelector(selector);
// now el is where you want to insert your HTML
// ...
}
The code inside the script tag doesn't have any connection with the tag itself. this should, basically, return the object on which the current function was called, or the global environment, window. In the first div, the code is just executed, on no object, so window is returned. The value of onclick, on the other hand, is treated as a function (with even some parameters, like e), that gets called on the element with the attribute. So, the code in the script element is executed in the global scope, whereas the one in the attribute is in a function scope (that's why all vars are shared across script tags).
As explained in How may I reference the script tag that loaded the currently-executing script?, the proper way of obtaining a reference to the script element whose code is being executed is
document.currentScript;
Then, to get the parent node of that element, use
document.currentScript.parentNode;
<div class="container">
<div id="regular-div">
<script type="text/javascript">
alert('#' + document.currentScript.parentNode.id);
</script>
Here is a div withOUT onclick
</div>
</div>

how to convert an html script into a .js file script

would like to place the script into a .js file that opens already with
$(document).ready(function() {
});
I have tried but it feel slike because im putting the onMouse over command into the html I don't think it will be possible?
<head>
<style>
div > p {
cursor: pointer;
}
</style>
<script>
var monkeySrc = "http://icons.iconarchive.com/icons/martin-berube/animal/256/monkey-icon.png";
var lionSrc = "http://icons.iconarchive.com/icons/martin-berube/animal/256/lion-icon.png";
var treeSrc = "http://totaltreeworks.co.nz/wp-content/uploads/2011/02/Tree-256x256.png";
var falconSrc = "http://icons.iconarchive.com/icons/jonathan-rey/star-wars-vehicles/256/Millenium-Falcon-01-icon.png";
function changeImage(src){
document.getElementById("myImage").src = src;
}
</script>
</head>
<body>
<div class="images">
<img id="myImage" width="256" height="256">
</div>
<div>
<p onmouseover="changeImage(monkeySrc)">Monkey are funny!</p>
</div>
<div>
<p onmouseover="changeImage(lionSrc)">Lions are cool!</p>
</div>
<div>
<p onmouseover="changeImage(treeSrc)">Trees are green!</p>
</div>
<div>
<p onmouseover="changeImage(falconSrc)">Falcons are fast!<p>
</div>
</body>
</html>
If you were to take your existing JavaScript and place it in an external file, it would work just fine. It would work because all of your variables and your function would be in the global scope.
Going one step further you'll want to move those onmouseover event handlers into the JavaScript itself.
Given a small change to your current HTML and assuming jQuery you could do something like the following:
<p data-kind="monkey">Monkey are funny!</p>
then
var urlMap = {
monkey : 'http://icons.iconarchive.com/icons/martin-berube/animal/256/monkey-icon.png'
...
};
$('p').on('mouseover', function () {
var kind = $(this).data('kind');
var url = urlMap[kind];
changeImage(url);
});
which you would then be able to wrap in the $(document).ready, the shorthand for which is just $(function () { /* The code from above here */ });
You would need to bind the event handlers programmatically from within the .js file. jQuery would make this very simple and allow you to use arbitrary CSS selectors, but you can do the same in pure JS using e.g. document.getElementById and document.addEventListener.
You can bind the function to the event using Javascript addEventListner
1- Add id attribute to each of your paragraphs tags
<p id="p1"> .....</p>
2- Grab a variable that points to each of those
var p1 = document.getElementById('p1');
3- add event listner
p1.addEventListener("mouseover", changeImage(monkeySrc));
If you put your javascript code in another file and replace <script>...</script> with <script src="javascriptcodefilename.js"></script> in your HTML file, it still works as intended.
Example: http://codepen.io/anon/pen/waLqxz
It might be cleaner to add all of your urls to an array where the key is the name of the link, so you would have something like urls['lionSrc'] = "www.xyz.com";...
then in your changeImage function you would do document.getElementById("myImage").src = url[src];
this way you could even check to see if the image exists already, and if not, show an "image not found" icon.

How to add text from span tag to data-attr by jQuery?

How to add text from span tag to data-attr?
Example:
I have this code
<div class="clearfix colelem" id="u92-5"><!-- content -->
<p>Icon<span id="u92-2">iconsymbol</span></p>
</div>
And I want to add iconsymbol to data-attr="iconsymbol" of the same element like a:
<div class="clearfix colelem" id="u92-5" data-attr="iconsymbol"><!-- content -->
<p>Icon<span id="u92-2">iconsymbol</span></p>
</div>
Yes and it will be with all elements which has a title="icon"
<script>
$( document ).ready(function() {
$("[title*='icon']").attr('data-attr',function(){
// I don't know
}).removeAttr('title');
});
</script>
Do you know how to do it?
So I know it is very simple but I am new in jquery and I need in your help.
I hope you understood my question.
Here is an example that should work for you. There is probably a few ways you can pull this off, but this should hopefully get you started. Please see the attached JSFiddle to see this example in action
$(function() {
$('[title*="icon"] span').each(function(){
$(this).parent().closest('div').attr('data-attr', $(this).text())
});
});
Here is another way you can do this as well
$('[title*="icon"]').each(function(){
$(this).attr('data-attr', $(this).children().closest('span').text());
});
JSFiddle Example
Your <div>s should have attribute title="icon"
You are using a callback to attr() function, so return the value which you need to set inside the function using .text().
$(document).ready(function () {
$("[title='icon']").attr('data-attr', function () {
return $(this).find('span').text();
}).removeAttr('title');
});
Demo

How to store a HTML snippet and insert it later in the document?

Is there a way to store a HTML snippet in a variable using Javascript or jQuery like this? (obviously it's a non-working an example)
var mysnippet = << EOF
<div class="myclass">
<div class="anotherclass">
Some dummy text
</div>
</div>
EOF
And then insert it in the document using jQuery:
mysnippet.append($('#someelement'));
EDIT:
Please, read this before answering of commenting: What I have is a raw HTML snippet inside my JS file, and I need to store it in a Javascript variable using something like that EOF construction. I need to avoid putting it between quotation marks.
If it's not possible using Javascript and/or jQuery, then the question has no solution.
Just get the HTML code of the div you want by var content = $('#somediv').html(); and then append it to some div later on ! $('#otherdiv').append(content);
$().html(); delivers the HTML Content of that div. documentation: http://api.jquery.com/html/
$().append(<content>); appends the Content to a special div. documentatoin: http://api.jquery.com/append/
You could use javascript templates like ejs and haml-coffee.
You could write:
var mysnippet = "<div class='myclass'>"+
"<div class='anotherclass'>"+
"Some dummy text"+
"</div>"+
"</div>";
and then insert is using the append function (which takes the snippet as argument).
Yes. Fiddle example
JavaScript
var html = '<b>Bold</b>'
$('.anotherclass').append(html);
HTML
<div class="myclass">
<div class="anotherclass">
Some dummy text
</div>
</div>
Unfortunately nothing like << EOF is available. Here's one solution:
$el = $('<div />')
.addClass('myClass')
.append(
$('<div />')
.addClass('anotherclass')
.text('Foo Bar')
);
Thinking on the same issue I have found this discussion. What I have in mind is to put a hidden textarea, containing the html, and then retrieving the html from there.
Thus there will be no conflicts with doubled DOM ids, since textarea content isn't rendered as html.
For those who come across this as I have...
You may wish to use the new
<template>
tag in HTML5.
It still doesn't store the HTML in the JavaScript unfortunately :(

best way to inject html using javascript

I'm hoping that this isn't too subjective. I feel there is a definitive answer so here goes.
I want to create this html on the fly using JS (no libraries):
Play
Mute
<div id="progressBarOuter">
<div id="bytesLoaded"></div>
<div id="progressBar"></div>
</div>
<div id="currentTime">0:00</div>
<div id="totalTime">0:00</div>
using javascript. I know I can do this using createElement etc but it seems extremely long winded to do this for each element. Can anyone suggest a way to do this with more brevity.
I do not have access to a library in this project....so no jquery etc.
Keep your markup separate from your code:
You can embed the HTML snippets that you'll be using as hidden templates inside your HTML page and clone them on demand:
<style type="text/css">
#templates { display: none }
</style>
...
<script type="text/javascript">
var node = document.getElementById("tmp_audio").cloneNode(true);
node.id = ""; // Don't forget :)
// modify node contents with DOM manipulation
container.appendChild(node);
</script>
...
<div id="templates">
<div id="tmp_audio">
Play
Mute
<div class="progressBarOuter">
<div class="bytesLoaded"></div>
<div class="progressBar"></div>
</div>
<div class="currentTime">0:00</div>
<div class="totalTime">0:00</div>
</div>
</div>
Update: Note that I've converted the id attributes in the template to class attributes. This is to avoid having multiple elements on your page with the same ids. You probably don't even need the classes. You can access elements with:
node.getElementsByTagName("div")[4].innerHTML =
format(data.currentTime);
Alternatively, you can act on the HTML of the template:
<script type="text/javascript">
var tmp = document.getElementById("tmp_audio").innerHTML;
// modify template HTML with token replacement
container.innerHTML += tmp;
</script>
Shove the entire thing into a JS variable:
var html = 'Play';
html += 'Mute';
html += '<div id="progressBarOuter"><div id="bytesLoaded"></div><div id="progressBar"></div></div>';
html += '<div id="currentTime">0:00</div>';
html += '<div id="totalTime">0:00</div>';
Then:
document.getElementById("parentElement").innerHTML = html;
if you want theN:
document.getElementById("totalTime").innerHTML = "5:00";
You can use
<script type="text/javascript">
function appendHTML() {
var wrapper = document.createElement("div");
wrapper.innerHTML = '\
Play\
Mute\
<div id="progressBarOuter"> \
<div id="bytesLoaded"></div>\
<div id="progressBar"></div>\
</div>\
<div id="currentTime">0:00</div>\
<div id="totalTime">0:00</div>\
';
document.body.appendChild(wrapper);
}
</script>
If you live in 2019 and beyond read here.
With JavaScript es6 you can use string literals to create templates.
create a function that returns a string/template literal
function videoPlayerTemplate(data) {
return `
<h1>${data.header}</h1>
<p>${data.subheader}</p>
Play
Mute
<div id="progressBarOuter">
<div id="bytesLoaded"></div>
<div id="progressBar"></div>
</div>
<time id="currentTime">0:00</time>
<time id="totalTime">0:00</time>
`
}
Create a JSON object containing the data you want to display
var data = {
header: 'My video player',
subheader: 'Version 2 coming soon'
}
add that to whatever element you like
const videoplayer = videoPlayerTemplate(data);
document.getElementById('myRandomElement').insertAdjacentHTML("afterbegin", videoplayer);
You can read more about string literals here
edit: HTML import is now deprecated.
Now with Web Components you can inject HTML using an HTML import.
The syntax looks like this:
<link rel="import" href="component.html" >
This will just load the content of the html file in the href attribute inline in the order it appears. You can any valid html in the loaded file, so you can even load other scripts if you want.
To inject that from JavaScript you could do something of the likes of:
var importTag = document.createElement('link');
importTag.setAttribute('rel', 'import');
importTag.setAttribute('href', 'component.html');
document.body.appendChild(importTag);
At the time I am writing this, Chrome and Opera support HTML imports. You can see an up to date compatibility table here http://caniuse.com/#feat=imports
But don't worry about browsers not supporting it, you can use it in them anyway with the webcomponentsjs polyfill.
For more info about HTML imports check http://webcomponents.org/articles/introduction-to-html-imports/
If you don't need any validation for your syntax (which is what makes createElement() so nice) then you could always default to simply setting the innerHTML property of the element you want to insert your markup inside of.
Personally, I would stick with using createElement(). It is more verbose but there are far less things to worry about that way.
If performance is a concern, stay away from innerHTML. You should create the whole object tree using document.createElement() as many times as needed, including for nested elements.
Finally, append it to the document with one statement, not many statements.
In my informal testing over the years, this will give you the best performance (some browsers may differ).
If HTML is ever declared in a variable, it should be simple and for a very specific purpose. Usually, this is not the right approach.
here's 2 possible cases :
Your HTML is static
Your HTML is dynamic
solution 1
In this case, wrap your HTML in double quotes, make it a string and save it in a variable. then push it inside HTML, here's a demo 👇
HTML
<div id="test"></div>
JavaScript
let selector = document.querySelector("#test");
let demo_1 = "<div id='child'> hello and welcome</div>"
selector.innerHTML = demo_1;
solution 2
In this case, wrap your HTML in back ticks, make it a template literal and save it in a variable. then push it inside HTML,
here, you can use variables to change your content. here's a demo 👇
HTML
<div id="test"></div>
JavaScript
let selector = document.querySelector("#test");
let changes = 'hello and welcome'
let demo_1 = `<div id='child'>${changes}</div>`
selector.innerHTML = demo_1;
You can concatenate raw HTML strings (being careful to escape text and prevent XSS holes), or you can rewrite jQuery (or something similar)
I have a situation where I pass text into a third party library, but if my model isPrivate, I'd like to add an element to the text.
return { id: item.id, text: (item.isPrivate == true) ? "<i class=\"icon-lock\" title=\"Private group.\"></i> " + item.label : item.label };
This creates issues with the way the third party library builds up its markup.
This is never a good idea, but third party libraries are there so that we don't have to write everything ourselves. In a situation like this, you have to rely on passing markup though javascript.
When i find a proper solution to this, I will give you an update

Categories

Resources