Handlebars.js printing object doesn't work - javascript

this might be real simple but I've tried many examples and still couldn't make it working.
So I've got this code to check if the entry is written by the author and if so, I want to print it into template.
function printTitltes() {
var currentUser = JSON.parse(localStorage.getItem('currentUser'))
var author = currentUser["username"];
var allEntries = JSON.parse(localStorage.getItem("allEntries"));
var template = Handlebars.compile($("#template").html());
var authorEntry;
if (!allEntries) {
return
} else {
for (var i=0; i<allEntries.length; i++) {
if (allEntries[i]["author"] === author) {
authorEntry = allEntries[i];
$("#titleArea").append(template(authorEntry));
}
}
}
}
And my template is:
<script type='text/template' id='template'>
<ul class="entries-list">
{{#each auhorEntry}}
<li data-id="{{ID}}">
<span> {{date}} </span>
{{title}}
</li>
{{/each}}
</ul>
</script>
When executed, all I got is an empty template. I've must have been sending a wrong object to the template but couldn't grasp how could I do it right. Anyone whould spot it for me please?

<script type="text/x-handlebars-template" id="template">

Related

Error "unexpected char '#' " with rendering Handlebars template

I have a simple 100% working code from CS50 lecture, which represents the usage of Handlebars. Here it is:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.11/handlebars.min.js"></script>
<script id="result" type="text/template">
<li>
You rolled:
{{#each values}}
<img alt="{{ this }}" title="{{ this }}" src="img/{{ this }}.png">
{{/each}}
(Total: {{ total }})
</li>
</script>
<script>
// Template for roll results
const template = Handlebars.compile(document.querySelector('#result').innerHTML);
document.addEventListener('DOMContentLoaded', () => {
document.querySelector('#roll').onclick = () => {
// Generate random rolls.
const counter = parseInt(document.querySelector('#counter').value);
const rolls = [];
let total = 0;
for (let i = 0; i < counter; i++) {
const value = Math.floor(Math.random() * 6) + 1;
rolls.push(value);
total += value;
};
// Add roll results to DOM.
const content = template({'values': rolls, 'total': total});
document.querySelector('#rolls').innerHTML += content;
};
});
</script>
</head>
<body>
<input id="counter" type="number" placeholder="Number of Rolls" min="1" value="1">
<button id="roll">Roll</button>
<ul id="rolls">
</ul>
</body>
</html>
When I try to render it in my browser I get "jinja2.exceptions.TemplateSyntaxError: unexpected char '#'".
Obviously the problem is on my computer side. But how to fix it?
I have searched for this problem in the web. One interesting thing I catch was that it is somehow connected with "my server side templating engine". Here is a thread - https://github.com/wycats/handlebars.js/issues/269 . Another guy here (https://github.com/wycats/handlebars.js/issues/1263) says he had similar error because of Pagespeed.
How can I understand which "templating engine" is installed? I have an ordinary Mac and project in virtual environment.
What might be the problem?
This happens because jinja2 reads curly braces as syntax (as variables or block codes).
So, You have to escape jinja in your HTML code.
the methods to do so are following;
The easiest way is to output a literal variable delimiter ({{) is by using a variable expression.
{{ '{{' }}
For bigger sections, it makes sense to mark a block raw. For example, to include handlebars syntax in a template, you can use this snippet:
{% raw %}
<ul>
{{#each vlaues}}
<li>{{ this }}</li>
{{/endeach}}
</ul>
{% endraw %}
For more info check enter link description here

Handlebars.js group by value

I'm using Handlebars to display some datas via ajax, and the JSON is like this:
{"data":[
{ "sn":"43","areasn":"3","name":"X1","status":"empty","seats":"12"},
{ "sn":"22","areasn":"1","name":"F1","status":"empty","seats":"8"},
{ "sn":"12","areasn":"2","name":"E1","status":"empty","seats":"6"},
{ "sn":"18","areasn":"3","name":"R3","status":"empty","seats":"6"},
{ "sn":"31","areasn":"1","name":"G4","status":"empty","seats":"4"},
{ "sn":"23","areasn":"2","name":"W5","status":"empty","seats":"12"}
]}
and I need to use handlebars.js in order to display tables in differents areas, something like these:
<script id="tables-template" type="text/x-handlebars-template">
{{#each data}}
// All tables in area-1
<ul id="area-{{areasn}}">
<li id="{{sn}}">{{name}}</li>
</ul>
// All tables in area-2
<ul id="area-{{areasn}}">
<li id="{{sn}}">{{name}}</li>
</ul>
// All tables in area-3
<ul id="area-{{areasn}}">
<li id="{{sn}}">{{name}}</li>
</ul>
{{/each}}
</script>
I have no idea how to write a helper for this, is anyone can help? thanks!
There is probably a better way of doing this as I don't know about handlebars, but this should do what you are looking for:
(function() {
var id = 0,
cache = [];
var ids={};
Handlebars.registerHelper("groupData", function(data) {
var dataKey = id++;
ids[data.areasn]=true;
if(cache[data.areasn]==undefined) cache[data.areasn]={id:data.areasn, data:[data]};
else cache[data.areasn].data.push(data)
if(dataKey==context.data.length-1){
context.cache=[];
for(var i in ids){
context.cache.push(cache[i])
}
}
});
})();
var context={"data":[
{ "sn":"43","areasn":"3","name":"X1","status":"empty","seats":"12"},
{ "sn":"22","areasn":"1","name":"F1","status":"empty","seats":"8"},
{ "sn":"12","areasn":"2","name":"E1","status":"empty","seats":"6"},
{ "sn":"18","areasn":"3","name":"R3","status":"empty","seats":"6"},
{ "sn":"31","areasn":"1","name":"G4","status":"empty","seats":"4"},
{ "sn":"23","areasn":"2","name":"W5","status":"empty","seats":"12"}
]}
var template = Handlebars.compile($("#your-template").text());
var html = template(context);
document.body.innerHTML=html;
Check fiddle for html:
http://jsfiddle.net/mE49M/226/

Automatic two way binding with Knockout

I'm just getting started with Knockout.js and i have a view(html) which is supposed to be populated by data from a rest api via jquery's $.getJSON method.
When i run the app, nothing shows but using firebug i can see that the 'GET' query returns a status code of 200 and the right data.
I'm at a fix as to why nothing shows in the view since the bindings in Knockout.js are supposed to be automatic.
Below is my code.
Thanks
<div id ='main'>
<!-- ko foreach: posts -->
<p>Hello</p><span data-bind="text: title"></span></p><p data-bind="text: content"></p>
<p data-bind="text: author"></p><p data-bind="text: date"></p>
<!-- /ko -->
</div>
</body>
<script type="text/javascript">
function Post(data){
this.title = ko.observable(data.title);
this.content = ko.observable(data.content);
this.author = ko.observable(data.author);
this.date = ko.observable(data.date)
}
function PostListViewModel(){
var self = this;
self.posts = ko.observableArray([]);
$.getJSON("/posts", function(getPost){
var mappedPost = $.map(getPost, function(item){
return new Post(item)
});
self.posts(mappedPost);
});
}
var postlistviewmodel = new PostListViewModel();
ko.applyBindings(postlistviewmodel);
</script>
This should be:
$.getJSON("/posts", function(getPost){
var mappedPosts = $.map(getPost, function(item){
return new Post(item)
});
self.posts(mappedPosts);
});
wouldn't do self.posts.push(mappedPosts[i]) at all. You should just pass mappedPosts through the ko binding in order to update the listeners.
If your just getting the latest posts and want to update your current list simply do:
var allPosts = self.posts().concat(mappedPosts);
self.posts(allPosts);
You don't need the model to have ko.observable if you're just displaying them. If you want to edit model as well, then leave as.
Also, I tend to do this for single or multiple view models:
ko.applyBindings({viewModel : new viewModel() };
This allows for having multiple named view models. Access scope using: $root.viewModel
This is what I did earlier: http://jsfiddle.net/jFb3X/
Check your code against this fiddle then.
Script tags also need to be above the closing body tags
<html>
<head>
</head>
<body>
<!-- all your html content -->
<script type="text/javascript">
var viewModel = function () {
}
ko.applyBindings({viewModel : new viewModel()});
</script>
</body>
</html>
Is it something as simple as waiting for the DOM to be ready?
Are you able to try the following:
$(function () {
ko.applyBindings(postlistviewmodel);
});
Source: I've done this a few times and been stumped for a bit trying to see what I did wrong. :-)
(As a style thing, I'd also move the /body to after the /script - probably not related to your issue though).
I suspect you get multiple posts from /posts. You only push a single item (array).
...
$.getJSON("/posts", function(getPost){
var mappedPosts = $.map(getPost, function(item){
return new Post(item)
});
for(var i = 0; i < mappedPosts.length; i++) {
self.posts.push(mappedPosts[i]);
}
});
...

Creating Inline Style Sheet With Javascript

Hihi. I'm trying to create an inline style sheet at the beginning of the page which reacts to what i'm GETTING from the url. Im doing this so I can have the navbutton of the page that im on highlighted. Kind of like here, www.myeg.net , but they have a static site and it is much easier.
<script type="text/javascript">
function parseUrl( url ) {
var a = document.createElement('a');
a.href = url;
return a;
}
var page=parseUrl('').search
function getSecondPart(str) {
return str.split('=')[1];
}
var site=getSecondPart(page);
var style = document.createElement("style");
style.innerHTML = ".nav_" + page + " { background-image:url('images/gradients/transparent_gradient.png');}";
document.body.appendChild(style);
}
</script>
</head>
<body>
<center><div><img width="960px" height="187.5" src="images/fullbanner.png"></div></center>
<div id="wrapper">
<div id="navbar">
<ul>
<li class="nav_index">Home</li>
<li class="nav_archive">News</li>
<li class="nav_squads">Roster</li>
<li class="nav_forum">Forums</li>
<li class="nav_about">Contact</li>
</ul>
I'm pretty noob at javascript so sorry ;;;
Try this:
<style type="text/css">
#banner{text-align:center;}
#banner>img{width:960px;height:187.5px;}
#nav>.selected{background-image:url('images/gradients/transparent_gradient.png');}
</style>
</head>
<body>
<div id="banner"><img src="images/fullbanner.png"></div>
<div id="wrapper">
<div id="navbar">
<ul id="nav">
<li id="nav_index">Home</li>
<li id="nav_archive">News</li>
<li id="nav_squads">Roster</li>
<li id="nav_forum">Forums</li>
<li id="nav_about">Contact</li>
</ul>
<script type="text/javascript">
document.getElementById('nav_'+window.location.href.split('=')[1]).className='selected';
</script>
You shouldn't use <center>, it's deprecated!
Instead of writing a style sheet with javascript in order to match an element, you should match a class and then only add that class to your element with javascript.
And I don't understand very well your code:
function parseUrl( url ) {
var a = document.createElement('a');
a.href = url;
return a;
}
var page=parseUrl('').search
It gives "" to me, but I have never seen .search on an anchor... If you want to get the current URL, you can do window.location.href.
And another point: if you use var outside functions (in global scope) you are creating a global variable, which won't be deleted and uses memory. Then, you can remove it when you don't want to use it anymore (var a="dagjhdjgailghkagh";/*code*/;a=null;), or use a self-execute function (closure) which contains your code.
Edit:
Sorry, instead of #nav>selected I meant #nav>.selected.
You can see a demo here: http://jsfiddle.net/VhWHp/
(But the url doesn't have =, so I replace it manually to 'archive'. In your site, remove that line)
And yes, it loads CSS first and then the nav. But that's the true power of CSS and javascript: if you set a class to an element after it has been loaded, that element will have the styles applied to that class.
Edit 2:
The problem is that if you do split('=')[1], the result will be something like "news&action" instead of "news".
Then, you could use a function I wrote some time ago:
function sQuery(arg) {
if(window.location.search){
var que = window.location.search.substring(1);
if(arg=='string'){return que;}
que = que.split("&");
if(!arg||arg=='array'){return que;}
for(var i=0;i<que.length;i++){
var qvar = que[i].split("=");
if(qvar[0]==arg){
return qvar[1];
}
}
}
return false;
}
Then, call the function like this: sQuery('site')
document.getElementById('nav_'+(sQuery('site')||'index')).className='selected';
You can also call sQuery('array') or just sQuery() if you want to get ["site=news","action=archive"], and sQuery('string') if you want "site=news&action=archive". If you won't use that, you can simplify the function:
function sQuery(arg) {
if(window.location.search){
var que = window.location.search.substring(1).split("&");
for(var i=0;i<que.length;i++){
var qvar = que[i].split("=");
if(qvar[0]==arg){
return qvar[1];
}
}
}
return false;
}

Handlebars Template rendering template as text

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.

Categories

Resources