Calling variable in template from view of backbone - javascript

I'm using text! plug-in of require.js to load javascript templates of my backbone project.
Here it is :
<table id="showcart">
<tr><td class="cartitemhead">Item to buy</td><td class="cartitemhead" style="text-align: center;">Quantity</td></tr>
<% _.each(item, function(item) { %>
<tr><td><table class="verticallist"><tr><td rowspan="4" style="width: 120px;"><img src="<%=item.PictureName%>" alt="Product" width="95px"/></td><td style="font-weight: bold;"><%=trimString(item.Name,50)%></td></tr><tr><td><i>Available in Stock(s)!</i></td></tr><tr><td><i>Rating: 650Va-390w Input: Single</i></td></tr></table></td><td class="centertxt"><%=item.QuantityInCart%></td></tr>
<% }); %>
</table>
item variable was declared in my view.
var CartListView = Backbone.View.extend({
render: function(){
var item = deserializeJSONToObj(window.localStorage.getItem("Cart"));
var cartList = _.template(showCartTemplate, {})
$("#cartlist").html(cartList);
}
});
Model :
define(["underscore" , "backbone"],function(_ , Backbone){
var Cart = Backbone.Model.extend({
});
});
I got one error from console : Uncaught ReferenceError: item is not defined.
Any help would be much appreciated, thank you.

You need to indicate somehow the value you want to pass for backbone template. Because you have defined a variable, Underscore template is looking for a value to get replaced with.
For this reason try to pass the model value as an argument to the appended view.
var CartListView = Backbone.View.extend({
render: function(){
var item = deserializeJSONToObj(window.localStorage.getItem("Cart"));
var cartList = _.template(showCartTemplate, {})
$("#cartlist").append({item : cartList});
}
});
This way, each time when undercore find a variable item it will replace with the value passed as argument to the view.

You need to pass the item key in the object that you pass in _.template
var CartListView = Backbone.View.extend({
render: function(){
var item = deserializeJSONToObj(window.localStorage.getItem("Cart"));
var cartList = _.template(showCartTemplate, {item : item})
$("#cartlist").append({item : cartList});
}
});
Because you can not access the item variable directly in template.

Related

Not sure how to template object of arrays using Backbone and Underscore templates

I have a collection where the data is returned looking like:
{
"departments": ["Customer Support", "Marketing"],
"classes": ["Planning", "Drawing"]
}
I'm not overly sure how to use underscore template loops to output each of the departments, right now I'm using ._each but my output is object Object. Can anyone advise how to resolve this?
Fiddle: http://jsfiddle.net/kyllle/aatc70Lo/7/
Template
<script type="text/template" class="js-department">
<select>
<% _.each(departments, function(department) { %>
<option value="<% department %>"><% department %></option>
<% }) %>
</select>
</script>
JS
var Department = Backbone.Model.extend();
var Departments = Backbone.Collection.extend({
model: Department,
parse: function(response) {
return response;
}
});
var DepartmentView = Backbone.View.extend({
template: '.js-department',
initialize: function() {
console.log('DepartmentView::initialize', this.collection.toJSON());
},
render: function() {
this.$el.html( this.template( this.collection.toJSON() ) );
}
});
var departments = new Departments({
"departments": ["Customer Support", "Marketing"]
}, {parse:true});
var departmentView = new DepartmentView({
collection: departments
});
document.body.innerHTML = departmentView;
You are not even calling render(), so your template is never even executed, and the object Object output has nothing to do to your template.
After you run render() you will realize
template: '.js-department'
doesn't work, because it is not Marionette, and Backbone will not compile the html by a selector for you. So you will replace it with something like this:
template: _.template($('.js-department').html())
Then you will have to realize this.collection is an array, that only has one item, so if you just want to render that first item, you will send to it to template:
this.$el.html( this.template( this.collection.first().toJSON() ) );
Then you will have to realize departmentView is a Backbone.View instance object, and isn't html itself. It has the el property which is the DOM element of this view instance, and $el property, which is the same DOM element wrapped with jQuery.
document.body.innerHTML = departmentView.el still will not work, because innerHTML expects a string. So you could instead do something like
document.body.appendChild( departmentView.el ); or
departmentView.$el.appendTo( document.body ); with jquery.
(For the last one to work render must return this)
Working jsfiddle: http://jsfiddle.net/yuraji/zuv01arh/

How to subscribe to items in collection/foreach DOM rendering

I have a view that is used to create and also update an item. I have this problem when updating where a function is running twice due to a change event on a dropdown list. What was suggested in my previous post is that I use a subscription to the value and create logic accordingly within the subscription. I think this is a great idea, however, I have no idea how I will apply these subscriptions to my model when the bindings are being applied dynamically from a view model sent to the view from a back-end controller method.
The collection items get their functionality from data-bind values provided in a foreach element loop and using $data. It would be preferred to keep this format for the solution.
<tbody data-bind="foreach: koModel.ModelData.Lines">
<tr class="form-group">
<td>...</td>
<td>..other model properties..</td>
<td>...</td>
<!-- v v v This is the property with the change event v v v -->
<td>#Html.SearchPickerMvcKOMultipleFor(
m => m.ItemNumber,
"ItemPicker",
new { #class = "form-control" }.AddMore(
"data-bind",
"MyProgramSearchPicker: ItemNumber, value: $data.ItemNumber, event: { change: ItemNumericDetails($data) }"
))</td>
<!-- ^ ^ ^ ^ ^ -->
<td>etc</td>
</tr>
</tbody>
The model is converted to JSON and then to a JavaScript variable:
#{
Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
string data = Newtonsoft.Json.JsonConvert.SerializeObject(Model);
#Html.Raw("var modelData = " + data + ";");
}
var koModel = new KOModel(modelData);
How can I apply a subscription to the ItemNumber property, either by executing an inline function from the element, or another method that can modify a dynamically rendered collection?
Create a class that represents a "line" of the koModel.ModelData.Lines
function Line(itemNumber) {
var self = this;
self.ItemNumber = ko.observable(itemNumber);
self.ItemNumber.subscribe(...);
};
koModel.ModelData.Lines.push(new Line(123));
Or, you can create a function in your view model:
function koModel() {
...
self.ItemNumericDetails = function (line) {
//do your job
};
};
and in the HTML:
<td>
#Html.SearchPickerMvcKOMultipleFor(
m => m.ItemNumber,
"ItemPicker",
new { #class = "form-control" }.AddMore(
"data-bind",
"MyProgramSearchPicker: ItemNumber, value: $data.ItemNumber, event: { change: $root.ItemNumericDetails }"
))
</td>

How do I access my viewmodel variables in my knockout component template?

I am trying to create a list of instruction steps using Knockout components/templates.
The UL is the going to contain a list of steps (using a knockout-registered custom element sidebar-step) which is just a template of <li></li>. I have another value this.testVar part of my model that could contain an attribute of <li> such as the class, or maybe a "data-customAttribute".
My question is, how do I include my testVar value into the template? I want it so that it might output a line like:
<sidebar-step class=*testVar* params="vm: sidebarStepModel">Message 1</sidebar-step>
Fiddle: https://jsfiddle.net/uu4hzc41/1/
HTML:
<ul>
<sidebar-step params="vm: sidebarStepModel"></sidebar-step>
</ul>
JavaScript:
ko.components.register("sidebar-step", {
viewModel: function (params) {
this.vm = params.vm;
},
template: "<li data-bind=\'text: vm.message\'></li>"
});
var SidebarStepModel = function () {
this.message = ko.observable("step description");
this.testVar = ko.observable("some value");
};
var ViewModel = function () {
this.sidebarStepModel = new SidebarStepModel();
this.sidebarStepModel.message("Message 1");
this.sidebarStepModel.testVar("69");
};
ko.applyBindings(new ViewModel());
You can use data-bind on the custom tag. To set class,
<sidebar-step data-bind="css:sidebarStepModel.testVar" params="vm: sidebarStepModel"></sidebar-step>
https://jsfiddle.net/uu4hzc41/3/

Backbone js.How to pass data from view to template in backbone js

I am new to Backbone js. Can some one help me to send data in template from my view.
My View has this code:
$('#top-bar').html(_.template($("#loginned-top-bar-template").html()));
and my template contains
<li class="menu-item"><%user_name%></li>
and I want to send "awsome_user"to it.
It would be great if any one would help me.
var compiled = _.template($("#loginned-top-bar-template").html());
var templateVars = {user_name : 'awesome_user' };
$('#top-bar').html( compiled(templateVars) );
<%user_name%> should be <%=user_name%> if you want to print the variable.
If you want to use other user_name, set user_name property before compiled function called.
var compiled = _.template($("#loginned-top-bar-template").html());
var templateVars = {user_name : 'awesome_user' };
templateVars.user_name = Parse.User.current().get("name");
$('#top-bar').html( compiled(templateVars) );

Odd behavior when trying to get the contents of a script element

I'm playing around with backbone and underscore templates. When I try to dereference the contents of a script block (using $("#people-templ").html()) I get two different behaviors depending on the context of the call. Inside the render function for the backbone view I get nothing returned. If I get the contents of the script block outside any function, I get the valid HTML contents. I tried this on Chrome, Safari, and Firefox. I stepped through with the debugger and validated that JQuery returned an empty array when calling $("#people-templ") within the callback function. I was wondering if someone had an explanation for this behavior.
In index.html I have a simple template:
<script type="text/template" id="people-templ">
<h1>People</h1>
<table>
<thead>
<tr><th>First Name</th><th>Last Name</th></tr>
</thead>
<tbody>
<% people.each(function(person) { %>
<tr>
<td><%= person.get("firstName") %></td>
<td><%= person.get("lastName") %></td>
</tr>
<% }) %>
</tbody>
</table>
</script>
<script src='/javascripts/lib/jquery-2.0.3.js'></script>
<script src='/javascripts/lib/underscore.js'></script>
<script src='/javascripts/lib/backbone.js'></script>
<script src="/javascripts/main/index.js"></script>
Inside index.js I have the following Backbone view definition:
var peopleHtml = $("#people-templ").html();
var PeopleView = Backbone.View.extend({
el: "#foo",
initialize: function() {
this.render();
},
render: function() {
var people = new People();
var me = this;
this.$el.empty();
people.fetch({
success: function(people) {
var template = _.template(peopleHtml, { people: people });
me.$el.html(template);
},
error: function() {
console.error("Failed to load the collection");
}
});
}
});
This works. The code gets the template from the script tag, Underscore processes it, and inserts the resulting markup into the DOM. If I move var peopleHtml = $("#people-templ").html(); inside of the callback, as such:
var PeopleView = Backbone.View.extend({
el: "#foo",
initialize: function() {
this.render();
},
render: function() {
var people = new People();
var me = this;
this.$el.empty();
people.fetch({
success: function(people) {
var template = _.template($("#people-templ").html(), { people: people });
me.$el.html(template);
},
error: function() {
console.error("Failed to load the collection");
}
});
}
});
Then it seems that nothing is returned from $("people-tempo").html() and the code failed inside of underscore.js when it tries to do text replacement when processing the template.
Does anyone know why this might be the case?
SOLVED thanks to Pointy
<div id="foo"/>
and
<div id="foo"></div>
are not the same thing. If the former is used, everything from the div on down (including all my script elements) were replaced by the templates text. using the latter, only the contents of the div are replaced.
When using elements for underscore templating, it looks like you need to use the
<div id='foo'></div>
form instead of just:
<div id='foo'/>

Categories