Use the same data object across multiple templates in Handlebars.js - javascript

I want to use the same data object across multiple templates in different contexts, how can I reuse it. By any chance, handlebars partials would be helpful in this situation.
$("document").ready(function(){
var source = $("#homePage-template").html();
var template = Handlebars.compile(source);
var dataPanel = {activites:[
{activity: "Events" , activityRedirect:"#", icon:"fa fa-camera-retro" , imageUrl:"xyz"},
{activity: "Ciriculars" , activityRedirect:"#", icon:"fa fa-paper-plane", imageUrl:"xyz"}
]};
$("#homePage-placeholder").html(template(dataPanel));
$("#another-placeholder").html(template(dataPanel));
});
And here is my template:
<script id="homePage-template" type="text/x-handlebars-template">
<ul>
{{#activites}}
<li><i class="{{icon}}" aria-hidden="true"></i>{{activity}}</li>
{{/activites}}
</ul>
</script>
Another Template
<script id="another-template" type="text/x-handlebars-template">
{{#activites}}
<div>
<img src="{{imageUrl}}"/>
<span>{{activity}}</span>
</div>
{{/activites}}
</script>
Now how can I reuse this data into "another-template", because I want an image and text in that but it renders like "homePage-template" only in form of a list, if anyone has an idea over this!

In order to have a second template you must fetch its HTML source from the DOM and compile it into a template method just as you are doing for the Home Page Template.
var homepage_template_source = $('#homePage-template').html();
var another_template_source = $('#another-template').html();
var homepage_template = Handlebars.compile(homepage_template_source);
var another_template = Handlebars.compile(another_template_source);
You must call the template method for the specific template you wish to render:
$("#homePage-placeholder").html(homepage_template(dataPanel));
$("#another-placeholder").html(another_template(dataPanel));
See this fiddle for an example.

Related

How to select elements from a handelbars template?

We have a div within our webpage:
<div id="person-details">
<div></div>
...
</div>
We select the relevant elements from this div using the following jQuery code:
var person = $("#person-details");
var children = release.find("div");
var fullname = children.first();
We use a render function to perform an ajax request to get a handlebars template that we're storing in an external file:
function _render() {
var templateScript;
template.getTemplate(filename).done(function(template) {
templateScript = Handlebars.compile(template);
fullname.html(templateScript(context));
});
}
The template looks like the following:
<div>
<div>
<p>{{name}}</p>
</div>
<div>
<p>{{value}}</p>
</div>
</div>
After the render function has been called, we want to select any of the elements from within the template. For example we have tried using:
fullname.children('div');
but as the content has been dynamically generated we aren't able to get the nodes from within the DOM.
Is it even possible to select elements from within a generated handlebars template like this?
Thanks to #DanielShillcock for highlighting render() being asynchronous. Here is a solution:
function _render() {
var templateScript;
template.getTemplate(filename).done(function(template) {
templateScript = Handlebars.compile(template);
selector.html(templateScript(attribute));
value = selector.find("div");
});
}

JsRender - How to Translate templates? (Best Practices)

Im rokiee using Jsrender, I would like to know which is the best way to translate my templates
I have templates like this:
_welcome.tmpl.html:
<div> Hello, {{:name}}</div>
<div> welcome to {{:place}}</div>
and i read daat from file like this:
welcome.json:
{
"name": "David"
"place": "wien"
}
Until here, works fine.
So, now i would like to translate the words "hello" and "welcome to" in diferrents languages. But my system its really ugly and inefficient.
I have different files that i load depends on "lang" attribute. For expample
lang="EN" im going to load:
english_vars.js
var t_hello = "Hello";
var t_msg = "Welcome to";
if lang="es" im going to load:
spanish_vars.js
var t_hello = "Hola";
var t_msg = "Bienvenido a";
Then my templates looks like this:
var wellcomeTemplate = `
<div>`+t_hello+`, {{:name}}</div>
<div>`+t_msg+` {{:place}}</div>`
There are any way to improve this templates engine translations?
Note: Translations MUST NOT come in the same .json that DATA
If you have your localized dictionary as JSON or a JavaScript object (hash):
var terms = {
hello: "Hola",
welcome: "Bienvenido a"
};
then you can pass in the terms separately from the data, as helper variables:
<script id="tmpl" type="text/x-jsrender">
<div>{{:~hello}}, {{:name}}</div>
<div>{{:~welcome}} {{:place}}</div>
</script>
like this:
var data = {
name: "John",
place: "Madrid"
};
var html = $.templates("#tmpl").render(data, terms);
When you change language, pass in the appropriate localized terms.
See http://www.jsviews.com/#helpers
An alternative possibility is to translate the template for each language, using JsRender itself to translate. Simply change the delimiters for the translation step, so you only translate the terms, without changing the other tags:
<script id="baseTmpl" type="text/x-jsrender">
<div><%:hello%>, {{:name}}</div>
<div><%:welcome%> {{:place}}</div>
</script>
then:
$.views.settings.delimiters("<%", "%>");
var localizedTemplate = $.templates("#baseTmpl").render(terms);
$.views.settings.delimiters("{{", "}}");
var html = $.templates(localizedTemplate).render(data);
See http://www.jsviews.com/#settings/delimiters
Both approaches are shown in this jsfiddle

Async loading a template in a Knockout component

I'm pretty experienced with Knockout but this is my first time using components so I'm really hoping I'm missing something obvious! I'll try and simplify my use case a little to explain my issue.
I have a HTML and JS file called Index. Index.html has the data-bind for the component and Index.js has the ko.components.register call.
Index.html
<div data-bind="component: { name: CurrentComponent }"></div>
Index.js
var vm = require("SectionViewModel");
var CurrentComponent = ko.observable("section");
ko.components.register("section", {
viewModel: vm.SectionViewModel,
template: "<h3>Loading...</h3>"
});
ko.applyBindings();
I then have another HTML and JS file - Section.html and SectionViewModel.js. As you can see above, SectionViewModel is what I specify as the view model for the component.
Section.html
<div>
<span data-bind="text: Section().Name"></span>
</div>
SectionViewModel.js
var SectionViewModel = (function() {
function SectionViewModel() {
this.Section = ko.observable();
$.get("http://apiurl").done(function (data) {
this.Section(new SectionModel(data.Model)); // my data used by the view model
ko.components.get("dashboard", function() {
component.template[0] = data.View; // my html from the api
});
});
}
return SectionViewModel;
});
exports.SectionViewModel = SectionViewModel;
As part of the constructor in SectionViewModel, I make a call to my API to get all the data needed to populate my view model. This API call also returns the HTML I need to use in my template (which is basically being read from Section.html).
Obviously this constructor isn't called until I've called applyBindings, so when I get into the success handler for my API call, the template on my component is already set to my default text.
What I need to know is, is it possible for me to update this template? I've tried the following in my success handler as shown above:
ko.components.get("section", function(component) {
component.template[0] = dataFromApi.Html;
});
This does indeed replace my default text with the html returned from my API (as seen in debug tools), but this update isn't reflected in the browser.
So, basically after all that, all I'm really asking is, is there a way to update the content of your components template after binding?
I know an option to solve the above you might think of is to require the template, but I've really simplified the above and in it's full implementation, I'm not able to do this, hence why the HTML is returned by the API.
Any help greatly appreciated! I do have a working solution currently, but I really don't like the way I've had to structure the JS code to get it working so a solution to the above would be the ideal.
Thanks.
You can use a template binding inside your componente.
The normal use of the template bindign is like this:
<div data-bind="template: { name: tmplName, data: tmplData }"></div>
You can make both tmplData and tmplName observables, so you can update the bound data, and change the template. The tmplName is the id of an element whose content will be used as template. If you use this syntax you need an element with the required id, so, in your succes handler you can use something like jQuery to create a new element with the appropriate id, and then update the tmplname, so that the template content gets updated.
*THIS WILL NOT WORK:
Another option is to use the template binding in a different way:
<div data-bind="template: { nodes: tmplNodes, data: tmplData }"></div>
In this case you can supply directly the nodes to the template. I.e. make a tmplNodes observable, which is initialized with your <h3>Loading...</h3> element. And then change it to hold the nodes received from the server.
because nodesdoesn't support observables:
nodes — directly pass an array of DOM nodes to use as a template. This should be a non-observable array and note that the elements will be removed from their current parent if they have one. This option is ignored if you have also passed a nonempty value for name.
So you need to use the first option: create a new element, add it to the document DOM with a known id, and use that id as the template name. DEMO:
// Simulate service that return HTML
var dynTemplNumber = 0;
var getHtml = function() {
var deferred = $.Deferred();
var html =
'<div class="c"> \
<h3>Dynamic template ' + dynTemplNumber++ + '</h3> \
Name: <span data-bind="text: name"/> \
</div>';
setTimeout(deferred.resolve, 2000, html);
return deferred.promise();
};
var Vm = function() {
self = this;
self.tmplIdx = 0;
self.tmplName = ko.observable('tmplA');
self.tmplData = ko.observable({ name: 'Helmut', surname: 'Kaufmann'});
self.tmplNames = ko.observableArray(['tmplA','tmplB']);
self.loading = ko.observable(false);
self.createNewTemplate = function() {
// simulate AJAX call to service
self.loading(true);
getHtml().then(function(html) {
var tmplName = 'tmpl' + tmplIdx++;
var $new = $('<div>');
$new.attr('id',tmplName);
$new.html(html);
$('#tmplContainer').append($new);
self.tmplNames.push(tmplName);
self.loading(false);
self.tmplName(tmplName);
});
};
return self;
};
ko.applyBindings(Vm(), byName);
div.container { border: solid 1px black; margin: 20px 0;}
div {padding: 5px; }
.a { background-color: #FEE;}
.b { background-color: #EFE;}
.c { background-color: #EEF;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="byName" class="container">
Select template by name:
<select data-bind="{options: tmplNames, value: tmplName}"></select>
<input type="button" value="Add template"
data-bind="click: createNewTemplate"/>
<span data-bind="visible: loading">Loading new template...</span>
<div data-bind="template: {name: tmplName, data: tmplData}"></div>
</div>
<div id="tmplContainer" style="display:none">
<div id="tmplA">
<div class="a">
<h3>Template A</h3>
<span data-bind="text: name"></span> <span data-bind="text: surname"></span>
</div>
</div>
<div id="tmplB">
<div class="b">
<h3>Template B</h3>
Name: <span data-bind="text: name"/>
</div>
</div>
</div>
component.template[0] = $(data)[0]
I know this is old, but I found it trying to do the same, and the approcah helped me come up with this in my case, the template seems to be an element, not just raw html

Backbone js.How to pass data from view to template in backbone js

I am new to Backbone js. Can some one help me to send data in template from my view.
My View has this code:
$('#top-bar').html(_.template($("#loginned-top-bar-template").html()));
and my template contains
<li class="menu-item"><%user_name%></li>
and I want to send "awsome_user"to it.
It would be great if any one would help me.
var compiled = _.template($("#loginned-top-bar-template").html());
var templateVars = {user_name : 'awesome_user' };
$('#top-bar').html( compiled(templateVars) );
<%user_name%> should be <%=user_name%> if you want to print the variable.
If you want to use other user_name, set user_name property before compiled function called.
var compiled = _.template($("#loginned-top-bar-template").html());
var templateVars = {user_name : 'awesome_user' };
templateVars.user_name = Parse.User.current().get("name");
$('#top-bar').html( compiled(templateVars) );

Ember.js property and ArrayController in template

I've got a setup like this in Ember:
App.ListObject = Ember.Object.create({
knownThings: function() {
var ot = this.openThings.get('content');
var ct = this.closedThings.get('content');
var kt = ot.concat(ct);
var known = Ember.ArrayController.create({content: kt});
return known;
}.property(),
openThings: Ember.ArrayController.create({
content: []
}),
closedThings: Ember.ArrayController.create({
content: []
}),
})
Basically, known things is the combined arrays of openThings and closedThings. I can't seem to figure out how to iterate over knownThings in the template. Just doing
{{#each App.ListObject.knownThings }}
Does not work as the property needs to be accessed like App.ListObject.get('knownThings') but that doesn't work in the template unless I'm doing something terribly wrong. Iterating over the other attributes in the template does work (open and closed things)
So, how would you iterate over knownThings in the template?
Slight Modifications needed...
Firstly,
knownThings: function() {
//use get to retrieve properties in ember, Always !
var ot = this.get('openThings').get('content');
//var ot = this.get('openThings.content') if you are using latest ember
var ct = this.get('closedThings').get('content');
//var ot = this.get('closedThings.content') if you are using latest ember
var kt = ot.concat(ct);
var known = Ember.ArrayController.create({content: kt});
return known;
//Add dependencies to keep your knownThings in sync with openThings & closedThings if at all they change in future
}.property('openThings', 'closedThings')
Coming to Handlebars iterate using
//you forgot content property, and in handlebars you don;t need to use get, dot operator is enough
{{#each App.List.knownThings}}
Let me know if this works...
Update
Working Fiddle...
Unless I didn't understand what you're saying, I think you should have ListObject extending Em.ArrayController instead of Em.Object. Also, if your property depends on content, it should be .property('content.#each'). If you're using the router, your template should look like {{#each thing in controller.knownThings}} and you use {{thin.something}}, if not using router, then {{#each item in App.listObject.knownThings}}. Also, openThings and closedThings don't seem to be correct and the way you're accessing them is wrong too.
I didn't write a fiddle for this specific case cause I don't really know what you're trying to do, but take a look at this fiddle, specifically at App.ResourcesController and the template 'resources-view':
Controller:
// ...
App.ResourcesController = Em.ArrayController.extend({
content: [],
categories: ['All', 'Handlebars', 'Ember', 'Ember Data', 'Bootstrap', 'Other'],
categorySelected: 'All',
filtered: function() {
if(this.get('categorySelected') == "All") {
return this.get('content');
} else {
return this.get("content")
.filterProperty(
"category",
this.get('categorySelected')
);
}
}.property('content.#each', 'categorySelected'),
filteredCount: function() {
return this.get('filtered').length;
}.property('content.#each', 'categorySelected'),
hasItems: function() {
return this.get('filtered').length > 0;
}.property('filteredCount')
);
// ...
Template:
<script type="text/x-handlebars" data-template-name="resources-view">
<h1>Ember Resources</h1>
{{#view Bootstrap.Well}}
The following is a list of links to Articles, Blogs, Examples and other types of resources about Ember.js and its eco-system.
{{/view }}
{{view Bootstrap.Pills contentBinding="controller.controllers.resourcesController.categories" selectionBinding="controller.controllers.resourcesController.categorySelected"}}
<i>{{controller.filteredCount}} Item(s) Found</i>
{{#if controller.hasItems}}
<ul>
{{#each resource in controller.filtered}}
<li>
<a {{bindAttr href="resource.url"
target="resource.target"
title="resource.description"}}>
{{resource.htmlText}}
</a>
</li>
{{/each}}
</ul>
{{else}}
{{#view Bootstrap.AlertMessage type="warning"}}
Couldn't find items for {{controller.categorySelected}}
{{/view}}
{{/if}}
</script>

Categories