using underscore templates with Backbone and Require.js - backbone.js

I'm trying to create a simple app using underscore templates and backbone (as described in this article). I'm sure that the template file is being loaded correctly, but I'm not so sure whether I'm applying the model to the template properly. (See below example)
I have also checked the output of compiledTemplate variable, but it only contains the <h1> </h1> tags, so it looks like there may be something wrong with the format of my model. But I have not been able to come up witjh any solution so far hence I'm posting this here hoping that someone could possibly help me out with this ..
index.html
<head>
<script src="./dev_env/app/libs/vendor/require.min.js" data-main="dev_env/app/main"></script>
<script>
require(['app_init']);
</script>
</head>
<body >
<div id="test">
</div>
</body>
</html>
./templates/template.html
<h1> <%= obj.title %> </h1>
./app_init.js
require([ '../app' ], function(App){
App.initialize();
});
./app.js
define([ 'backbone', './router', 'underscore','jquery'], function (Backbone, Router, _, $) {
var initialize = function(){
Router.initialize();
}
return {
initialize: initialize
};
});
./models/model_menu.js
define([ 'underscore', 'backbone' ], function(_, Backbone){
var MenuModel = Backbone.Model.extend({
defaults: {
title: "Test1"
}
});
return MenuModel;
});
./collections/collection_menu.js
define([ 'underscore', 'backbone', 'models/model_menu'
], function(_, Backbone, MenuModel){
var MenuCollection = Backbone.Collection.extend({
model: MenuModel
});
return MenuCollection;
});
./router.js
define(['jquery','underscore', 'backbone', 'views/menu/view_menu'], function ($, _, Backbone, vMenu) {
var AppRouter = Backbone.Router.extend({
routes : {
'menu' : 'showMenu',
}
});
var initialize = function () {
var app_router = new AppRouter;
app_router.on('route:showMenu', function () {
var MyMenu = new vMenu();
MyMenu.render();
});
Backbone.history.start();
};
return {
initialize : initialize
};
});
./views/menu_view/view_menu.js
define([ 'jquery','underscore', 'backbone', 'collections/collection_menu', 'text!templates/template.html' ], function ($, _, Backbone, MenuCollection, myTempl) {
var MenuViiew = Backbone.View.extend({
el : $('#test'),
initialize : function () {
this.collection = new MenuCollection();
this.collection.add( {title: "Title2"});
var compiledTemplate = _.template( myTempl, { obj : this.collection.models} );
this.$el.html(compiledTemplate);
}
});
return MenuViiew;
});

I now understand where I was wrong, I misunderstand what a collection was therefore I couldn't make it work. Apologies for that, but I'm still learning this stuff.
here's the solution:
btw. I have changed the collection_menu to menu_collections so it's clear that the file contains a collection of menu models.
views/view_model.js
define([ 'jquery','underscore', 'backbone', 'collections/menu_collections', 'text!templates/template.html' ], function ($, _, Backbone, MenuCollections, myTempl) {
var MenuViiew = Backbone.View.extend({
el : $('#alex'),
initialize : function () {
this.collection = new MenusCollection()
this.collection.add({ title: "Test1" });
this.collection.add({ title: "Test2" });
},
render: function(){
var compiledTemplate = _.template(myTempl, { menus : this.collection.models});
this.$el.html(compiledTemplate);
}
});
return MenuViiew;
});
./templates/template.html
<% _.each(menus, function(menu) { %>
<h1> <%= menu.get('title') %> </h1>
<% }); %>

Related

Backbone / ReactJS view not recognizing JSX

I'm starting on a Backbone AMD application, using React.js for the views. The view is not recognizing the JSX I've written in the render() function. Am I missing a statement in the router or view? The error I'm receiving is 'Unexpected token <'.
Below is the app flow from top to bottom:
Index.html
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="style.css">
<!--<script src="http://fb.me/react-0.12.0.js"></script>
<script src="http://fb.me/JSXTransformer-0.12.0.js"></script> -->
<script data-main="js/main" src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.15/require.min.js"></script>
main.js
require.config({
paths: {
jquery: 'http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min',
underscore: 'http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min',
backbone: 'http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone-min',
react: 'http://fb.me/react-0.12.0',
JSXTransformer: 'http://fb.me/JSXTransformer-0.12.0'
}
});
require([
// Load our app module and pass it to our definition function
'app',
], function(App){
// The "app" dependency is passed in as "App"
App.initialize();
});
app.js
define([
'jquery',
'underscore',
'backbone',
'router' // Request router.js
], function($, _, Backbone, Router){
var initialize = function(){
// Pass in our Router module and call it's initialize function
Router.initialize();
}
return {
initialize: initialize
};
});
router.js
define([
'jquery',
'underscore',
'backbone',
'views/team/list'
], function($, _, Backbone, TeamListView){
var AppRouter = Backbone.Router.extend({
routes: {
// Define some URL routes
'team': 'showTeam',
// Default
'*actions': 'defaultAction'
}
});
var initialize = function(){
var app_router = new AppRouter;
app_router.on('route:showTeam', function(){
// Call render on the module we loaded in via the dependency array
// 'views/teams/list'
var teamListView = new TeamListView();
teamListView.render();
});
app_router.on('route:defaultAction', function(actions){
// We have no matching route, lets just log what the URL was
console.log('No route:', actions);
});
Backbone.history.start();
};
return {
initialize: initialize
};
});
list.js
/**
* #jsx React.DOM
*/
define(
[
'jquery',
'underscore',
'backbone',
'react',
'JSXTransformer'
], function($, _, Backbone, react, JSXTransformer){
var MyWidget = React.createClass({
handleClick: function() {
alert('Hello!');
},
render: function() {
return (
<a href="#" onClick={this.handleClick}>Do something!</a>
);
}
}),
var TeamListView = Backbone.View.extend({
el: 'body',
template: '<div class="widget-container"></div>',
render: function() {
this.$el.html(this.template);
React.renderComponent(new MyWidget(), this.$('.widget-container').get(0));
return this;
}
});
// Our module now returns our view
return TeamListView;
});
list.js (updated - working version)
define(
[
'jquery',
'underscore',
'backbone',
'react'
], function($, _, Backbone, React){
var MyWidget = React.createClass({displayName: 'MyWidget',
handleClick: function() {
alert('Hello!');
},
render: function() {
return (<div>
<ul>
<li></li>
<li></li>
</ul>
<div>Test</div>
<a href="#" onClick={this.handleClick}>Do something!</a>
</div>
)
}
});
var TeamListView = Backbone.View.extend({
el: $('#mainContent'),
events: {
},
initialize: function() {
console.log('test');
},
render: function (){
React.render(
React.createElement(MyWidget, null),
document.getElementById('mainContent')
);
}
});
return TeamListView;
});
JSX must be compiled to JavaScript before browsers can understand it.
You can use the jsx tool to do this.
JSX transformer and Require.js are incompatible.
If you're using RequireJS, you can use a JSX plugin like this one. For what it's worth, when I integrated the JSX transformer into our RequireJS setup, it required quite a bit of tweaking and experimentation.

Calling view function from another view from autocomplete

I have the following views in my application.
sets.js
define([
'jquery',
'underscore',
'backbone',
'bootstrap',
'jqueryui',
'numberformat',
'text!templates/sets/sets.html'
], function ($, _, Backbone, bootstrap, jqueryui, numberformat, setsTemplate) {
var setsView = Backbone.View.extend({
el: $("#contenido"),
events: {
'keyup table tbody input': 'afterRender'
},
initialize: function (options) {
_.bindAll(this, 'render', 'afterRender');
this.options = options || {};
},
render: function () {
var data = {sets: this.options.sets};
var compiledTemplate = _.template(setsTemplate, data);
this.$el.html(compiledTemplate);
$(".alert").addClass('alert-' + this.options.clase);
var tabs = $("#tabs").tabs();
tabs.find(".ui-tabs-nav").sortable({
axis: "x",
stop: function () {
tabs.tabs("refresh");
}
});
$('#emisor').hide();
this.afterRender();
},
afterRender: function () {
console.log('afterRender');
var ventasView = new VentasView();
ventasView.render();
}
})
return setsView;
});
ventas.js
define([
'jquery',
'underscore',
'backbone',
'bootstrap',
'jqueryui',
'text!templates/cliente/cliente.html',
'models/cliente',
'views/sets/sets'
], function ($, _, Backbone, bootstrap, jqueryui, clienteTemplate, SetsView) {
var clienteView = Backbone.View.extend({
el: $("#cliente"),
initialize: function (options) {
this.options = options || {};
},
render: function () {
$("#cliente").html(clienteTemplate);
$('#rut').autocomplete(
{
source: '/clientes/buscar/',
minLength: 1,
dataType: 'json',
cache: false,
select: function (event, ui) {
$("#rut").val(ui.item.Cliente.rut);
$("#id").val(ui.item.Cliente.id);
$("#razon").val(ui.item.Cliente.razon);
$("#giro").val(ui.item.Cliente.giro);
$("#direccion").val(ui.item.Cliente.direccion);
$("#comuna").val(ui.item.Cliente.comuna);
$("#ciudad").val(ui.item.Cliente.ciudad);
var sets = new SetsView();
sets.afterRender();
return false;
}
}).data("autocomplete")._renderItem = function (ul, item) {
return $("<li></li>").data("item.autocomplete", item).append("<a><strong>" + item.Cliente.rut + "</strong></a>").appendTo(ul);
};
}
});
return clienteView;
});
error
Uncaught TypeError: Object [object Object] has no method 'afterRender'
You are missing a parameter in your function :
function ($, _, Backbone, bootstrap, jqueryui, clienteTemplate, SetsView)
function ($, _, Backbone, bootstrap, jqueryui, clienteTemplate, clienteModel, SetsView)

backbone.js Uncaught TypeError: Cannot read property 'View' of null

When I run my backbone app in NetBeans 7.3.1, the main page displays for a few seconds, maybe 5 or 6, then in NetBeans output I see the following...
Uncaught TypeError: Cannot read property 'View' of null (18:43:36:307 | error, javascript)
at (js/views/HomeView.js:6:28)
at d.execCb (js/libs/require/require.js:27:197)
at o (js/libs/require/require.js:10:471)
at (js/libs/require/require.js:12:184)
at o (js/libs/require/require.js:12:75)
at (js/libs/require/require.js:14:1)
at o (js/libs/require/require.js:12:75)
at l (js/libs/require/require.js:12:336)
at g.finishLoad (js/text.js:10:192)
at g.load (js/text.js:10:354)
at window.undefined.window.navigator.window.document.c.onreadystatechange (js/text.js:7:30)
Uncaught TypeError: Cannot read property 'Model' of null (18:43:36:317 | error, javascript)
at (js/models/Member.js:6:26)
at d.execCb (js/libs/require/require.js:27:197)
at o (js/libs/require/require.js:10:471)
at x (js/libs/require/require.js:15:186)
at m (js/libs/require/require.js:15:207)
at g.completeLoad (js/libs/require/require.js:21:388)
at d.onScriptLoad (js/libs/require/require.js:27:490)
Uncaught Error: Load timeout for modules: text!templates/homeTemplate.html
http://requirejs.org/docs/errors.html#timeout (18:43:38:511 | error, javascript)
at N (js/libs/require/require.js:7:217)
at A (js/libs/require/require.js:16:230)
at (js/libs/require/require.js:16:394)
It looks like RequireJS is failing to load Backbone. Here is main.js...
// Filename: main.js
require.config({
shim: {
underscore: {
exports: '_'
},
backbone: {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
}
},
paths: {
jquery: 'libs/jquery/jquery-min',
underscore: 'libs/underscore/underscore-min',
backbone: 'libs/backbone/backbone-min',
templates: '../templates'
}
});
require([
'app',
], function(App) {
App.initialize();
});
I'm totally spinning my wheels on this. Why is Require not loading Backbone?
#Sushanth--: Edited original post to include HomeView.js
Here is the HomeView.js...
define([
'jquery',
'underscore',
'backbone',
'text!templates/homeTemplate.html'
], function($, _, Backbone, homeTemplate) {
var HomeView = Backbone.View.extend({
el: $("#page"),
initialize: function() {
},
render: function() {
var compiledTemplate = _.template( homeTemplate, {} );
this.$el.html( compiledTemplate );
}
});
return HomeView;
});
#Sushanth--: I'm rendering from the router.js...
// Filename: /js/router.js
define([
'jquery',
'underscore',
'backbone',
'views/HomeView',
'views/MembersView'
], function($, _, Backbone, HomeView, MembersView) {
var AppRouter = Backbone.Router.extend({
routes: {
// Define some URL routes
'members': 'showMembers',
// Default
'*actions': 'defaultAction'
}
});
var initialize = function(){
//alert('router init');
var app_router = new AppRouter;
app_router.on('route:showMembers', function () {
// Like above, call render but know that this view has nested sub views which
// handle loading and displaying data from the GitHub API
var membersView = new MembersView();
});
app_router.on('route:defaultAction', function (actions) {
// We have no matching route, lets display the home page
var homeView = new HomeView();
homeView.render();
});
// Unlike the above, we don't call render on this view as it will handle
// the render call internally after it loads data. Further more we load it
// outside of an on-route function to have it loaded no matter which page is
// loaded initially.
//var footerView = new FooterView();
//alert('hello from router.js');
//Backbone.history.start({pushState: true, root: "/modular-backbone/"});
//Backbone.history.start({pushState: true});
Backbone.history.start();
};
return {
initialize: initialize
};
});
Added a test alert in main.js, app.initialize...
require(['app'], function(App) {
// THIS ALERT NEVER DISPLAYS!?!?!
alert('inside main.js before app.initialize');
App.initialize();
});
I replaced my Backbone and Underscore js files with the AMD versions and it started working.

Handeling response from backbone.js collection using fetch

am pretty new to backbone.js and managed recently to finish my first application. I made a collection that is responsible for fetching data through a API but am not able to loop through the result and use it.
Here is my model file
define([
'jquery',
'underscore',
'backbone'
], function($, _, Backbone){
var VehicleLookupModel = Backbone.Model.extend({
//data will contain one of the items returned from the collection's 'parse' function.
parse: function(data){
return data;
}
})
return VehicleLookupModel;
});
collection file
define([
'jquery',
'underscore',
'backbone',
'l/models/VehicleLookupModel'
], function($, _, Backbone, VehicleLookupModel){
var VehicleLookupModelSet = Backbone.Collection.extend({
model : VehicleLookupModel,
url : function() {
return '/en/car/api/model-lookup-model.json/'+this.make+'/';
},
parse : function(response) {
return response;
},
initialize: function(options) {
options || (options = {});
this.make = options.make;
}
})
return VehicleLookupModelSet;
});
and finally the view file
define([
'jquery',
'underscore',
'backbone',
'l/collections/VehicleLookupMakeSet',
'l/collections/VehicleLookupModelSet',
'l/collections/VehicleLookupTrimSet'
], function($, _, Backbone, VehicleLookupMakeSet, VehicleLookupModelSet, VehicleLookupTrimSet){
var BrowseVehicleView = Backbone.View.extend({
el: $('#vehicle-browse-form'),
initialize: function(){
// Extend JQuery example
// This would extend JQuery function for resetting elements on the form
$.fn.extend({
resetElement: function(){
$(this).attr('disabled', 'disabled');
$(this).html('');
return $(this);
}
});
// define array of elements to be used in DOM manipulations
this.elements = {
"make" : $('#id_make', this.el),
"model" : $('#id_model', this.el),
"trim" : $('#id_trim', this.el),
"year" : $('#id_year', this.el)
}
},
events: {
"change #id_make" : "onMakeChange",
"change #id_model" : "onModelChange",
"change #id_trim" : "onTrimChange"
},
render: function(){
// Using Underscore we can compile our template with data
},
onMakeChange: function(event) {
this.elements.model.resetElement();
this.elements.trim.resetElement();
this.collection = new VehicleLookupModelSet({make: this.elements.make.val()})
this.collection.fetch();
console.log(this.collection);
},
onModelChange: function(event) {
var VehicleLookupTrimInstance = new VehicleLookupTrimSet({make: this.elements.make.val(), model: this.elements.model.val()})
VehicleLookupTrimInstance.fetch();
},
onTrimChange: function(event) {
},
renderItem: function(object, item) {
console.log(item);
}
});
// Our module now returns our view
return new BrowseVehicleView;
});
The above is console.log(this.collection) is returning an object with many property which am not sure how to use. But, I noticed that there is a method "models" and inside models there is many number of objects, each represent the value of the json.
Any ideas how i can loop through the object?
this.collection.fetch({
success: function(collection, response) {
_.each(collection.models, function(model) {
console.log(model.toJSON());
})
}
});

Backbone.js view events registered but not firing

Just getting started here and cannot seem to get this very basic thing working. All my elements render as I expect. My events register in firefox in the "events" tab, but none of them seem to fire (click, mouseover, etc). I am using the following.
backbone 0.9.2
underscore 1.4.1
Marionette .10.2
require-jquery (requireJs 2.1.0) (jquery 1.8.2)
Router
define([
'jquery',
'backbone',
'underscore',
'views/TodaysProgramsView',
'collections/ProgramSnippetCollection'],
function($, Backbone, _, TodaysProgramsView, ProgramSnippetCollection){
return Backbone.Router.extend({
initialize:function () {
var programSnippetCollection = new ProgramSnippetCollection([
{title:'underwater basket weaving'},
{title:'How to win friends and influence people and stuff'}
]);
this.mainView = new TodaysProgramsView({
el : $("#todays_programs"),
collection:programSnippetCollection
});
Backbone.history.start();
},
routes:{
'':'home'
},
'home':function () {
this.mainView.render();
}
});
});
Collection View [TodaysProgramsView.js]
define([
'jquery',
'backbone',
'underscore',
'views/ProgramSnippetView'],
function($, Backbone, _, ProgramSnippetView){
return Backbone.Marionette.CollectionView.extend({
events: {
"click" : "clicked"
},
clicked : function(){
alert("parent clicked")
},
itemView : ProgramSnippetView
});
});
Item View [ProgramSnippetView.js]
define([
'jquery',
'backbone',
'underscore',
'text!templates/programSnippet.html'],
function($, Backbone, _, template){
return Backbone.Marionette.ItemView.extend({
events: {
"click" : "courseClicked",
'mouseover' : 'mousedOver'
},
render: function(){
var json = this.model.toJSON();
console.log("RENDERING SNIPPET with data", json);
$(this.el).html( _.template(template, json) );
return this;
},
courseClicked : function(){
alert("you clicked a course, good work");
},
mousedOver : function(){
console.log("Mousin!");
}
});
});
After much frustration and many hours of javascript tweaking, I noticed that there was a div set with a z-index to 2. This was overlaying my target and gobbling up all the events. Sigh.

Resources