binding object to templates with javascript - javascript

I have been playing with jquery and templates, and I cobbled together a simple template binding system:
<script type="text/template" id="Template">
<div>{0}</div>
</script>
and...
var buffer = '';
var template = $("#Template").html();
response.Data.forEach(function(arrayElement)
{
buffer += template.format(arrayElement.p1,);
});
$("#ListOutput").html(buffer);
My question is: Is there a more natural way that I can take a JSON object, such as:
{"user": { "id": "1","name": "bob" }}
And use a more natural binding sintax, such a this:
<script type="text/template" id="Template">
<div>{user.name}</div>
</script>
straight JS or jquery would be idea. I know that some of the more complex data binding tools like Angular provide these features, but the complexity of some of the data binding plugins makes my head swim. Anything based on node is right out.
Is there some native feature I don't know about that makes this easy?

If you can use ES2015 "template strings".
<script type="text/template" id="Template">
<div>${user.name}</div>
</script>
You have not added response array, so I am assuming it as
[
{"user": { "id": "1","name": "bob" }},
{"user": { "id": "2","name": "Some Name" }}
]
var buffer = '';
var template = $("#Template").html();
response.Data.forEach(function(arrayElement) {
var user = arrayElement.user;
buffer += eval('`' + template + '`');
});
$("#ListOutput").html(buffer);

Related

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

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.

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

Extract date from last item in JSON object (AngularJS)

I am dynamically creating an object on a web app using AngularJS. The idea is that the user can load new events as they click a button, for this to work I need to get the date of the last one so Ill know which ones to load next.
This is the code that generates the JSON object
services.getEvents().then(function(data){
$scope.events = data.data;
});
and my html...
<li ng-repeat="event in events | orderBy:'-event_date' ">
<span>{{event.event_date}},{{event.event_name}}, {{event.event_venue}}, {{event.event_description}} </span>
</li>
An example of one event...
{
"event_id":"1",
"event_name":"Event 1",
"event_date":"2014-09-26 00:00:00",
"event_venue":"Limerick",
"event_description":"stuff"
}
Is it possible to extract the latest date from a list of these so I can send it back to the API? Or am I going about this a wrong way altogether.
Im also using this an opportunity to learn AngularJS
var app = angular.module("app", []);
function MainCtrl ($filter) {
this.data = [
{
"event_id":"1",
"event_name":"Event 1",
"event_date":"2014-05-26 00:00:00",
"event_venue":"Limerick",
"event_description":"stuff"
},{
"event_id":"2",
"event_name":"Event 1",
"event_date":"2015-09-26 00:00:00",
"event_venue":"Limerick",
"event_description":"stuff"
},{
"event_id":"3",
"event_name":"Event 1",
"event_date":"2014-9-27 00:00:00",
"event_venue":"Limerick",
"event_description":"stuff"
}
];
this.lastOne =$filter('orderBy')(this.data,'-event_date')[this.data.length-1].event_date ;
}
angular.module("app").controller("MainCtrl", MainCtrl);
<html ng-app="app">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-controller="MainCtrl as vm">
<div class="container">
<h3>Latest One:{{vm.lastOne}}</h3>
</div>
</body>
</html>
To access the last element of an array use length -1
events[events.length - 1].event_date
if the response from the server is not sorted in any way you should filter first
var sortedArray = $filter('orderBy')($scope.events, '-event_date');
var lastDate = sortedArray[sortedArray.length - 1].event_date
hope this gets you on the way.
If you make your server side code return an array sorted by descending date, you could just take the date off the first item in your array. Something like:
events[0].event_date;
Failing that, you could do the sorting on the client side with something like:
events.sort(function(a, b){return new Date(a.event_date) < new Date(b.event_date);});
Then get the value of:
events[0].event_date;

jsrender Template method

I have use the following code snippet to render the data.
Code snippet:
<body>
<div id="myGrid" style="border:1px solid red; width:500px;height:600px;">
</div>
<script id="template" type="text/x-jsrender">
<div><div>{{:Name]}}</div></div>
</script>
<script type="text/javascript"7>
var helpers = {};
helpers["templateMethod"] = Test;
$.views.helpers(helpers);
var data = [{ "ID": 1, "Name": "Raja" },
{ "ID": 2, "Name": "sekar" },
{ "ID": 3, "Name": "Ram" }
]
var test = $("#template").render(data);
$("#myGrid").html(test);
function Test() {
}
</script>
</body>
In this case i want to get the each div element while rendering for customization.
How to get this div element while rendering.
If I understand your question, you want to change the to where foo changes in each div (and "class" is just an example). To do that, you would need either a helper, a tag, or another template. Each have advantages.
Here is the link for tags. I think that is most likely what you want.

Create HTML tag from Javascript object

What is the best method to change this object
{
src: 'img.jpg',
title: 'foo'
}
into a valid HTML tag string like this
<img src="img.jpg" title="foo" />
Solution 1
With jQuery this is easy; but complicated:
$('<img/>').attr(obj).wrap('<div/>').parent().html();
Any better ideas?
Why not:
$('<img/>', obj).get(0).outerHTML;
Fiddle
You do not need to wrap it in a div using multiple functions and get the html, just use get(0) to get the DOM element and outerHTML to get the element's html representation.
Unless you are using browsers really old you can rely on outerHTML
Here is a JSPerf to compare the performance diff between the approaches.
Perhaps slightly more concise than PSL's?
$('<img />',object)[0].outerHTML;
Simple with jquery
$("<div>").append($('<img />',object)).html();
If you are only doing one element, then this solution is overkill, but I thought I would post it anyway as I don't know what your project is.
Have you considered a JavaScript template engine? I've been playing around with Swig lately, as it is quite lightweight, but there are many options. Basically, you create a template, pass a JavaScript object, and the compiled template is executed, returning a string of HTML.
Example from Swig Documentation
Template
<h1>{{ pagename|title }}</h1>
<ul>
{% for author in authors %}
<li{% if loop.first%} class="first"{% endif %}>
{{ author }}
</li>
{% else %}
<li>There are no authors.</li>
{% endfor %}
</ul>
JavaScript to Render Template
var template = require('swig');
var tmpl = template.compileFile('/path/to/template.html');
tmpl.render({ // The return value of this function is your output HTML
pagename: 'awesome people',
authors: ['Paul', 'Jim', 'Jane']
});
Output
<h1>Awesome People</h1>
<ul>
<li class="first">Paul</li>
<li>Jim</li>
<li>Jane</li>
</ul>
Making html elements based out of objects containing attribute-attribute values such as
{
src: 'img.jpg',
title: 'foo'
}
almost completely falls into the paradigm of cook.js.
The command which you would issue with cook would be:
img ({
src: 'img.jpg',
title: 'foo'
})
If the attribute details are stored as given in your example,
in a variable obj then:
img(obj)
For more details check it out at cook.relfor.co.
Here's how you make it as a string:
var img = '<img ',
obj = { src : 'img.jpg', title: 'foo' };
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
img += prop + '=' + '"' + obj[prop] + '" ';
}
}
img += '/>';
http://jsfiddle.net/5dx6e/
EDIT: Note that the code answers the precise question. Of course it's unsafe to create HTML this way. But that's not what the question asked. If security was OP's concern, obviously he/she would use document.createElement('img') instead of a string.
EDIT 2: For the sake of completeness, here is a much safer way of creating HTML from the object:
var img = document.createElement('img'),
obj = { src : 'img.jpg', title: 'foo' };
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
img.setAttribute(prop, obj[prop]);
}
}
http://jsfiddle.net/8yn6Y/

Categories