fix handlebar js not working on client side - javascript

I am trying to use handlebars templates. I used Express-handlebars for my server, and i want to use handlebars js for my client side rendering.
This is the script for the handlebars template.
<script id="some-template" type="text/x-handlebars-template">
<div class="row">
{{#each result}}
<!-- product -->
<div class="col-md-4 col-xs-6">
<a href="/product/{{_id}}"> <div class="product">
<div class="product-img">
<img src="\{{picture}}" style="height:160px;">
<div class="product-label">
{{#if percent}}
<span class="sale">{{percent}}%</span>
{{/if}}
<span class="new">NEW</span>
</div>
</div>
<div class="product-body">
<p class="product-category">{{category}}</p>
<h3 class="product-name">{{this.title}}</h3>
<h4 class="product-price">${{this.price}} <del class="product-old-price">${{this.discounted_price}}</del></h4>
{{#if this.averagerating}}
</div></a>
</div>
{{/each}}
</div>
</script>
For the client side
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.4.2/handlebars.js" integrity="sha256-hSzapznWRy/aOZkctlN03an9DxCLlN8ZCQS0lxntiHg=" crossorigin="anonymous"></script>
$('#mybutton').click(function(){
var post_url = $('#myform').attr("action");
var form_data = $('#myform').serialize();
// console.log(post_url, form_data);
var source = $("#some-template").html();
var template = Handlebars.compile(source);
$('#loader').show();
$.get( post_url, form_data, function( response ) {
$("#searchresult").html("");
console.log(response);
var data = template({result:response});
console.log(data);
$("#searchresult").html(data);
//$('#loader').hide();
});
My response is an array with an object inside, for example:[ {title:"Black Cap", price:60}].
But nothing shows on the page!!!. the data which i am supposed to send as html displays like :
:
<div class="row">
</div>
Please help. Thanks

You should make sure the data structure is correct:
try with this line in JS:
...
var data = template(response);
...
and in handlebars:
{{#each this}}

Handlebars js api, only accepts a javascript object.
if you create an object, Displayhtml with the result array as a field, like this :
Displayhtml={
results:[ {title:"Black Cap", price:60}]
}
Then you parse the object to the template: template(Displayhtml). then it works!!!
In front-end(you must but a \ before any helper in handlebars if you are also using handlebars as in server-side rendering ):
\{{# each results}}
\\do whatever you want.
\{{/each}}

Related

Using AJAX in Node js and displaying data using Handlebars

I am using AJAX and Handlebars to get data from my MongoDB without refreshing the page and represent it in an easier manner.
I have created a div with a search button where a user places his/her inputs. These inputs need to passed to my routes and then the results from my DB should be sent back from my routes, to the handlebar which will help me display the products.
index.hbs
<div id="search-form">
....
<input id="bhkInput" name="bmin" type="number">
<input id="priceMin" name="pf" type="number">
<input id="priceMax" name="pt" type="number">
<input type="submit" class="btn searchButton" id="submit" value="Search" onclick="showResults()">
</div>
<div class="row col-sm-12 searchResults" id="sr">
//Results need to be displayed here
</div>
<script id = "result-template" type="text/x-handlebars-template">
{{#each searchResults }}
<div class="row">
{{#each this }}
<div class="col-sm-6 col-md-4">
...
<img src="{{this.imagePath}}" alt="..." class=" card-img-top">
<div class="card-body">
<h4>Flat No: {{this.flatNo}}</h4>
...
<p class="description">
{{this.description}}
</p>
...
...
</div>
</div>
</div>
</div>
{{/each}}
</div>
{{/each}}
</script>
<script>
function showResults(){
let bmin = document.getElementById('bhkInput').value;
let pf = document.getElementById('priceMin').value;
let pt = document.getElementById('priceMax').value;
$.ajax({
type: 'GET',
data: {
bmin: bmin,
pf: pf,
pt: pt
},
contentType: 'application/json; charset=utf-8',
dataType: 'json',
url: "/results",
success: function(data){
let source = $('#result-template').html();
let template = Handlebars.compile(source);
let html = template(data);
$(".searchResults").innerHTML = html;
}
});
}
The issue that I am facing:
When I send back the results from my DB, I am unable to display it using Handlebars.
How do I handle the data after success function is called. I want the results to be appended in the 'searchResults' div. I went through this link, however I am yet not able to see the data of my results.
Update
I took dummy data from the Handlebars Docs and used it for my template and yet there is no data being appended in the html
The console.log(html) returns the template without the new data items
index.hbs
<script id="entry-template" type="text/x-handlebars-template">
<div class="entry">
<h1>{{title}}</h1>
<div class="body">
{{body}}
</div>
</div>
</script>
<script>
....
$.ajax({
....
success: function(data){
var source = document.getElementById("entry-template").innerHTML;
var template = Handlebars.compile(source);
var context = {title: "My New Post", body: "This is my first post!"};
var html = template(context);
console.log(html);
....
</script>
Output for console.log(html)
<div class="entry">
<h1></h1>
<div class="body">
</div>
</div>
For the first issue. Your method is GET so I think you can get it by req.query.productId.
For the second issue. You should append your data in ajax success callback function, because ajax is asynchronous. For example:
$.ajax({
type: 'GET',
data: encodeURIComponent(searchObject),
url: "/results",
success: function(data){
console.log(data);
let sr = document.getElementById('sr');
$(sr).append();
}
});
How to get "data" from JQuery Ajax requests

Handlebars.js returns empty markup

I have a problem with rendering handlebars.js template. I'm doing AJAX request to server, and servers returns me data which contains 'dishes' array with objects.Dish object contains id,price,weight,description,and array of photos. Then i render it with handlebars,and its works properly, 'html' variable containts rendered markup.
var data ;
var modalDishInfo;
var modalDishComments;
var vitrina;
function ajax(params){
$.ajax({
url: '/admin/getDishByCategory',
type: 'POST',
dataType: "json",
data: params,
success: function (result){
data = JSON.parse(result);
vitrina = Handlebars.compile( $('#vitrina_template').html() );
modalDishInfo = Handlebars.compile( $('#modalDishInfo').html() );
var html = vitrina(data.dishes);
console.log(html);
$('.foodmenucontent').empty();
$('.foodmenucontent').append(vitrina(data.dishes));
}
<script id="vitrina_template" type="text/x-handlebars-template">
{{#each this}}
<div class="col-lg-3 mealcard" >
<p class="text-center mealname">{{ dish_name }}</p>
<div class="weightandprice">
<div class="weightcontainer"><span class="mealweight pull-right">{{ dish_weight }} грамм</span></div>
<div class="pricecontainer"><span class="mealprice pull-left">{{ dish_price }} руб.</span></div>
</div>
<button class="orderbutton center-block">ЗАКАЗАТЬ</button>
</div>
{{/each}}
</script>
As you can see this code renders elements, which contains links with openModal() function.I have empty bootstrap modal window and want to render its content, according to clicked link.
function openModal(id){
var foo = id.slice(-1);
var modaldata = data.dishes;
var modaldish = $.grep(modaldata, function (element) {
return element.id == foo;
});
modaldish = modaldish[0];
console.log(modaldish);
var markup = modalDishInfo(modaldish);
$('#modalDishInfo').empty();
$('#modalDishInfo').append(markup);
$('#modalDish').modal('show');
$('.fotorama').fotorama();
};
and template
<script id="modalDishInfo" type="text/x-handlebars-template">
<div class="modalcontainer">
<div class="row">
<div class="col-lg-6">
<div class="fotorama" data-nav="thumbs" data-width="100%" data- thumbwidth="80" data-thumbheight="45"
data-transition="crossfade" data-loop="true" data-keyboard="true" data-navposition="bottom"
data-fit="cover" data-ratio="1600/900">
{{#each dish_photos}}
<img src="/uploads/gallery/{{ this.path }}" class="img-responsive" alt="">
{{/each}}
</div>
</div>
<div class="col-lg-6">
<p class="mealname">{{ dish_name}}</p>
<pre>{{ dish_description }}</pre>
<p>{{ dish_weight }}гр.</p>
<p class="mealprice">{{ dish_price }}руб.</p><br>
<button class="orderbutton ">ЗАКАЗАТЬ</button>
</div>
</div>
The problem is second template(modalDishInfo) dont want to render, console.log returns 'markup' variable completely empty. I tried different combinations of block helpers, and expressions,but none of them working. Maybe im missing something important? Or need to use specific expressions, when passing single object to template?
I found mistake that i did.My template id and container id(which is empty) are the same. So jquery selector returned me empty markup. I didn't notice that, because im using TWIG and my scripts was in {% verbatim %} tag to avoid TWIG errors, so i dont receive any errors or warning using duplicate ID's in code. Hope my answer is informative and can be helpful to someone.

meteor display image with variable source

I'm using meteor.js and playing around with a simple application. I have a form on my page and once submitted the data is inserted into a database. I have a 'feed' of data on the left side of my page which updates when a new entry in the database is submitted, displaying the data. This is basic data at present about countries and populations etc. My question is how to mix a js variable to vary the source of an image file thats loaded in this 'feed' - hopefully explained below.
So, in code, I have this:
<template name="mainLeftCol">
<div class="col-sm-5">
{{> form}}
</div>
</template>
<template name="mainBody">
{{> mainLeftCol}}
<div class="col-sm-7">
{{#each dbEntry}}
{{> formItem}}
{{/each}}
</div>
</template>
and in a js file I have the event code for when the form is submitted:
Template.mainLeftCol.events({
'submit form': function(e) {
e.preventDefault()
var country = $(e.target).find('[id=country]').val()
prefix = country.slice(0,3);
if (prefix === 'Eng') {
console.log("Eng is for England");
}
var spot = {
country: country,
continent: $(e.target).find('[id=continent]').val(),
};
spot._id = Spots.insert(spot);
}
});
The formItems are being displayed using the following template which outputs the 'variables' that were input in the form:
<template name="formItem">
{{#Animate}}
<div class="panel panel-default spot animate">
<div class="panel-heading">
<h5 class="pull-right">{{country}}</h5>
<h4><mark><b>{{continent}}</b></mark></h4>
</div>
<div class="panel-body">
<img src="Eng.png" class="img-circle pull-right">
</div>
</div>
{{/Animate}}
</template>
As you can see in this template I have hardcoded "Eng.png" as the source for the image. What I would like to do is based on the prefix variable which slices the country field is to have the template display a different image (they're flags) based on the country on the template.
How can I mix a JS variable from my events code into the source of the image file in my template code?
Hope this makes sense!
I don't know if i got i right, but if you want to change the image (flag) according to the country try something like this:
Build a Template helper "prefix" which outputs the current country prefix.
Prefix helper:
Template.formItem.helpers({
countryPrefix: function () {
var country = $(e.target).find('[id=country]').val()
return country.slice(0,3);
}
});
In your Template you can now:
<div class="panel-body">
<img src="{{countryPrefix}}.png" class="img-circle pull-right">
</div>

Ember -retrieving data from server to a view?

Does anyone happen to know How to show data from server, right now ive been showing related models in basic handlebars like this
{{
view Ember.Select
prompt="Organization"
contentBinding="organizations"
optionValuePath="content.id"
optionLabelPath="content.name"
selectionBinding="selectedOrganization"
}}
But i need to create an has many form... which im duplicating using views? Is using views even the right path to go ?!
{{#each view.anotherField}}
{{view Ember.TextField value=view.name}}
{{/each}}
Here is the output of my form, u can see Organizatons form being doubled
JSbin http://jsbin.com/efeReDer/7/edit
Today I came up with this... :D Kinda serves the purpose ? looks ugly tho
http://emberjs.jsbin.com/acUCocu/6/edit
Basically i made an empty model which i then each loop.
On action i "store.create".empty record to it.
Give me your thoughts on this :)
Also is there a way to make these fields indepedent ? without all changing their content while an input is changed.
Cheers,
kristjan
Here you can find an example to work on, of what i think you are asking
http://emberjs.jsbin.com/iPeHuNA/1/edit
js
Tried to separate the entities related to the model of the app, from how they will be displayed.Created an ember class App.Person that will hold the data from server. I have not used ember-data, but it is quite easy to replace the classes with ember-data notation and the dummy ajax calls with respective store calls etc, if desired.
App = Ember.Application.create();
App.Router.map(function() {
this.route("persons");
});
App.IndexRoute = Ember.Route.extend({
beforeModel: function() {
this.transitionTo("persons");
}
});
App.PersonsRoute = Ember.Route.extend({
model:function(){
return $.ajax({url:"/"}).then(function(){/*in url it is required to place the actual server address that will return data e.g. from a rest web service*/
/*let's imagine that the following data has been returned from the server*/
/*i.e. two Person entities have already been stored to the server and now are retrieved to display*/
var personsData = [];
var person1 = App.Person.create({id:1,fname:"Person1",lname:"First",genderId:2});
var person2 = App.Person.create({id:2,fname:"Person2",lname:"Second",genderId:1});
personsData.pushObject(person1);
personsData.pushObject(person2);
return personsData;
});
},
setupController:function(controller,model){
/*this could also be retrieved from server*/
/*let's mimic a call*/
$.ajax({url:"/",success:function(){
/*This will run async but ember's binding will preper everything.If this is not acceptable, then initialization of lists' values/dictionary values can take place in any earlier phase of the app. */
var gendersData = [];
gendersData.pushObject(App.Gender.create({id:1,type:"male"}));
gendersData.pushObject(App.Gender.create({id:2,type:"female"}));
controller.set("genders",gendersData);
model.forEach(function(person){
person.set("gender",gendersData.findBy("id",person.get("genderId")));
});
}});
controller.set("model",model);
}
});
App.PersonsController = Ember.ArrayController.extend({
genders:[],
actions:{
addPerson:function(){
this.get("model").pushObject(App.Person.create({id:Date.now(),fname:"",lname:""}));
},
print:function(){
console.log(this.get("model"));
}
}
});
App.PersonFormView = Ember.View.extend({
templateName:"personForm",
/*layoutName:"simple-row"*/
layoutName:"collapsible-row"
});
App.Person = Ember.Object.extend({
id:null,
fname:"",
lname:"",
gender:null
});
App.Gender = Ember.Object.extend({
id:null,
type:null
});
html/hbs
created a view that takes care of how each App.Person instance gets rendered. As example partial and layouts have been used to accomodate bootstrap styling, as i noticed you used some in your example.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Ember Starter Kit</title>
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/normalize/2.1.0/normalize.css">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
</head>
<body>
<script type="text/x-handlebars">
<h2>Welcome to Ember.js</h2>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="persons">
{{#each person in this}}
{{view App.PersonFormView}}
{{/each}}
<br/><br/>
{{partial "buttons"}}
</script>
<script type="text/x-handlebars" data-template-name="_buttons">
<button type="button" class="btn btn-primary" {{action "addPerson"}}>
add
</button>
<button type="button" class="btn btn-primary" {{action "print"}}>
print results to console
</button>
</script>
<script type="text/x-handlebars" data-template-name="personForm">
<div class="row">
<div class="col-md-6 col-xs-5">
<div class="form-group">
<label>First Name</label>
{{input class="form-control" placeholder="First Name" value=person.fname}}
</div>
</div>
<div class="col-md-6 col-xs-5">
<div class="form-group">
<label>Last Name</label>
{{input class="form-control" placeholder="Last Name" value=person.lname}}
</div>
</div>
</div>
<div class="row">
<div class="col-md-2 col-xs-4">
{{
view Ember.Select
prompt="Gender"
content=controller.genders
optionValuePath="content.id"
optionLabelPath="content.type"
selectionBinding=person.gender
class="form-control"
}}
</div>
</div>
<!--</div>-->
</script>
<script type="text/x-handlebars" data-template-name="simple-row">
<div class="row">
{{yield}}
</div>
<br/><br/>
</script>
<script type="text/x-handlebars" data-template-name="collapsible-row">
<div class="panel-group" >
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href=#{{unbound person.id}}>
person:{{person.fname}}
</a>
</h4>
</div>
<div id={{unbound person.id}} class="panel-collapse collapse">
<div class="panel-body">
{{yield}}
</div>
</div>
</div>
</div>
</br>
</script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
<script src="http://builds.handlebarsjs.com.s3.amazonaws.com/handlebars-v1.1.2.js"></script>
<script src="http://builds.emberjs.com/tags/v1.2.0/ember.min.js"></script>
</body>
</html>

Handlebarsjs appending to rendered template dynamically

I'm trying to append text to an already rendered Handlebars page dynamically, so I don't want to have to reload the entire page:
<script id="post-template" type="text/x-handlebars-template">
{{#each blogPost}}
<article>
<h1 class="blog-post-title">{{title}}</h1>
<div class="blog-post-info">
<p class="blog-post-text">{{{post}}}</p>
</div>
{{> comments}}
</article>
{{/each}}
</script>
<script id="comment-template" type="text/x-handlebars-template">
{{#if comments}}
<p class="lead">Comments</p>
{{#each comments}}
<div class="comment-info">
<span>By: {{name}}</span>
<time>Time: {{time}}</time>
</div>
<p>{{body}}</p>
<hr>
{{/each}}
{{/if}}
</script>
So, each time someone adds a comment, I was hoping to load just that. Here's my js:
This renders the page:
$.get('/render-post', function(data){
var source = $("#post-template").html();
var template = Handlebars.compile(source);
$('.posts').html(template({blogPost : data}));
});
And this is what I'm trying to do on a comment:
$.post('/add-comment', commentData, function(data){
if(data){
var source = $("#comment-partial").html();
var template = Handlebars.compile(source);
console.log(template({blogPost : data}));
$('.posts').append(template({blogPost : data}));
}
});
Thank you for any help you can offer.

Categories

Resources