I've recently started using the <template> tag for HTML that I process afterwards using a template library, e.g.
<template id="tmpl">
<div class="something">
{{title}}
</div>
</template>
...
<script>
var output = Mustache.render($('#tmpl').html(), {
link: 'abc',
title: 'abc'
});
</script>
However, I've come to realise this means I have a broken link (example.com/pages/{{link}}) in my HTML. This is a concern, as various crawlers might consider it invalid (in fact, the Google Search Console reports my homepage as having a broken link).
Is it valid to use <template> this way?
Is it better to put it in something like <script type="text/template"> instead (as seen on the handlebars.js website)?
The output variable does contain the HTML we would expect, i.e., the rendered template; however, your code does not write the contents of the output variable anywhere.
Here is a working example:
<template id="tmpl">
<div class="something">
{{title}}
</div>
</template>
<span id="output"></span>
<script>
var output = Mustache.render($('#tmpl').html(), {
link: 'abc',
title: 'abc'
});
$('#output').html(output);
</script>
Google has not properly crawled the test site I setup for this. However, when I asked GoogleBot to render my version of your code it displayed the link inside the template element, i.e., *{{title}}* and the rendered template link, i.e., *abc*. Even though Google says you have a broken link in the template element, you really don't when a user views it.
One possible way to get Google to quit indicating that you have a broken link is to surround your template tags with <!--googleoff: anchor--> ...templates... <!--googleon: anchor-->. These tags stop googlebot from indexing anchor tags contained within.
Example:
<!--googleoff: anchor-->
<template id="tmpl">
<div class="something">
{{title}}
</div>
</template>
<!--googleon: anchor-->
Related
I've been reading with interest about the dialog element in HTML:
<dialog id="helpOnName">
<p>
The name is arbitrary. There is no validation, whatsoever.
</p>
</dialog>
So, that's well for this simple text. However, with growing complexity, I'd rather have something like
<dialog url="helpOnName.html"></dialog>
In other words: Rather than embedding the dialog contents into the opening page, I'd like it to be read from another file.
Is that possible? How? (Using JQuery would be fine.)
You may have different options to achieve the goal to have content loaded from an external resource.
Doing an ajax request that will return a response to embed
dynamically in the dialog
Embedding the content inside an <iframe> tag
Referencing the content with an <object> tag
This is the demo for the third and most original option of those.
The content for the <dialog> is specified by an <object> element fed by an url having its content. As a fallback, I added the option that will override its content with a default template defined in the page itself.
<object>: The External Object element
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/object
:scope (worth of mention)
*for selecting only starting from the direct children
https://developer.mozilla.org/en-US/docs/Web/CSS/:scope
This is an answer better covering <iframe> <embed> <object>
Difference between iframe, embed and object elements
And I would add I forgot to mention <link>
document.addEventListener('DOMContentLoaded', ()=>{
const dialog = document.getElementById('primaryDialog');
fillDialogContent(dialog);
})
function fillDialogContent(dialog){
const template = dialog.querySelector(':scope > .fallback');
const content = template.content.cloneNode(true);
const objectEl = dialog.querySelector('object');
objectEl.append(content);
}
<dialog id="primaryDialog" open>
<object data="your-custom-dialog-content.html" type="text/html"></object>
<template class="fallback">
<div class="container">
<p>This is the default dialog content</p>
<p>An error occurred in the attempt to load the custom template</p>
</div>
</template>
</dialog>
Here is another way of doing it with fetch():
document.addEventListener('DOMContentLoaded', function(ev) {
document.querySelectorAll("[data-url]").forEach(el=>
fetch(el.dataset.url).then(r=>r.text()).then(html=>el.innerHTML=html)
)
});
<h3>First dialogue</h3>
<div data-url="https://baconipsum.com/api/?type=all-meat¶s=3&format=html">hello</div>
<h3>Second dialogue</h3>
<div data-url="https://baconipsum.com/api/?type=all-meat¶s=5&make-it-spicy=1&format=html">hello again</div>
I'm pretty new to web design, and I'm trying to build a dashboard for a project. So far, I've got my UI looking like I want it to. It basically consists of a header bar, with a navigation bar on the left side with some options that the user can click on. I want a click on each item to change the content in the central area. The way I thought of was simply to use:
document.getElementById("central text element").innerHTML = "the HTML I want to change it to";
This approach, functionally, does everything I would like. The only problem is, the content I would like to insert is not short. For each of my options, I basically have to create individual HTML documents that I could edit the content in, then run it through a converter like this: https://tomeko.net/online_tools/cpp_text_escape.php?lang=en, then copy it in. As you can probably understand, this method is not very streamlined, as every time I want to make some changes to the code, I have to copy that chunk of code into this converter then paste it into the JavaScript function.
Is there a better way to achieve what I'm trying to do here?
There are several ways to do this:
The <template> element
If you want all the content to be loaded in the page, you can use <template>.
const content1 = document.getElementById("content1").content,
content2 = document.getElementById("content2").content,
div = document.getElementById("div");
function changeContent(content) {
const nodes = [...div.childNodes];
for (let node of nodes) {
node.remove();
}
div.appendChild(content.cloneNode(true));
}
document.getElementById("add-content1-btn").addEventListener("click", () => {
changeContent(content1);
});
document.getElementById("add-content2-btn").addEventListener("click", () => {
changeContent(content2);
});
#div {
border: 1px solid black
}
<template id="content1">
<p>
This is some HTML content. It won't be rendered unless you use JavaScript.
It supports <strong>markup</strong>, of course.
</p>
</template>
<template id="content2">
<p>
This is another HTML content.
</p>
<ul>
<li>Yes,</li>
<li>it</li>
<li>supports</li>
<li>lists.</li>
</ul>
</template>
<button id="add-content1-btn">Add content1 to div</button> <button id="add-content2-btn">Add content2 to div</button>
<div id="div"></div>
Loading pages with <iframe>
You can use <iframe> to load another page inside a page. This is a great approach if the content is really big, because the main page won't need to load that content unless requested. You can change the src attribute of the <iframe> dynamically to load different pages. Note that the page you load needs to be a full page, with its own CSS and all.
<iframe src="https://example.com/">
I have a banner html with a bunch of buttons(i.e. home, about,..etc.) that I'd like to set as a template. On my unique pages(say the home page), I'd like to "import" this template html file. How do I code this?
I've tried many different ways and looked it up but the closest I got was that when I imported, it had those scrollers and wasn't really "integrated" with the page. A good example of what I'm looking for is for instance, the arduino website where the top banner doesn't change.
Thanks,
You can use HTML Imports to import an external HTML file with a <template> element where you add the elements you want to import.
In the main file:
<head>
<link rel="import" href="template.html" id="myTemplate">
</head>
<body>
<div id="container"></div>
</body>
In the template.html file:
<template>
<span>Hello World!</span>
</template>
<script>
//get the imported HTML document
var importedDoc = document.querySelector( '#myTemplate' ).import
//get the content of the template element
var content = importedDoc.querySelector( 'template' ).content
//add a compy to the main page
document.querySelector( '#container' ).appendChild( content.cloneNode( true ) )
</script>
In the example above, the conent of the <template> element (the <span> text "Hello World!") will be put in the <div id=container> element in the main page.
Update 2019
HTML Imports won't be supported natively after Chrome 73. You should then use the other solutions listed above (the polyfill, an alternate module loader, JS import, or a direct download with fetch).
Our team is building our first polymer all in one page app and we kind of have to reverse engineer a neglected component of the project. We need to set the title for the title bar in the core-scaffolding. This is easy on simple pages by using JS, however some pages have conditional templates that show content and each require their own titles.
eg
<core-scaffolding>
<div id="title">Dynamic Title goes here</div>
<core-animated-pages transitions="cross-fade">
<section>
<div cross-fade>
<my-element>
<template if="{{condition1}}"></template>
Content 1
</template>
<template if="{{condition2}}"></template>
Content 2
</template>
<template if="{{condition3}}"></template>
Content 3
</template>
</my-element>
</div>
</section>
<section>
<div cross-fade></div>
</section>
</core-animated-pages>
I was going to add an attribute on the template elements to be able to pass a title value, however I don't know how to use JS to find out which template is the one that is conditionally rendered (active). I can't seem to find any documentation on this. Also I want to build something reusable (not with IDs) that can be used globally on any page.
Can anyone provide any suggestions?
Cheers,
david
i don't think i would use conditional template for this. if that condition changes a lot the content of the template will be added and removed from the dom every time it is changed. i think it would be better to use the hidden attribute or use databinding to change the text dynamically.
hidden attribute
<span hidden?="{{!condition1}}">Content 1</span>
<span hidden?="{{!condition2}}">Content 2</span>
<span hidden?="{{!condition2}}">Content 3</span>
databinding
<span>{{content}}</span>
then you can change the databind in javascript like normal.
if (condition1) {
this.content = 'Content 1';
}
I was trying to see if I could use ICanHaz or Handlebars for building the sidebar of my Google Docs Add-on. However, it turns out Caja is stripping the actual HTML from my script tag. Is there any way to prevent this from happening?
Let's just say my Handlebars template would be this:
<script id="user" type="text/x-handlebars-template">
<li>
<p class="name">Hello I'm {{ name }}</p>
</li>
</script>
Then currently, at runtime it's this:
<script id="user-caja-guest-0___" data-caja-type="text/x-handlebars-template"></script>
So, even though I'm able to look it up using $('#user").html(), it will just give me an empty template. Is there a way to prevent Caja from doing this?
Caja does not currently support preserving the content of <script> elements in any case, and also assumes that all script text is JavaScript. This would be possible, but nontrivial to support. If you need this feature, please file a request for it.
This appears to work for Handlebars.js with Caja.
Template markup (No script tag + hiding the div)
<div id="entry-template" class="header" style="display: none">
<h1>{{title}}</h1>
<div class="body">
{{body}}
</div>
</div>
Then your script
var source = $("#entry-template").html();
var template = Handlebars.compile(source);
var context = {title: "My New Post", body: "This is my first post!"};
alert(template(context));
And we get
<h1>My New Post</h1>
<div class="body">
This is my first post!
</div>