How to select elements from <template> with jQuery - javascript

I have two similar selections. The first uses a <div> tag, which works fine, the second uses a newly <template> tag, which doesn't work anymore.
Can anyone tell me how to get this to work with jQuery using the <template> tag?
HTML
<div id="div">
<div>content</div>
</div>
<template id="template">
<div>content</div>
</template>
JavaScript
var $div = $('#div');
var $content = $div.find('div');
console.log($content); //works ($content.length == 1)
var $template = $('#template');
var $content = $template.find('div');
console.log($content); //doesn't work ($content.length == 0)
http://jsfiddle.net/s8b5w0Le/1/

HTMLTemplateElement saves the DOM into a seperate attribute:
JQuery
<script src="jquery-3.1.0.js"></script>
<script type="text/javascript">
$(document).ready(function()
{
var $div = $('#div');
var $content = $div.find('div');
console.log($content.text()); // output "content", inner div
var $template = $('#template');
var node = $template.prop('content');
var $content = $(node).find('div');
console.log($content.text()); // output "content", inner template
});
JavaScript
document.createElement('template').content

I'm fairly certain this has to do with Chrome's use of shadow dom (thank Polymer... )
You can either try your luck using the /deep/ combinator (probably won't work on other browsers), but I think the most robust solution would be $template[0].outerHTML as in your comment if you just need the text.
If you need jQuery functionality, using $.parseXML (to avoid Chrome's native dom construction) would probably do the trick across all browsers (can confirm Chrome + FF).
Example here: http://jsfiddle.net/3fe9jjfj
var tc = $('#template')[0].outerHTML;
$template = $($.parseXML(tc)).contents();
console.log($template);
console.log($template.find('div'));
Both logs return as we'd expect, and $template can now be treated as an ordinary jQuery object.

As others have noted, Chrome puts <template> child elements into a shadow DOM. To access them:
// Access the JavaScript object for the template content
$('template')[0]
// Make a jQuery selection out of it
$($('template')[0])
// Now you can search it
$($('template')[0]).find('div.someclass').css('color','#000');

A way, too late for the party but I ended up doing this:
function resolveTemplate(id) {
return $(id).contents();
}
...
var $searchIcon = resolveTemplate('#search-icon-template');
$('#div').append($searchIcon);

You can use all the JQuery methods as usual if the element inside the template element are wrapped with a container.
const temp = $("#template").contents().clone();
$(temp).find("h1").text("A dynamic title");
temp.appendTo($("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="app"></div>
<template id="template">
<div class="container">
<h1>lorem ipsum</h1>
<p>lorem ipsum </p>
<img src="" alt="">
</div>
</template>
The container can also be appended dynamically with JQuery. Or if you don't want a container, you can append its content.
const temp = $('<div></div>').html($("#template").contents().clone());
$(temp).find("h1").text('dynamic title');
$(temp).find("p").text('But no container this time');
temp.contents().appendTo($("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="app"></div>
<template id="template">
<h1>lorem ipsum</h1>
<p>lorem ipsum </p>
<img src="" alt="">
</template>

<template>
<div class="template-container">
<div class="content">content</div>
</div>
</template>
var templateHtml = ('#template').html() // this will return the template container div
var template = $(templateHtml);
var content = template.find('.content');
console.log(content);

var $content = $template.content.find('div');
... instead of ...
var $content = $template.find('div');
Worked for me.

HTML5 template is display: none; by default, childNodes in template is invalid, if you inspect it in console you'll find something different

Related

Add all elements after first element to a div by using javascript (No jQuery)

I have the following html
<div id="main">
<aside id="list"><p>sometext</p></aside>
<aside id="list-2"><p>sometext</p></aside>
<aside id="list-3"><p>sometext</p></aside>
<aside id="list-4"><p>sometext</p></aside>
</div>
I want to use javascript to make it look like :
<div id="main">
<aside id="list"><p>sometext</p></aside>
<div id="wrap">
<aside id="list-2"><p>sometext</p></aside>
<aside id="list-3"><p>sometext</p></aside>
<aside id="list-4"><p>sometext</p></aside>
</div>
</div>
I have tried insertAdjacentHTML and innerHTML methods :
widgets = document.getElementById('main');
widgets.innerHTML = "<div class='box-class'>" + widgets.innerHTML + "</div>";
But this adds wrapper over "list" too.
There are two big problems with the code you said you tried (three if widgets isn't declared anywhere):
widgets = document.getElementById('main');
widgets.innerHTML = "<div class='box-class'>" + widgets.innerHTML + "</div>";
Using strings means the browser has to go through the elements, build an HTML string for them, and return that string to JavaScript; then when you assign to innerHTML it has to destroy the elements that are already there and build new replacement ones by parsing the HTML string. This will wipe out any event handlers or similar attached to the elements. (Of course, if there aren't any, it doesn't matter much.)
That wraps all of the children, not just the ones after the first child.
(It also wraps them in <div class='box-class'>, not <div id="wrap">, but...)
On all modern browsers, elements have a children list you can use for this. Then just create a wrapper, move the children other than the first into it, and append it.
var main = document.getElementById("main");
var wrapper = document.createElement("div");
wrapper.id = "wrap";
while (main.children.length > 1) {
// Note: Appending the element to a new parent removes it from its original
// parent, so `main.children.length` will decrease by 1
wrapper.appendChild(main.children[1]);
}
main.appendChild(wrapper);
Example:
var main = document.getElementById("main");
var wrapper = document.createElement("div");
wrapper.id = "wrap";
while (main.children.length > 1) {
wrapper.appendChild(main.children[1]);
}
main.appendChild(wrapper);
#wrap {
border: 1px solid blue;
}
<div id="main">
<aside id="list">
<p>sometext</p>
</aside>
<aside id="list-2">
<p>sometext</p>
</aside>
<aside id="list-3">
<p>sometext</p>
</aside>
<aside id="list-4">
<p>sometext</p>
</aside>
</div>
Side note: In your markup, you have </div> where you want </aside>.

Alternative to x.innerHTML for long texts

I'm trying to write a form in HTML and JS that shows at the end the completed form uneditable for confirmation.
I have to replace the contents of the page without refresh and/or redirection.
My code is:
function F() {
if(...){
//Empty fields [...]
}else{
var el = document.getElementById("formID"); //Form da sostituire
el.innerHTML = "NEW CONTENT";
}
}
The problem is that the "new content" is really long and is very uncomfortable to write it as a string. Are there any alternatives to innerHTML for this situation?
Use the <template> tag. Put the content you want inside a <template> tag, give it an ID, and then in JavaScript simply copy the content of the template inside the form.
HTML:
<template id="form-template">
NEW CONTENT
</template>
JavaScript:
function F() {
if(...){
//Empty fields [...]
}else{
var el = document.getElementById("formID"); //Form da sostituire
el.innerHTML = document.getElementById("form-template").innerHTML;
}
}
See live example in the following snippet:
document.querySelector("button").addEventListener("click", event => {
document.getElementById("content").innerHTML = document.getElementById("my-template").innerHTML
})
<template id="my-template">
<h1>Hello template!</h1>
</template>
<button type="button">Try it!</button>
<div id="content"></div>
For problem of <template> browser support you could use any element as placeholder, like this :
document.querySelector("button").addEventListener("click", event => {
document.getElementById("content").innerHTML = document.getElementById("my-template").innerHTML
})
.template{
display:none;
}
<div id="my-template" class="template">
<h1>Hello template!</h1>
</div>
<button type="button">Try it!</button>
<div id="content"></div>
Or just give display:none to template element :)

How parse DOM to get emails Javascript

I'am building a Chrome extension that parses the entire DOM/HTML and replace any found email(multiple emails) with the following div:
<div class="email_tmp"> found_email <span>SAVE EMAIL</span></div>
EXAMPLE:
<body>
<div>Some Text...</div>
<div>text a#a.com text</div>
<div>Some Text...</div>
<p>More Text</p>
<div><div><span>text b#b.com text</span></div></div>
<span>Last text</span>
</body>
replaced to:
<body>
<div>Some Text...</div>
<div>text <div class="email_tmp"> a#a.com <span>SAVE EMAIL</span></div> text</div>
<div>Some Text...</div>
<p>More Text</p>
<div><div><span>text <div class="email_tmp"> b#b.com <span>SAVE EMAIL</span></div> text</span></div></div>
<span>Last text</span>
</body>
How can I search and replace the found email by the entire div and the string found_email by the email too?
I want to replace only the found email(s) string, nothing more...
I really appreciate any help.
Here is the total solution for what your looking for
HTML
<div id="main">
sdfsdsdfsdfsdf a#a.com sdfsdfsdfsdfsdfsdf
</div>
JavaScript
var page_content = document.getElementById('main').innerHTML;
var found_email = "<div class='email_tmp'> found_email <span>SAVE EMAIL</span></div>";
//gives an array of the emails
var email = page_content.match(/([a-zA-Z0-9._-]+#[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi);
//replaces the emails to your desired content
var result = page_content.replace(email, found_email);
//replaces the changed HTML back to the 'main' div
document.getElementById('main').innerHTML = result;
Here is the Fiddle
Update:
If you want to replace only the text without adding any class or tags to the content of the HTML, then it gets real complicated to write a vanilla script for the same. In that case I would highly suggest you to use this library which I found to be the perfect solution for your problem.
Its a library called findAndReplaceDOMText which uses inbuilt methods to solve the purpose. You just need to give the find(what to find) and replace(replacing HTML) like so,
findAndReplaceDOMText(document.getElementById('t'), {
find: /([a-zA-Z0-9._-]+#[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi,
replace: '<div class='email_tmp'> found_email <span>SAVE EMAIL</span></div>'
});
You can obviously revert if you face any problems in implementing this library.
Also this a must read article for you - replacing-text-in-the-dom-solved
Slight update on #NikhilNanjappa 's original answer: my version is less efficient, but it will keep the actual email address and prepend the div and append the span and closing tags, based on the original answer.
var save_email_beg = "<div class='email_tmp'> ";
var save_email_end = " <span>SAVE EMAIL</span></div>";
var i = 0;
for (; i < email.length; i++) {
var new_string = save_email_beg + email[i] + save_email_end;
page_content = page_content.replace(email[i], new_string);
}
document.getElementById('main').innerHTML = page_content;

JQuery each function to fill array with attributes from HTML images

I'm trying to load an array filled with the src attribute from a series of img tags in my HTML document.
HTML:
<html>
<head>
<title>
JQuery Slider
</title>
<link rel="stylesheet" type="text/css" href="css/main.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script type="text/javascript" src="js/main.js"></script>
</head>
<body>
<div id = "wrapper">
<h1 class="dark-header">2014 Salt Lake Comic Con FanX</h1>
<div id="background-img">
<img src="img/img01.jpg"/>
</div>
<div>
<img src="img/img02.jpg"/>
</div>
<div>
<img src="img/img03.jpg"/>
</div>
<div>
<img src="img/img04.jpg"/>
</div>
<div>
<img src="img/img05.jpg"/>
</div>
<div>
<img src="img/img06.jpg"/>
</div>
<div>
<img src="img/img07.jpg"/>
</div>
<div>
<img src="img/img08.jpg"/>
</div>
<div>
<img src="img/img09.jpg"/>
</div>
<div>
<img src="img/img10.jpg"/>
</div>
</div>
</body>
</html>
JQuery:
$(document).ready(function() {
var source = new Array();
$('img').each(function(attr) {
source.push($('img').attr('src'))
});
console.log(source)
});//end document.ready
The output to the console is an array of 10 elements, but only using the first img attribute. I'm not sure how to get the each function to go through all elements and push them to the array.
Your issue is that $('img').attr('src') will always return the value of the first element in the collection of elements.
As pointed out in comments , you need to look at specific instances within your loop
Another way you can do this is using map() which will create the array for you
var source = $('img').map(function(){
return $(this).attr('src');
}).get();
DEMO
You could try something like this:
var source = [];
$('img').each(function() {
source.push( this.getAttribute('src') );
});
In your each code, you re-select the entire group with $('img') so it is only adding the first one of THAT Selection to your array.
OR
If you aren't using jQuery for anything else, you could do it in straight javascript like this:
document.addEventListener('DOMContentLoaded', getImgAttr);
var source = [];
function getImgAttr() {
var imgs = document.querySelectorAll('img');
[].forEach.call(imgs, function( img ) {
source.push( img.src);
});
}
you need to use 'this' while inside the loop to reference the image, otherwise you are getting the reference to first 'img ' tag.
it should be like this:
$('img').each(function(attr) {
source.push($(this).attr('src'))
});
Your callback function needs to accept a second param...
The first param is the current index of the array and the second param is the object at that index.
You may also utilize the keyword this as suggested above.
Based on my answer your code would look like this:
$('img').each(function(i, img) {
source.push($(img).attr('src'));
// alternatively -> source.push($(this).attr('src'));
});
A second option you may like and puts what you're trying to do onto a single line would be to use the jQuery map function...
var source = $.map($('img'), function(img) { return $(img).attr('src'); });

Javascript - JQuery : Cannot find id and .html("") or getElementById and set the innerHTML

I'm new to jQuery and can't add innerhtml to a div.
I have tried getElementById and also $('').html().
My javascript
var dishes = arg;
var starterDish = dishes[0];
var mainDish = dishes[1];
var dessertDish = dishes[2];
location.href=$('#finishButton').attr('href');
//The new HTML file
alert($('#starterDishName').html());
// will only return unidentified
$('#starterDishName').html(starterDish.name);
$('#starterDishPrep').html(starterDish.description);
$('#mainDishName').html(mainDish.name);
$('#mainDishPrep').html(mainDish.description);
$('#dessertDishName').html(dessertDish.name);
$('#dessertDishPrep').html(dessertDish.description);
run4 = false;
and the finish.html file:
</div>
<div id="starterDishName" align="center"> <h3>blablabla</h3></div>
<div id="starterDishPrep" align="center"> </div>
<div id="mainDishName" align="center"> <h3></h3></div>
<div id="mainDishProp" align="center"> </div>
<div id="dessertDishName" align="center"> <h3> </h3></div>
<div id="dessertDishProp" align="center"> </div>
</div>
I think the problem is located: location.href=$('#finishButton').attr('href');
and that the new html file wont allow me to use the ID's get?
QUESTION:
How can I get the id of the new html file and change the innerhtml of it from my code's perspective?
I assume you have this in a JavaScript file as you wrote: "My .js". And if you have included it in the head-section of your HTML the script is executed immediately and the selectors are not aware of all the HTML elements. Using jQuery you can simply wrap everything into a closure as this will get executed after the DOM is parsed:
$(document).ready(function() {
// your logic goes here
});
var id = document.getElementById('id').innerHTML;

Categories

Resources