Backbone can't see a key passed to the template [duplicate] - javascript

This question already has answers here:
Underscore template throwing variable not defined error
(2 answers)
Closed 7 years ago.
I have a very simple code in order to use a backbone/underscore template.
HTML:
<script type="text/template" id="search_template">
<div>Name comes here: <h4><%=name%></h4></div>
<input type="text" id="search_input" />
<input type="button" id="search_button" value="Search" />
</script>
<div id="search_container"></div>
JS:
$(function(){
var SearchView = Backbone.View.extend({
initialize: function(){
this.render();
},
render: function(){
var tmpl = $('#search_template').html(),
compiled = _.template(tmpl, { name:'hello' });
$(this.el).html(compiled);
}
});
var search_view = new SearchView({ el: "#search_container" });
});
The problem is it can't see the key "name" which should be passed into template. I still don't figure out why.
The whole code sample is located here: http://plnkr.co/edit/7fV2azTh6cpjmUxIBHvJ?p=preview

You are not using Underscore's template method correctly.
The compilation step is not where you pass in your parameters to be replaced by the template. Rather, the compilation step produces a function. The result of invoking the compiled function, with your view model parameters as the first argument, will return a string of your template with the replaced values of your view model.
render: function () {
var tmpl = $('#search_template').html(),
compiled = _.template(tmpl);
this.$el.html(compiled({ name:'hello' }));
}
An additional point: Notice how a Backbone View already gives us a convenient this.$el, so we don't need to do the $(this.el) step again.

change
compiled = _.template(tmpl, { name:'hello' });
to
compiled = _.template(tmpl)({ name:'hello' });
_.template returns function that accepts data to be inserted into template
http://plnkr.co/edit/GqFBvepfukIwDGLQa8Ki?p=preview

Related

Pass angular value to common JavaScript

I am trying to pass a value from angular scope to common JavaScript.
The JavaScript is like this
<script type="text/javascript">
var epaycode = null;
var epaybuysum = null;
paymentwindow = new PaymentWindow({
'merchantnumber': epaycode,
'amount': epaybuysum,
'currency': "DKK",
'windowstate': "4",
'paymentcollection': "1",
'iframeheight': "250",
'iframewidth': "500"
});
paymentwindow.append('payment-div');
setTimeout(function(){
paymentwindow.open();
}, 1000);
The angular controller code is like this
$scope.showpay = function () {
$window.epaybuysum = $scope.buysum * 100;
$window.epaycode = $scope.ePayCode;
};
The Angular showpay() function is called after the common JavaScript is initialized. The buysum and ePayCode is set earlier in the program. They have value and is tested with console.log().
Why doesn't the epaybuysum and epaycode getting transferred to the common JavaScript?
Is there any other solutions to passing values to common JavaScript from Angular controllers?
Have a look at this plunker: http://plnkr.co/edit/lQiXpObbWuG84CNbcZt2?p=preview
<div ng-controller="MainCtrl">
<input ng-model="buyCode">
<input ng-model="buySum">
<p>{{buyCode}} ... {{buySum}}</p>
<button ng-click="showPay()">call showPay</button>
</div>
<button onclick="buttonClick()">Console.log</button>
The first button calls your showPay function(the one on scope). The second button calls console.log (outside the angular controller, simple js). For this simple usecase it seems to work as expected. How are you calling showPay function?
Try this:
(function (angular, epaycode) {
'use strict';
var module = angular.module('abc', []);
//Your controller etc.
}
})(angular, epaycode);
Updated
The plunker in the comments section shows how you can do this.

javascript does not function after dom is updated [duplicate]

This question already has answers here:
jQuery doesn't work after content is loaded via AJAX
(9 answers)
Closed 7 years ago.
I got a webpage that updates its content using ajax/json and handlebars. Now i want to use bootstrap-datepicker for my date fields, but after updating the DOM with handlebars, the javascript event does not work.
My javascript
$(function(){
var refresher = function () {
$.getJSON( "{% url 'characters:journal_json' 1 %}", function(obj) {
refresh_timer = obj.refresh_timer * 1000;
setTimeout(refresher, refresh_timer);
if (obj.content) {
// do shit with content and data
var source = $("#JournalTemplate").html();
var template = Handlebars.compile(source);
var html = template(obj.content);
$("#JournalContent").replaceWith(html);
}
});
};
setTimeout(refresher, 300); // 0.3 seconds
});
$('.datepicker').datepicker({
format: "mm-dd-yyyy",
autoclose: true
});
Handlebars template (will be expanded after i solve this problem):
<form class="form-inline" action="" method="GET" id="FilterForm">
<input class="form-control input-sm datepicker" id="id_end_date" name="end_date" type="text" value="05-26-2015" />
<button type="submit" class="btn btn-primary btn-sm">Filter</button>
</form>
Try this way :
$('body').on('focus', '.datepicker', function () {
$(this).datepicker({
format: "mm-dd-yyyy",
autoclose: true
});
});
With on the event is also triggered for dynamic elements
I did little trick, please try this,
$(function(){
var refresher = function () {
$.getJSON( "{% url 'characters:journal_json' 1 %}", function(obj) {
refresh_timer = obj.refresh_timer * 1000;
setTimeout(refresher, refresh_timer);
if (obj.content) {
// do shit with content and data
var source = $("#JournalTemplate").html();
var template = Handlebars.compile(source);
var html = template(obj.content);
$("#JournalContent").replaceWith(html);
bindDatepicker(); // *** Here I am binding again...
}
});
};
setTimeout(refresher, 300); // 0.3 seconds
});
function bindDatepicker() {
$('.datepicker').datepicker({
format: "mm-dd-yyyy",
autoclose: true
});
}
This code binds datepicker every time when HTML is updated.
Hope it helps.
First of all bootstrap uses jQuery, so please confirm that you are putting jQuery script before bootstrap.js. After that write your own script inside tag followed by self executing/ anonymous function, called as IIFE(Immediately Invoked Function Expression) in JavaScript. So, this is a good approach to write scripts always. Please try as below.
(function(){
----- Your Code ----
})();
And definitely you will get rid of all these. Thanks.

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]);
}
});
...

passing model object to view in backbone

I have been trying to pass a model object to be evaluated in my template but had no luck. I tried the following but had no luck
dashboardmodel.js
var myMod = Backbone.Model.extend({
defaults: {
name: "mo",
age: "10"
}
});
myview.js
var dashView = Backbone.View.extend({
el: '.content-area',
this.mymodel = new myMod({}),
template: _.template(dashBoardTemplate, this.mymodel),
initialize: function() {
},
render: function() {
this.$el.html(this.template);
return this;
}
// more javascript code.............
dahboard.html
<p> Hello <%= name %> </p>
PS: I am using the underscore template engine
In addition , your way to pass a model to a view is not flexible, because you would pass an instance of your model, instead of a default model. Thus, you might want to single out
this.mymodel = new myMod({}),
(btw, above line gives me error message in my chrome browser because of "=" sign)
Then, suppose you have an instance A:
A = new myMod({"name": "World", "age":100})
Then pass it to your view as:
myview = new dashView({mymodel: A})
One more step, you have to do is to call render function:
myview.render();
Here's a complete solution:
<html>
<script src="jquery-1.10.2.min.js"></script>
<script src="underscore-min.js"></script>
<script src="backbone.js"></script>
<body>
<script type="text/template" id="dashBoardTemplate">
<p> Hello <%= name %> </p>
</script>
<div class="content-area">
</div>
<script type="text/javascript">
var myMod = Backbone.Model.extend({
defaults: {
name: "mo",
age: "10"
}
});
var dashView = Backbone.View.extend({
el: '.content-area',
template: _.template($("#dashBoardTemplate").html()),
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
mymod = new myMod({"name": "World", "age":100});
myview = new dashView({model:mymod});
myview.render();
</script>
</body>
</html>
If you want to study backone.js, please read this open source book which get me started:
http://addyosmani.github.io/backbone-fundamentals/
You need to get properties of a Backbone Model with the getter syntax, so you need to rewrite your template to:
<p> Hello <%= obj.get('name') %> </p>
Or you need to convert your model into a plain JS object when calling _.template what you can do with the .toJSON() (which creates a clone of the model) or .attributes property:
template: _.template(dashBoardTemplate, this.mymodel.toJSON())
Side note: you should consider to move the template rendering logic into your view. Because your current code render your template when your view is declared and not when you call the render method. So you might get unexpected result. So your code you look like this:
template: _.template(dashBoardTemplate), //only compile the template
render: function() {
this.$el.html(this.template(this.mymodel.toJSON()));
return this;
}

Getting started on Knockout JS

I am currently developing using ASP.NET, and I'd like to get started on Knockout JS... Basically what I've done is I've copy-pasted the code provided in the first tutorial.
So I put this into my head:
<script type="text/javascript">
function() {
// This is a simple *viewmodel* - JavaScript that defines the data and
behavior of your UI
function AppViewModel() {
this.firstName = ko.observable("Bert");
this.lastName = ko.observable("Bertington");
this.fullName = ko.computed(function() {
return this.firstName() + " " + this.lastName();
}, this);
this.capitalizeLastName = function() {
var currentVal = this.lastName(); // Read the current value
this.lastName(currentVal.toUpperCase()); // Write back a modified value
};
}
// Activates knockout.js
ko.applyBindings(new AppViewModel());
}();
</script>
...along with
<script type="text/javascript" src="Scripts/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="Scripts/knockout-2.0.0.js"></script>
In my body I placed
<!-- This is a *view* - HTML markup that defines the appearance of your UI -->
<p>
First name: <strong data-bind="text: firstName"></strong>
</p>
<p>
Last name: <strong data-bind="text: lastName"></strong>
</p>
<p>
First name:
<input data-bind="value: firstName" /></p>
<p>
Last name:
<input data-bind="value: lastName" /></p>
<p>
Full name: <strong data-bind="text: fullName"></strong>
</p>
<button data-bind="click: capitalizeLastName">
Go caps</button>
The code was all taken from Knockout JS's tutorial, but somehow the values don't bind themselves automatically--in other words it doesn't work for me. Am I missing something here?
It looks to me like you JavaScript code is being executed before the DOM (your HTML) has been rendered. The JavaScript function you have included in the head is executed immediately. You need to ensure that this code is only executed when the page has been fully rendered.
You can do that with the jQuery ready function.
<script type="text/javascript">
$(document).ready(function () {
// your existing JavaScript goes here.
})
</script>
It's seems to me that You wrongly use anonymous function wrapper.
You need to add more ( ) to code.
(function() {
...
})();
Working example: http://jsfiddle.net/AlfeG/bZatD/
If you didn't want to use jQuery, You could also:
remove your outer self-executing function
put the script referencing knockout view models at the bottom of the body

Categories

Resources