Call methods on mustache variable in a template - javascript

I have a mustache template and I would like to call some function on the mustache variables ({{name}} in this case). Specifically, I want to call toLowerCase() method on the name variable.
<tbody>
<script id="mytemplate" type="text/template">
{{#cat}}
<tr data-index="{{age}}-{{name}}"></tr>
{{/cat}}
</script>
</tbody>
I tried looking in the mustache docs but I couldn't find out how to do this. I tried doing
<tr data-index="{{age}}-{{name.toLowerCase()}}"></tr>
<tr data-index="{{age}}-{{name}}.toLowerCase()"></tr>
But I'm not getting what I expect. I render the template with this code which gets triggered on document ready.
$(function() {
$.getJSON('/cats.json', function(data){
var template = $("#mytemplate").html();
var view = Mustache.to_html(template, data);
$("tbody").html(view);
});
})

you need to pass the function as part of the data, like so:
$(function() {
$.getJSON('/cats.json', function(data){
data.lower = function () {
return function (text, render) {
//wrong line return render(text.toLowerCase());
return render(text).toLowerCase();
}
};
var template = $("#mytemplate").html();
var view = Mustache.to_html(template, data);
$("tbody").html(view);
});
})
and the template:
<tr data-index="{{age}}-{{#lower}}{{name}}{{/lower}}"></tr>

Related

I can't register Handlebars helper missing

I can't register Handlebars helper missing
This code below shows you the condition block in the page:
<table class="table table-striped sorting">
<thead>
<tr class="home">
<th>Title</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{{#each pages}}
<tr id="id_{{this._id}}" class="{{this.slug}}">
<td>{{this.title}}</td>
<td>Edit</td>
{{#checkhomepage home}}
<td></td>
{{else}}
<td><a class="confirmDeletion" href="/admin/pages/delete-page/{{this._id}}">Delete</a></td>
{{/if}}
</tr>
{{/each}}
</tbody>
</table>
And this code below show you my script code block:
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script>
<script>
$('tbody').sortable({
placeholder: "ui-state-hightlight",
update: function () {
var ids = $('tbody').sortable("serialize");
var url = "/admin/pages/reorder-pages";
$.post(url, ids);
}
});
Handlebars.registerHelper('checkhomepage', function (home) {
if(this.title == home){
return true;
}else{
return false;
}
});
});
</script>
in app.js
// view engine
var expressHbs = require('express-handlebars');
var app = express();
app.set('views', __dirname + '/views/');
app.set('view engine', 'handlebars');
var hbs = require('handlebars');
hbs.registerHelper("HelperMissing", function(value, options)
{
return parseInt(value) + 1;
});
app.engine('handlebars', engines.handlebars);
ReferenceError: engines is not defined
engines inside app.js what can i do to solve this problem
You are trying to create a Handlebars Block Helper, but you have a few issues.
In your template, you have the following:
{{checkhomepage home}}
<!-- Home stuff -->
{{else}}
<!-- Non-Home stuff -->
{{/if}}
This will not work because:
Block helpers must begin with a "#" in the opening tag, before the helper name.
The opening and closing helper tags in the template must match, ie. {{#checkhomepage home}}{{else}}{{/checkhomepage}}`.
You are passing the value of home to your helper. However, it is not apparent that there is a home value in the current context, so this value is probably undefined. Perhaps you want to pass the String "home", in which case, you will need to include quotes: {{#checkhomepage 'home'}}.
Next, in order for a block helper to work, you need to use the options argument. In particular, the options arg has an fn function that will render the template nested within the block, as well as an inverse function that will render what is nested in the else block.
The following is the helper re-written to use these options functions. (I have also renamed the home arg to title for clarity:
Handlebars.registerHelper('checkhomepage', function (title, options) {
if (this.title === title) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
I have created a fiddle for your reference.
now i solved my problem
in past i dont set register helper in correct place
i'll post that code to see it
in app.js set helper into hbs caller like this
// view engine setup
app.engine('.hbs' , expressHbs({defaultLayout : 'layout' , extname : '.hbs' , helpers : {
checkhomepage: function (title, options) {
if (this.title === title) {
return options.fn(this);
} else {
return options.inverse(this);
}
},
if you see set helper function inside app.engine(.......,helper:{//here set your function helper like above
finally ill say thank's 76484 :) because he also help me to fix this issue

Handlebars - data not being displayed at all

Hello everyone,
I've been playing around with the handlebars trying to make it work in my project, but I keep getting no results when I'm testing the page.
I'm using the JSON data that I have received from another page. Those data should be displayed after compiling the template. But nothing really happens, I just get no results at all.
get_items_data.js
var source = $("#mytemplate").html();
var template = Handlebars.compile(source);
var Items = Array();
getting_items_data = true;
$.get('GetItemsData',function(responseJson) {
if(responseJson!=null){
$.each(responseJson, function(key,value) {
Items.push({ "id": value['item_id'], "blabla": "bla" });
});
}
});
$('body').append(template(Items));
test.jsp
<script id="mytemplate" type="text/x-handlebars-template">
<table>
<thead>
<th>Items</th>
</thead>
<tbody>
{{#each this}}
<tr>
<td>{{id}}</td>
<td>{{blabla}}</td>
</tr>
{{/each}}
</tbody>
</table>
</script>
JSON data format:
[{"ItemID":74,"SectionID":4},{"ItemID":78,"SectionID":4}]
Any ideas what may be wrong here?
It looks your template function is called before you have the data returned, so the Items array is empty when the elements are appended to the DOM. Unlike AngularJS, Handlebars is static templating so it won't update the DOM if you update the array later.
Try move that render logic into the callback of get:
$.get('GetItemsData',function(responseJson) {
if(responseJson!=null){
$.each(responseJson, function(key,value) {
Items.push({ "id": value['item_id'], "blabla": "bla" });
});
$('body').append(template(Items));
}
});
$(document).ready(function() {
LoadItems();
});
Will never execute inside a script of type text/x-handlebars-template.
Also there could be a problem with your variables attempting to get values from the dom before it's loaded.
Here is a dumbed down version that works: http://jsfiddle.net/whDqv/
function LoadItems()
{
var source = $("#mytemplate").html();
var template = Handlebars.compile(source);
var Items = Array();
getting_items_data = true;
Items.push({ "id": 1, "blabla": "bla" });
var template = Handlebars.compile(source);
$('body').append(template(Items));
}
$(document).ready(function() {
LoadItems();
});

Asp.Net Mvc Render Partial View With Knockout

I use Web Api and Knockout.js in my project. I want to try like this: if I click the "Home" I want to refresh just main div. So I write this code.
My script in layout.cshtml
<script type="text/javascript">
$(document).ready(function () {
ko.applyBindings(new TalesViewModel());//First load the code is runnig and load the main div
function TalesViewModel() {
var self = this;
self.tales = ko.observableArray();
$.getJSON("/api/tales/", self.tales);
}
$('#home').click(function () {
var Tale = function (TaleName, Content, VoicePath, Tales) {
self = this;
self.TaleName = TaleName;
self.Content = Content;
self.VoicePath = VoicePath;
}
var mapping = {
'tales': {
create: function (options) {
return new Tale(options.data.TaleName, options.data.Content,
options.data.VoicePath);
}
}
}
var data = $.getJSON("/api/tales/", Tale);
var viewModel = ko.mapping.fromjs(data, mapping);
ko.applyBindings(viewModel);
})
})
</script>
I want to refresh this place
<div id="main">
#RenderBody()
</div>
TaleList.cshtml (PartialView)
<div>
<ul data-bind="foreach: tales">
<li>
<div>
<div>Masal Adı</div>
<span data-bind="text: $data.TaleName"></span>
</div>
<div>
<div>İçerik</div>
<span data-bind="text: $data.Content"></span>
</div>
<div>
<div>Ses Dosyası</div>
<span data-bind="text: $data.VoicePath"></span>
</div>
</li>
</ul>
When I clicked Home main div is refresh but no data in here. I think I have to use Knockout something but I don't know how can I do it.
I hope I can explain. Thanks all replies.
Update
If I check with firebug I see this error "TypeError: Object # has no method 'fromjs'"
Update2
I added my first knockout code when I load the project.
This is what you need to do:
Create a js object
var Tale = function (TaleName, Content, VoicePath, Tales) {
self = this;
self.TaleName = TaleName;
self.Content = Content;
self.VoicePath = VoicePath;
}
Create a mapping to convert to your js objects
var mapping = {
'tales': {
create: function(options) {
return new Tale(options.data.TaleName, options.data.Content,
options.data.VoicePath);
}
}
}
Check that your data matches something like below, checking the names match as below:
var data = {"tales" : [{"TaleName": "T1", "Content":"c1", "VoicePath":"v1"}, {"TaleName": "T2", "Content":"c2", "VoicePath":"v2"}]}
var viewModel = ko.mapping.fromJS(data, mapping);
Apply the bindings
ko.applyBindings(viewModel);
Here is a working fiddle with mimicked data
http://jsfiddle.net/dxJpc/1/
Update
You are mixing a combination of getJson and ajax, you only need one.
This can be replaced: (With Ajax)
$.ajax({
type: 'GET',
url: '/Pages/TaleList/',
contentType: 'application/html; charset=utf-8',
dataType: 'html'
})
.success(function (data) {
alert("okey!")
var viewModel = ko.mapping.fromJS(data, mapping);
ko.applyBindings(viewModel);
})
.error(function (req, status, error) {
alert("Error!Occured")
})
With getJSON:
var data = $.getJSON("/api/tales/", Tale);
var viewModel = ko.mapping.fromJS(data, mapping);
ko.applyBindings(viewModel);
Update 3
If you are loading your initial load as you have changed it to, you can simply put this in your on click event:
$('#home').click(function () {
ko.applyBindings(new TalesViewModel());
})
Update 4
Declare the view model in the document ready.
$(document).ready(function () {
var viewModel = new TalesViewModel();
ko.applyBindings(viewModel);
Then change your click to this:
$(document).ready(function () {
viewModel = new TalesViewModel();

Templating a table with ember.js not working with JSON call

I've got an index page that lists taxes in a table. I'm trying to
implement this with ember.js following some of the code in the
contacts example app.
Here is the gist: https://gist.github.com/1494281
When I don't load the content from JSON, by commenting out line 19 of
taxes.js, the table renders correctly. However if I use the content
that I pulled from taxes.json then the table renders without tr and
td elements.
Script:
App.Tax = Ember.Object.extend({});
App.taxesController = Ember.ArrayController.create({
content: [
{name:"tax1",rate:"10",number_id:"TaxIDNum"},
{name:"tax2",rate:"9",number_id:null}
],
newTax: function() {
this.pushObject(App.Tax.create({}));
},
loadTaxes: function() {
console.log('loadTaxes');
var self = this;
$.getJSON('/taxes.json', function(json) {
console.log('got response', taxes);
var taxes = json.map(function(item) {
return self.createTaxFromJSON(item);
});
self.set('content', taxes);
});
},
createTaxFromJSON: function(json) {
console.log("createTaxFromJSON", json.tax);
return App.Tax.create(json.tax);
}
});
App.taxesController.loadTaxes();
App.selectedTaxController = Ember.Object.create({
content: null
});
App.TaxListView = Ember.View.extend({
classNameBindings: ['isSelected'],
click: function() {
var content = this.get('content');
console.log('click', content);
App.selectedTaxController.set('content', content);
},
isSelected: function() {
var selectedItem = App.selectedTaxController.get('content');
var content = this.get('content');
if (content == selectedItem) {
return true;
}
return false;
}.property('App.selectedTaxController.content')
});
App.TaxView = Ember.View.extend({
contentBinding: 'App.selectedContactController.content'
});
HTML:
<script type="text/x-handlebars">
<table>
{{#each App.taxesController.content}}
{{#view App.TaxListView contentBinding="this" tagName="tr"}}
{{#with content}}
<td>{{name}}</td>
<td>{{rate}}</td>
<td>{{number_id}}</td>
<td>
Edit
Delete
</td>
{{/with}}
{{/view}}
{{/each}}
</table>
</script>
JSON:
[{"tax":{"account_id":1,"created_at":"2011-12-16T22:45:43Z","id":1,"name":"CA Sales Tax","number_id":"","rate":10.0,"updated_at":"2011-12-16T22:45:43Z"}},{"tax":{"account_id":1,"created_at":"2011-12-17T01:03:01Z","id":2,"name":"Second Tax","number_id":"EIN29387","rate":0.3,"updated_at":"2011-12-17T01:03:01Z"}}]
When you look at the resulting HTML, you'll notice that ember added tags inside your table. these are the markers for bindings to work
according to the HTML specification, inside a tag there MUST only be , , , tags, everything else is undefined behaviour
to make it work, you'll have to remove the {{#view}} and it should at least render something useful.

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