Render HTML Tag attribute using mustache - javascript

In my mustache template I do have something like:
<div {{attr}}="{{attrVal}}"></div>
Rendering this using
Mustache.render(template, {attr : 'data-test', attrVal : 'test'})
does produce
<div ="test"></div>
I expect to get something like
<div data-test="test"></div>
Isn't it possible to render attribute name inside of a tag using Mustache?
UPDATE
I figured out the problem. I define my HTML Mustache Templates inside custom <template> tags in my document. For example:
<template id='myTemplate'>
<div {{dataAttr}}="{{dataAttrValue}}"></div>
</template>
When getting the template using document.querySelector("#myTemplate").innerHTML the browser does convert the {{dataAttr}} to {{dataattr}} because attributes are case insensitiv. So calling
Mustache.render(
document.querySelector("#myTemplate").innerHTML,
{ dataAttr : 'data-attr', dataAttrValue : 'test'}
);
Results in
<div ="test"></div>

Hope this code snippet will help you..
var template = document.querySelector("#template").innerHTML;
//Mustache.parse(template); // optional, speeds up future uses
var rendered = Mustache.render(template, {
attr: "data-test",
attrVal: "test"
});
document.querySelector("#target").innerHTML = rendered;
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.2.1/mustache.js"></script>
<body>
<div id="target">Loading...</div>
<template id="template" >
<textarea style="width:300px">
<div {{attr}}="{{attrVal}}"></div>
</textarea>
</template>
</body>

I head the same problem Try the single [']:
<template id='myTemplate'>
<div {{dataAttr}}='{{dataAttrValue}}'></div>
</template>
.....

You can also try using to_html method for the expected output.
const HTML = Mustache.to_html(template, {attr : 'data-test', attrVal : 'test'});
document.getElementById("myTemplate").innerHTML = HTML;
const template = `
<div {{attr}}="{{attrVal}}">
</div>
`
const HTML = Mustache.to_html(template, {attr : 'data-test', attrVal : 'test'});
document.getElementById("myTemplate").innerHTML = HTML;
console.log(document.getElementById("myTemplate").innerHTML);
<html>
<head>
</head>
<body>
<template id='myTemplate'>
</template>
<div id="display-output"></div>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/3.1.0/mustache.min.js"></script>
</body>
</html>

Related

context is not getting passed for handlebars

I am using handlebars template. I have stumbled across a strange problem. Following code is not passing context to compiled handlebars template when used on browser but strange thing is that same code works fine in jsfiddle !
https://jsfiddle.net/5pnfrjwa/
Here is my code
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
{{> navbar this }}
<div id="render_here">
first
</div>
<div id="render_here_again">
second
</div>
<script id="first-template" type="text/x-handlebars-template">
<div>
<div> Inside first template</div>
<h4 style="color:green">title1 :{{title1}}</h4>
<h4 style="color:blue">body1 :{{body1}}</h4>
<h4 style="color:blue">context : {{context}}</h4>
</div>
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.4/handlebars.js"></script>
<script>
$(document).ready(function() {
var source = $("#first-template").html();
var template = Handlebars.compile(source);
var context
// = "test 1"
= {
title1: "hello",
body1: "body1"
}
var el_html = template(context);
console.log("*** This is source : " + source);
console.log("*** This is template : " + template);
console.log("*** This is template(context) : " + el_html)
console.log(" data is : " + context.title1)
// $(document.body).append(el_html);
// $("#render_here").html(el_html);
// $("#render_here_again").html(el_html);
// document.getElementById('render_here_again').innerHTML = template(context);
$("#render_here_again").html(el_html)
});
</script>
</body>
</html>
I displayed source to console and here is the output
*** This is source :
<div>
<div> Inside first template</div>
<h4 style="color:green">title1 :</h4>
<h4 style="color:blue">body1 :</h4>
<h4 style="color:blue">context : </h4>
</div>
If same is displayed on jsfiddle, its as below:
*** This is source :
<div>
<div> Inside first template</div>
<h4 style="color:green">title1 :{{title1}}</h4>
<h4 style="color:blue">body1 :{{body1}}</h4>
<h4 style="color:blue">context : {{context}}</h4>
</div>
It seems variable name is coming in the source in double curly brackets on jsfiddle but its not coming on my locale machine. Any idea why this behaves differently on browser and jsfiddle.
I tried it with chrome and Mozilla but facing same issue with both.
I am using nodejs and expressjs at server side.
Edit one
It seems I might have identified the issue but I am still searching for solution. This is happening when I am rendering this pages from express 4 server. If I open simple html file with above code, its working fine.
Try to escape from curly braces with a backslash, to avoid rendering on the server side.
<script id="first-template" type="text/x-handlebars-template">
<div>
<div> Inside first template</div>
<h4 style="color:green">title1 :\{{title1}}</h4>
<h4 style="color:blue">body1 :\{{body1}}</h4>
<h4 style="color:blue">context : \{{context}}</h4>
</div>
</script>

Unable to do Computed Databind

I've written a function (Polymer 1.2.0) to return an auth header for iron-ajax, but no matter what I try, I get the message
[dom-bind::_annotatedComputationEffect]: compute methodmakeheadersnot defined
In addition to this code, I've also tried the `Polymer({is: 'dom-bind'} ... blah:fn()' way of binding the fn.
What am I doing wrong? Here's the relevant chunk of the code:
<div id="futuretweets" style="height: 400px">
<template is="dom-bind" id="big-temp">
<script>
document.querySelector('template[is=dom-bind]').makeheaders = function () {
var obj = {};
obj.Authorization = "Bearer " + localStorage.getItem('userToken');
return obj;
};
</script>
<iron-localstorage name="auth" value="{{localtoken}}"></iron-localstorage>
<iron-ajax url="api/twitter/v1/private/gettweets" last-response="{{data}}" auto
headers="{{makeheaders()}}"
handle-as="json">
</iron-ajax>
<iron-list items="[[data.futuretweets]]" as="item">
<template id="tweet-item">
<form is="iron-form" id="tweetform" method="post" action="api/twitter/v1/private/updatetweet"
headers="{{makeheaders()}}" contentType="application/json">
<div class="card layout horizontal center">
<paper-textarea label="Tweet">[[item.text]]</paper-textarea>
<p>datetime: [[item.datetime]]</p>
</div>
<paper-button>Save</paper-button>
</form>
</template>
</iron-list>
</template>
<div id="tweeteditor">
</div>
</div>
Move the script outside of the template element. Templates are static. What happens in your code is that you are declaring the dom-bind's property after it was stamped to the DOM.

Not able to dynamically use id element for a GET request in JQuery

I am trying to use handlebars.js to template a GET request from themoviedb. The idea is that the first get request and template show ALL the movies in the DB with pictures etc and when one of the titles is clicked, it prepends that particular movie with more information on that respective movie. To do this I am trying to use the data attr in the #clickable div with a data-id to which I have assigned the "{{ id }}" element. From there I have an .onclick event handler that saves the movie id to var Id. Lastly I concatenate the var Id to the second get request to populate the new template.
I keep getting an Uncaught Error You must pass a string or Handlebars AST to Handlebars.compile. You passed undefined.
Here is the code -- please help!
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>URDB!</title>
</head>
<body>
<div class="main">hello world</div>
<script src="js/jquery-1.11.1.min.js"></script>
<script src="js/handlebars-v1.3.0.js"></script>
<script src="js/script.js"></script>
<script id="all" type="text/x-handlebars-template">
<div class="list">
<div id="clickable" data-id={{ id }}><h4>{{ title }}</h4></div>
<p>{{ release_date }}</p>
<p>{{ vote_average }}</p>
<h2><img src="https://image.tmdb.org/t/p/w396{{poster_path}}"></h2>
</div>
</script>
<script id="one" type="text/x-handlebars-template">
<div class="single">
<h4>{{ title }}</h4>
<p>{{ release_date }}</p>
<p>{{ vote_average }}</p>
<p>{{ imdb_id }}</p>
<p>{{ tagline }}</p>
<h2><img src="https://image.tmdb.org/t/p/w396{{poster_path}}"></h2>
</div>
</script>
<script>
$(document).ready(function(){
var source = $("#All").html();
var source2 = $("#single").html();
var template = Handlebars.compile(source);
var template2 = Handlebars.compile(source2);
var myList = [];
$.get('https://api.themoviedb.org/3/movie/now_playing?api_key=caa1990e26f7dab9052573323febcbdc', function(data){
data.results.forEach(function(x){
myList.push(x);
var myNewHTML = template({
title: x.title,
release_date: x.release_date,
vote_average: x.vote_average,
poster_path: x.poster_path,
id: x.id
});
$('body').append(myNewHTML);
})
});
$("#clickable").on('click', function(){
var Id = $(this).data('id');
$.get('http://api.themoviedb.org/3/movie/'+Id+'?api_key=caa1990e26f7dab9052573323febcbdc', function(data){
console.log(data);
var anotherHTML = template2({
title: data.title,
release_date: data.release_date,
vote_average: data.vote_average,
poster_path: data.poster_path,
imdb_id: data.imdb_id,
tagline: data.tagline
});
$('body').prepend(anotherHTML);
})
})
})
</script>
</body>
</html>
The problem
The id attributes you are referencing do not reflect your source code, which means you are passing undefined into Handlebars.compile and hence getting the error:
<script id="all" type="text/x-handlebars-template">...</script>
<script id="one" type="text/x-handlebars-template">...</script>
var source = $("#All").html();
var source2 = $("#single").html();
The issues are:
#All - JavaScript is case-sensitive; the id in your script tag is all lowercase
#single - The is no id single in your code; you should be looking for one!
The solution (JSFiddle)
Change #All to #all or vice versa
Change #single to #one or vice versa

document.getElementById(#mapid) returns null

referring to this question here, context is not defined javascript
I am just throwing out another question in regards of the error where document.getElementById is returning a null even though the template is already compiled.
A brief background, I am using handlebar template, jquery and I want a googlemap to appear in 1 of the handlebar template.
my html:
<script id="employee-tpl" type="text/x-handlebars-template">
<div class='header'>Back<h1>Gloop</h1></div>
<div class='details'>
<img class='employee-image' src='img/{{firstName}}_{{lastName}}.jpg' />
<h1>{{name}}</h1>
<h2>{{address}}</h2>
<h2>{{phone}}</h2>
<span class="location"></span>
<ul>
<li><div id="map-canvas"> </div></li>
</ul>
</div>
</script>
and my js
this.render = function(){
this.el.html(EmployeeView.template(employee));
console.log(document.getElementById("map-canvas"));
};
this.initialize = function(){
this.el=$('<div/>');
};
this.initialize();
}
EmployeeView.template = Handlebars.compile($("#employee-tpl").html());
notice that the call to console will log a null value and this js is called at the bottom of my html file
<script src="lib/iscroll.js"></script>
<script src="lib/handlebars.js"></script>
<script src="lib/jquery-1.8.2.min.js"></script>
<script src="js/storage/cafe-memory-store.js"></script>
<script src="js/EmployeeView.js"></script>
<script src="js/main.js"></script>
</body>
</html>
my understanding it that the my compilation will render the div which then should be able to be seen but this is not the case. Anyone knows why?
Is that fiddle all the code you have? If I add this to the JS it works.. but it's hard to see what you're after.
var source = $("#employee-tpl").html();
var template = Handlebars.compile(source);
var data = { //your data here }
$('body').append(template(data));

ICANHAZ.js render dom element instead of text

Param:
'<div class="someclass">' + somecontent + '</div>' + somecontent2
Template:
<div>{{ param }}</div>
And in browser I have:
<div class="someclass"> somecontent </div>somecontent2
How to isolate .someclass, that it render as a dom element, not text?
I think all Html elements are escaped by default. To return un-escaped Html use the triple mustache:
<div>{{{param}}}</div>
I would suggest using partial templates for this.
<script id="main" type="text/html">
<div>{{>partial}}</div>
</script>
<script id="partial" class="partial" type="text/html">
<div class="someclass">{{somecontent}}</div>{{somecontent2}}
</script>
Then just call the main template with your data as normal:
html = ich.main({
somecontent: 'content',
somecontent2: 'content2'
});

Categories