I created a helper in Handlebars to help with logic, but my template parses the returned html as text rather than html.
I have a quiz results page that is rendered after the quiz is completed:
<script id="quiz-result" type="text/x-handlebars-template">
{{#each rounds}}
{{round_end_result}}
{{/each}}
<div class="clear"></div>
</script>
For each of the rounds, I use a helper to determine which template to render a round's result:
Handlebars.registerHelper("round_end_result", function() {
if (this.correct) {
var source = '';
if (this.guess == this.correct) {
console.log("correct guess");
var source = $("#round-end-correct").html();
} else {
var source = $("#round-end-wrong").html();
}
var template = Handlebars.compile(source);
var context = this;
var html = template(context);
console.log(html);
return html;
} else {
console.log("tie");
}
});
Here is a template that describes a correct round (let's take say it rendered the #round-end-correct template):
<script id="round-end-correct" type="text/x-handlebars-template">
<div></div>
</script>
Here is what gets rendered:
<div></div>
Not as HTML, but as text. How do I get it to actually render the HTML as HTML, rather than text?
I assume that unescaping in Handlebars works the same as in vanilla Mustache.
In that case use triple mustaches to unescape html, i,e: {{{unescapedhtml}}}, like:
<script id="quiz-result" type="text/x-handlebars-template">
{{#each rounds}}
{{{round_end_result}}}
{{/each}}
<div class="clear"></div>
for ref see:
http://mustache.github.com/mustache.5.html
Geert-Jan's answers is correct but just for reference you can also set the result to "safe" directly inside the helper (code from handlebars.js wiki)
Handlebars.registerHelper('foo', function(text, url) {
text = Handlebars.Utils.escapeExpression(text);
url = Handlebars.Utils.escapeExpression(url);
var result = '' + text + '';
return new Handlebars.SafeString(result);
});
With that you can use regular double handlebars {{ }} and handlebars won't escape your expression.
Related
I have an HTML string that I would like rendered as HTML in Mustache. However, that string also contains a Mustache conditional. When I inspect the rendered HTML in Chrome Dev Tools, it seems that the conditional is literally being printed inside the input element, instead of being handled. I think it might be a problem with the forward slash in the closing brackets. In Chrome Dev Tools, the / is removed upon rendering. So I tried using the HTML decimal code. That also did not work.
This is where I am rendering the HTML string:
<span>{{{response.additionalInfo}}}</span>
This is the object I am passing to the view. The additionalInfo property is the one that has the embedded Mustache conditionals:
var response = {
templateType: "optIn",
header: "Opt-In",
additionalInfo: "<label><input type='checkbox' id='notOptIn' name='isOptIn' {{^response.isOptIn}}checked{{/response.isOptIn}}> YES</label>",
isOptIn: false,
}
Is it possible to add a Mustache conditional inside a string that Mustache will render as HTML? If so, how do I escape the / in the ending tags?
I didn't manage to make it work with a single call to Mustache.
For what it's worth, I managed to make it work by converting the template in response.additionalInfo and storing the result in response.additionalInfo.
Then I converted the template you provided.
With isOptIn = false :
var response = {
templateType: "optIn",
header: "Opt-In",
additionalInfo: "<label><input type='checkbox' id='notOptIn' name='isOptIn' {{^response.isOptIn}}checked{{/response.isOptIn}}> YES</label>",
isOptIn: false,
}
var template = "<span>{{{response.additionalInfo}}}</span>";
document.getElementById("run").addEventListener("click", function() {
response.additionalInfo = Mustache.to_html(response.additionalInfo, window);
html = Mustache.to_html(template, window);
document.getElementById("container").innerHTML = html;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>
<script src="https://mustache.github.io/extras/mustache.js"></script>
<button id="run">Run</button>
<div id="container"/>
With isOptIn = true :
var response = {
templateType: "optIn",
header: "Opt-In",
additionalInfo: "<label><input type='checkbox' id='notOptIn' name='isOptIn' {{^response.isOptIn}}checked{{/response.isOptIn}}> YES</label>",
isOptIn: true,
}
var template = "<span>{{{response.additionalInfo}}}</span>";
document.getElementById("run").addEventListener("click", function() {
response.additionalInfo = Mustache.to_html(response.additionalInfo, window);
html = Mustache.to_html(template, window);
document.getElementById("container").innerHTML = html;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>
<script src="https://mustache.github.io/extras/mustache.js"></script>
<button id="run">Run</button>
<div id="container"/>
I am new to webdevelopment. So, Here, I have textAngular. In this I a, showing html document. Now, I want to show the text of the document only but that should be with the formatting as it is in the .html file. So,Right now my code is like -
here data is the html file content, you can say it's a string which has the html file content.Now,
$scope.htmlOriginalDoc = parser.parseFromString(data, 'text/html');
$rootScope.data.htmlDocument = $scope.htmlOriginalDoc.body.innerText;
So, Here when I get this that time I am getting all the data of that file, but when I see it it is like just a text document it is not having any new lines,I mean its not preserving the new line or spaces .So, How can I achieve this ?
Basically you need to compile it from string, then bind it with ngSanitize. To preserve the white space wrap with <pre> tags.
var app = angular.module('myApp', ['ngSanitize']);
app.controller('myCtrl', function($scope, $sce) {
$scope.html = "<div style=\"color:red;font-size:24px;\"> T e s t </div>"; // string
$scope.html = $sce.trustAsHtml($scope.html);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular-sanitize.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div style="white-space: pre;"> <!-- instead of <pre> -->
<div ng-bind-html="html"></div>
</div>
</div>
Let's say I have some model with html field. This field contains some handlebars code. For example
<div class="foo">
{{model.title}}
</div>
The problem is when I'm trying to iterate over models and render html field, it doesn't evaluate handlebars code inside it.
{{#each models as |model|}}
{{{model.html}}}
{{/each}}
Here's an idea, create a Handlebars helper, that will compile handlebars.
With this sample, I believe you can build something that will suit your needs:
<script type="text/javascript" src="http://builds.handlebarsjs.com.s3.amazonaws.com/handlebars.min-latest.js"></script>
<script>
var data = [{
"title": "Hey",
"subtitle": "I'm an inner handlebar template.",
"html": '<h1>{{title}}</h1><h2>{{subtitle}}</h2>'
}, {
"title": "Nice!",
"html": '<h1>{{title}}</h1>'
}];
/** Handlebar helper that will compile the content passed, with the data at index **/
Handlebars.registerHelper("compile", function(content, index) {
var template = Handlebars.compile(content);
return template(data[index]);
});
var content = '{{#each .}}\
{{{compile html #index}}}\
{{/each}}';
var template = Handlebars.compile(content);
document.body.innerHTML = template(data);
</script>
I never used ember, but I believe you can make it work easily ;)
I have an empty todo list:
<ul class="list">
</ul>
I want to create a li inside that list for each json title I have in the following json data:
[{"id":2,"title":"Mandar cartas a impresión","description":"","status":false,"priority":1,"created_at":"2015-12-07T13:09:55.552Z","updated_at":"2015-12-07T13:09:55.552Z","project_id":1},{"id":3,"title":"CIF Intracomunitario","description":"","status":false,"priority":1,"created_at":"2015-12-07T13:10:05.736Z","updated_at":"2015-12-07T13:10:05.736Z","project_id":1},{"id":4,"title":"Uniformes Chef a Porter","description":"","status":false,"priority":1,"created_at":"2015-12-07T13:10:16.170Z","updated_at":"2015-12-07T13:10:16.170Z","project_id":1},{"id":5,"title":"Personal","description":"","status":false,"priority":1,"created_at":"2015-12-07T13:10:31.569Z","updated_at":"2015-12-07T13:10:31.569Z","project_id":1},{"id":1,"title":"Mandar contrato pleni","description":"","status":false,"priority":1,"created_at":"2015-12-07T13:09:36.747Z","updated_at":"2015-12-07T13:13:12.068Z","project_id":1},{"id":17,"title":"Comprar TPV","description":"","status":false,"priority":null,"created_at":"2015-12-08T00:18:40.753Z","updated_at":"2015-12-08T00:18:40.753Z","project_id":1},{"id":18,"title":"Vajillas Zara Home","description":"","status":false,"priority":null,"created_at":"2015-12-08T00:18:54.580Z","updated_at":"2015-12-08T00:18:54.580Z","project_id":1},{"id":19,"title":"Tpv","description":"","status":false,"priority":null,"created_at":"2015-12-08T00:33:17.393Z","updated_at":"2015-12-08T00:33:17.393Z","project_id":1},{"id":21,"title":"Wifi - Contratar","description":"","status":false,"priority":null,"created_at":"2015-12-08T15:33:24.639Z","updated_at":"2015-12-08T15:33:24.639Z","project_id":1},{"id":22,"title":"Cuenta Definitiva Santander","description":"","status":false,"priority":null,"created_at":"2015-12-08T15:33:50.255Z","updated_at":"2015-12-08T15:33:50.255Z","project_id":1},{"id":23,"title":"Pagarés Kider","description":"","status":false,"priority":null,"created_at":"2015-12-08T15:34:08.162Z","updated_at":"2015-12-08T15:34:08.162Z","project_id":1}]
So, I have the following javascript which uses handlebars for templating:
<script>
jQuery.getJSON("http://myurl/tasks.json", function(data){
var source = $("#tasks-template").html();
var template = Handlebars.compile(source);
$.each(data) function() {
var context = data;
var show = template(context);
$(".list").html(show);
});
});
</script>
My handlebars template:
<script id="tasks-template" type="text/x-handlebars-template">
<li>
<div>{{title}}</div>
</li>
</script>
It wont create a li in my html for each title in the json.
What am I missing?
Thanks!
When you iterate for each object of the array received in the JSON, you have to use this instead of data to access to the object.
data is the whole array and this is the current object where you want to retrieve the title property:
$.each(data, function() {
var context = this;
var show = template(context);
$(".list").append(show);
});
And also change the html method for append for don't overwrite the content.
Regards
Given HTML code such :
<!-- 2. Anchor -->
<div id="anchor">This div is the <b>#anchor</b>.</div>
<!-- 3. Template -->
<script id="tpl" type="text/template">
{{#people}}
<div><img src="{{photo}}"><b>{{family}} {{name}}</b> — {{title}}, {{place}} : {{introduction}}.</div>
{{/people}}
</script>
Given JS/Handlebars such as :
<!--4. Handlebars.js slingshot -->
//4a.function creation
var slingshot = function (url, tplId, anchor) {
$.getJSON(url, function(data) {
var template = $(tplId).html();
var stone = Handlebars.compile(template)(data);
$(anchor).append(stone);
});
}
slingshot('data.json', '#tpl', '#anchor'); // since url = 'data.json' , we can use both notations.
How to externalize the my 3. Template (#tpl) into a proper .txt text file (or other extension) ? How to load it back ? so I may use the same template into various .html webpages.
Full code : http://bl.ocks.org/hugolpz/8075193 / http://bl.ocks.org/hugolpz/raw/8075193/
Put the following template content into a file named test.handlebars
{{#people}}
<div><img src="{{photo}}">
<b>
{{family}} {{name}}
</b> — {{title}},
{{place}} : {{introduction}}.
</div>
{{/people}}
Write a function which will use the template as below
function getTemplate(name) {
if (Handlebars.templates === undefined || Handlebars.templates[name] === undefined) {
$.ajax({
url : name + ".handlebars",
success : function(data) {
if (Handlebars.templates === undefined) {
Handlebars.templates = {};
}
Handlebars.templates[name] = Handlebars.compile(data);
},
async : false
});
}
return Handlebars.templates[name];
}
In the main program you can write the below statement to insert the template contents into div with id="anchor", as shown below
var Template = getTemplate("test")
this.$("#anchor).append(Template(data));
where data is the contents of a json file or some db query output which will give you the values meant for the following attributes in json format
people, twitter, name, family, photo, title, place, introduction
I'm assuming you have already compiled your template. So you can use the technique I have described in Bootstrapping Multiple Instances of an HandlebarsJS Template Into a Page.
Hook and libs
Place this in your index.html:
<div class="hook" data-json="data/whatever.json"></div>
and the JavaScript libs
<!-- Helper to inject data-set in templates instance -->
<script src="scripts/template-loader.js"></script>
<!-- Get the (compiled) template -->
<script src="scripts/myTemplate.hbs.js"></script>
template-loader.js helper
$(function(){
'use strict';
var compiledTemplate = myApp.Templates['app/templates/myTemplate.hbs'];
$('.hook').each(function(i, h){ # h = current hook
var url = $(h).data('json'); # data-set's url
$.getJSON(url).then(function (json) { # fetch data-set
var tpl = compiledTemplate( json ); # inject data into template
$(h).html(tpl); # inflate template in page
});
});
});
Please read the complete article for further details.