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.
Related
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}}
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.
These are templates:
<template name="postsList">
{{#each posts}}
{{>postItem}}
{{/each}}
</template>
<template name="postItem">
<div class="more-less">
<div class="more-block">
<p>{{{text}}}</p>
</div>
<p class="continued">…</p>
[ + ]
</div>
</template>
When posts is updated with new post, postItem is inserted to postsLists. How can I apply this only for new inserted postItem template:
$('.more-less .more-block').css('height', 20).css('overflow', 'hidden');
Template.postItem.rendered affects all posts in page, but I need to affect only newly inserted post without affecting existing ones.
I'm going to assume new posts are added to the top of the list? if so...
<template name="postsList">
<div class="posts-list">
{{#each posts}}
{{>postItem}}
{{/each}}
</div>
</template>
<template name="postItem">
<div class="more-less">
<div class="more-block">
<p>{{{text}}}</p>
</div>
<p class="continued">…</p>
[ + ]
</div>
</template>
You can simply achieve this with CSS:
.posts-list .more-less:first-child .more-block {
height: 20px;
overflow: hidden;
}
No need to use JavaScript and worry about reactivity and DOM mutation.
I'm messing around with JSON structures in EmberJS starting from the top level Application level and trying to pass data to a general MenuController/MenuView child so I can reuse it.
The JSON I've come up with to play around with how data gets passed through nested ember structures is this:
JSON
{
appName: "CheesyPuffs"
menuItems: [
{name:"Gouda"}
{name:"Crackers", menuItems: [
{name: "Cheezeits"}
]
}
]
}
Handlebars
<script type="text/x-handlebars">
<div class='app'>
<div class='header'>
{{#if menuItems}}
// Embed template 'menu'
{{/if}}
</div>
</div>
</script>
<script type="text/x-handlebars" data-template-name="menu">
<ul>
{{#each menuItems}}
<li>{{name}}</li>
{{#if menuItems}}
// Embed menu template
{{/if}}
{{/each}}
</ul>
</script>
JS
App.MenuController = Ember.ArrayController.extend({
actions: {
click: function(){
// Signal Event to App
}
}
});
App.MenuView = Ember.View.extend({
click: function(){
console.log("I clicked a menu");
}
});
All the examples I've seen concerning nested stuff involves routes with the classic _id subroute. I'm not sure how I would go about telling the App Router that it needs to pass the menuItems data to a child controller that's embedded in the same view. I have a feeling you can do this both via the template and programmically? If so, how would you do it both ways?
using the template you should use render. And that's the way you should do it, programmatically doesn't make sense.
<script type="text/x-handlebars">
<div class='app'>
<div class='header'>
{{#if menuItems}}
{{render 'menu' menuItems}}
{{/if}}
</div>
</div>
</script>
<script type="text/x-handlebars" data-template-name="menu">
<ul>
{{#each menuItems}}
<li>{{name}}</li>
{{#if menuItems}}
{{render 'menu' menuItems}}
{{/if}}
{{/each}}
</ul>
</script>
I'm new to ember I am trying to append a template to another and it seems to work but it raises an error, can you please explain why?
The error:
Assertion failed: You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead
This is the code in app.js
App.NewStickie = Ember.View.extend({
click: function(evt){
var stickie = Ember.View.create({
templateName: 'stickie',
content: 'write your notes here'
});
stickie.appendTo('#stickies');
}
});
These are the contents of index.html
<script type="text/x-handlebars">
{{#view App.NewStickie}}
<button type="button" class="btn btn-success">
New
</button>
{{/view}}
{{outlet}}
</script>
<script type="text/x-handlebars" id="index">
<div id="stickies">
{{#each item in model}}
<div class="stickie" contenteditable="true">
{{#view App.DeleteStickie}}
<span class="glyphicon glyphicon-trash"></span>
{{/view}}
<div contenteditable="true">
{{item.content}}
</div>
</div>
{{/each}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="stickie">
<div class="stickie">
{{#view App.DeleteStickie}}
<span class="glyphicon glyphicon-trash"></span>
{{/view}}
<div contenteditable="true">
{{view.content}}
</div>
</div>
</script>
Each view in ember have a template, for example:
foo_view.js
App.FooView = Ember.View.extend({
templateName: 'foo'
})
foo template
<script type="text/x-handlebars" data-template-name="index">
<div id=myFooView>Foo</div>
</script>
You are trying to insert a view inside of other in that way:
App.BarView.create().appendTo('#myFooView')
This isn't allowed. You can use the {{view}} handlebars helper to render a view inside other like that:
foo template
<script type="text/x-handlebars" data-template-name="index">
<div id=myFooView>
Foo
{{view App.BarView}}
</div>
</script>
But I think that you want this working dynamically. So you can use the ContainerView, like described by the error message:
App.StickiesView = Ember.ContainerView.extend({
click: function() {
var stickie = Ember.View.create({
templateName: 'stickie',
content: 'write your notes here'
});
this.pushObject(stickie);
}
})
I see in your code a lot of views with the click event, ember encourage you to use actions, this give more flexibility, error/loading handling etc. I think is a good idea to use it.
I hope it helps
You should probably read this guide that explains that ContainerView is. Also, I don't think it's necessary to create another View to append a template to another template.