Require.js Backbone loading view issue - backbone.js

I have a backbone project that I am converting to require.js so I can learn how to use it. My backbone project works fine before converting. I have gone through and converted the project to use require.js, but in doing so the static data I load into my view from my app.js is not visible. Additionally, I am not able to display any new data added from the form on index.html.
Something is inhibiting the view from showing. I keep getting the error "Uncaught TypeError: undefined is not a function" on line 17 of my app.js file in the console in chrome. Below are my files. I am pretty sure I am missing something here conceptually, and any input to help me understand why I am not getting this to work would be greatly appreciated.
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Inventory App</title>
<link rel="stylesheet" href="assets/less/style.css">
</head>
<body>
<div id="items">
<form class="item_form" id="addItem" action="#" name="item_form">
<div>
<ul>
<li>
<h2>Inventory App</h2>
<span class="required_notification">* Denotes Required Field</span>
</li>
<li>
<label for="component">Component:</label>
<input type="text" name="component" id="component"placeholder="Component" required/>
</li>
<li>
<label for="stockQty">Stock Qty:</label>
<input type="number" name="stockQty" id="stockQty"placeholder="Stock Qty" required/>
</li>
<li>
<label for="reorderQty">Reorder #:</label>
<input type="number" number="reorderQty" id="reorderQty" placeholder="Reorder #" required/>
</li>
<li>
<label for="qtyPerCrane">Qty per Crane:</label>
<input type="number" name="qtyPerCrane" id="qtyPerCrane" placeholder="Qty per Crane" required/>
</li>
<li>
<label for="vendorId">Vendor Id:</label>
<input type="number" name="vendorID" id="vendorID" placeholder="Vendor ID" required/>
</li>
<li>
<button class="submit" id="add" >Add</button>
</li>
</ul>
</div>
</form>
<!-- Label Html goes here-->
<table id="inventory-grid">
<thead>
<tr>
<th>Component</th>
<th>Stock Qty</th>
<th>Qty Per Crane</th>
<th>Reorder Qty</th>
<th>Vendor ID</th>
<th> </th>
</tr>
</thead>
<tbody id="inventory-holder"></tbody>
</table>
</div>
<!-- render inventory items-->
<script id="inventoryTemplate" type="text/template">
<td> <%= component %> </td>
<td> <%= stockQty %> </td>
<td> <%= qtyPerCrane %> </td>
<td> <%= reorderQty %> </td>
<td> <%= vendorID %> </td>
<td> <button class="delete">Delete</button> </td>
</script>
<script data-main='js/main' src="js/lib/require.js"></script>
</body>
</html>
main.js
//configure RequireJS
requirejs.config({
paths: {
jquery: 'lib/jquery',
backbone: 'lib/backbone',
localStorage: 'lib/backbone.localStorage',
underscore: 'lib/underscore',
views: 'views',
models: 'models',
collections: 'collections'
},
// Shim declaration
'shim': {
'underscore': {
'exports': '_'
},
'backbone': {
'deps': ['jquery', 'underscore'],
'exports': 'Backbone'
}
}
});
// call app.js to load static data
define(['app'], function(AppView) {
var AppView = new AppView();
});
app.js
// load view with data
define (['jquery', 'backbone'], function($,Backbone) {
var app = app || {};
$(function() {
var inventory = [
{ component: 'bottom bracket', stockQty: '22', reorderQty: '15', qtyPerCrane: '13', vendorID: 'Foster Machine' },
{ component: 'bottom bracket', stockQty: '22', reorderQty: '15', qtyPerCrane: '13', vendorID: 'Foster Machine' },
{ component: 'bottom bracket', stockQty: '22', reorderQty: '15', qtyPerCrane: '13', vendorID: 'Foster Machine' },
{ component: 'bottom bracket', stockQty: '22', reorderQty: '15', qtyPerCrane: '13', vendorID: 'Foster Machine' },
{ component: 'bottom bracket', stockQty: '22', reorderQty: '15', qtyPerCrane: '13', vendorID: 'Foster Machine' }
];
console.log('inventory loaded');
// THIS IS WHERE THE ERROR GETS THROWN
new app.InventoryView( inventory );
});
});
item.js (views)
// site/js/views/item.js
define(['jquery', 'backbone'], function($, Backbone) {
var app = app || {};
app.ItemView = Backbone.View.extend({
tagName: 'tr',
className: 'itemContainer',
template: _.template( $( '#inventoryTemplate' ).html() ),
events: {
'click .delete': 'deleteItem'
},
deleteItem: function() {
//Delete model
this.model.destroy();
//Delete view
this.remove();
},
render: function() {
//this.el is what we defined in tagName. use $el to get access to jQuery html() function
this.$el.html( this.template( this.model.attributes ) );
return this;
}
});
});
inventory.js (views)
// site/js/views/inventory.js
define(['jquery', 'backbone'], function($, Backbone) {
var app = app || {};
app.InventoryView = Backbone.View.extend({
el: '#items',
initialize: function( initialInventory ) {
this.collection = new app.Inventory( initialInventory );
this.listenTo( this.collection, 'add', this.renderItem );
this.render();
},
events:{
'click #add':'addItem'
},
addItem: function( e ) {
e.preventDefault();
var formData = {};
$( '#addItem li' ).children( 'input' ).each( function( i, el ) {
if( $( el ).val() != '' )
{
formData[ el.id ] = $( el ).val();
}
});
this.collection.add( new app.Item( formData ) );
},
// render inventory by rendering each book in its collection
render: function() {
this.collection.each(function( item ) {
this.renderItem( item );
}, this );
},
// render an item by creating an ItemView and appending the
// element it renders to the inventory's element
renderItem: function( item ) {
var itemView = new app.ItemView({
model: item
});
this.$el.find('#inventory-holder').append( itemView.render().el );
}
});
});
item.js (models)
// site/js/models/item.js
define(['jquery', 'backbone'], function($, Backbone) {
var app = app || {};
app.Item = Backbone.Model.extend({
defaults: {
component: 'no component',
stockQty: 'no stock qty',
reorderQty: 'no reorder qty',
qtyPerCrane: 'qty per crane',
vendorID: 'vendor ID'
}
});
});
inventory.js (collections)
// site/js/collections/inventory.js
define(['jquery', 'backbone'], function($, Backbone) {
var app = app || {};
app.Inventory = Backbone.Collection.extend({
model: app.Item
});
});

I suggest you study an example backbone/requirejs application, to get a feeling, i recommend this excellent project: https://github.com/BenjaminAdams/RedditJS/blob/master/public/js/app/App.js.
So the way you define your application is:
// app.js
define(["jquery", "backbone"], function($, Backbone) {
// not exactly this but similar define your app here.
// get rid of all of this: `var app = app || {};`
var App = new Backbone.application();
// don't forget to return the Backbone App.
return App;
});
define a backbone view:
// sampleView.js
define(["App", "backbone", "hbs!template/comment"], function(App, Backbone, commentTmpl) {
// Use the variable App safely here rather than `var app = app || {};`
return Backbone.View.extend({});
});
define a backbone controller:
define(["App", "backbone"], function(App, Backbone) {
return Backbone.Controller.extend({});
});
define a backbone router:
define(["App", "backbone"], function(App, Backbone) {
var AppRouter = Backbone.AppRouter.extend({});
return AppRouter;
});
Finally fire up with requirejs require function: eg(see here)
require(["App", "router", "jquery", "backbone"], function(App, AppRouter) {
App.appRouter = new AppRouter();
App.start();
});
Note that, this is just a dummy example, you should get the idea and apply it to your application backbone way.

new app.InventoryView( inventory ); would throw error because it is undefined in app.js.
You need to load the InventoryView.js inside the app.js like
define (['jquery', 'backbone', 'InventoryView'], function($,Backbone,InventoryView) {
var app = app || {};
$(function() {
var inventory = [
{ component: 'bottom bracket',.... },....... Your Code
];
console.log('inventory loaded');
app.InventoryView = InventoryView( inventory );
// AND NOW YOU CAN CALL YOUR LINE
new app.InventoryView();
});
});
While using RequireJS you must load the file(make sure it returning some value) and take reference of it in the inline function and use it.

Related

backbone and underscore template rendering

I'm trying to use backbone to show on a page the result from an API call, I would like to iterate over the collection and create one entry for every element of the collection within my html. It seems I'm missing something cause I see the template tag rendered but none of my items are there. What's the problem with my code?
here the html
<div class="form-group" id="main">
<% _.each(collection, function(car) { %>
<div class="form-group">
<input class="form-control" /><%= car.get("model") %>
</div>
<% }); %>
</div>
and here js
var CarView = Backbone.View.extend({
el: "#main",
template: _.template($("#main").html()),
initialize: function() {
this.render();
},
render: function() {
$(this.el).html(this.template({collection: [{id:1, model:"ford"}, {id:2,model:"kia"}]}));
return this;
}
});
var carView = new CarView();
here the fiddle: https://jsfiddle.net/e5hg6rzp/3/
First of all I suggest you to keep your template in <script type='text'/template> ... </script> tag. Secondly you are using .get() method inside your template on plain objects which are do not have this method. In your example you can access property through a . -
<div class="form-group">
<input class="form-control" /><%= car.model %>
</div>
Check this fiddle
If you want to use Backbone.Collection when you should create Car Collection and Car Model:
var data = [{
id: 1,
model: "ford"
}, {
id: 2,
model: "kia"
}];
var CarView = Backbone.View.extend({
el: "#main",
template: _.template($("#templ").html()),
initialize: function() {
this.render();
},
render: function() {
return this.$el.html(this.template(new CarCollection(data)))
}
});
var CarModel = Backbone.Model.extend({
defaults: {
id: '',
model: ''
}
})
var CarCollection = Backbone.Collection.extend({
model: CarModel
})
var carView = new CarView();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone.js"></script>
<div class="container">
<div class="form-inline panel panel-default">
<div class="form-group" id="main">
</div>
</div>
</div>
<script type='text/template' id='templ'>
<% _.each(models, function(car) { %>
<div class="form-group">
<input class="form-control" />
<%= car.get('model') %>
</div>
<% }); %>
</script>

how to replace view with another view in backbone.js on runtime

I am trying to build backbone.js application with twitter API.
the application that I am working on performs 3 tasks:1-returns the recent tweets on the user 's timeline, 2-returns the user profile 3- provides the ability to search in twitter. my problem is that I want the results of the search functionality to appear in the location of the tweets when the user clicks the search button. in my code there is view to display the tweets and another view to display the results of searching..how to put view in the place of another view on runtime. here is some of the code to explain the idea:
index.html :
<body>
<header role="banner">
<!—some code here-->
</header>
<div id="search" class="inner-search">
<form>
<label>Search for</label>
<input type="search" id="searchbox" style="width: 70%;"
autofocus="" placeholder="I'm looking for.."/>
<button id="searchbutton" style="width: 10%;">Go</button>
</form>
</div><!--search-view-->
<div class="inner-content">
<nav role="navigation">
<ul class="chapter-list">
………
</ul>
</nav>
<div role="main" class="main-content metrouicss">
<div id='timeline' class='timeline-view'>
<h3>Tweets </h3>
</div>
</div><!--main-->
<div role="right" class="right-content">
<h3>My Profile </h3>
<div id="profile" class="profile-view">
<!-- This would be the template -->
</div></div><!--right-->
</div> <!-- /.content-wrapper -->
<footer role="contentinfo">
<div class="inner-footer">
<p class="copyright">© Eva Hriekes, 2015. All rights
reserved.</p>
</div> <!-- /.inner-footer -->
</footer>
<!-- Template for profile -->
<script type="text/x-handlebars-template" id="profile-template">
<div class='tiles clearfix'>
<div class="tile double bg-color-orangeDark">
<div class="tile-content">
<img src="{{user.profile_image_url}}" class="place-left">
<h3 style="margin-bottom: 5px;">{{user.name}}</h3>
<p style="float:left;">{{user.description}}</p>
<div class="brand">
<div class="badge">{{user.followers_count}} Followers</div>
</div>
</div>
</div>
</div>
</script>
<!-- Template for timeline -->
<script type="text/x-handlebars-template" id="timeline-template">
<ul class='listview fluid'>
{{#each tweet}}
<li >
<div class='icon'>
<img src='{{user.profile_image_url}}'></img>
</div>
<div class='data'>
<h4>{{user.name}}</h4>
<p>{{format text}}</p>
<p class="timestamp" style="text-decoration:underline;">
<i>{{friendlyDate}}</i></p>
<p style="font-weight:bold;">Rating:
<i class="fa fa-star-o"></i><i class="fa fa-star-
o"></i><i class="fa fa-star-o"></i><i class="fa fa-star-
o"></i><i class="fa fa-star-o"></i></p>
</div>
</li>
{{/each}}
</ul>
</script>
<!-- Template for search results -->
<script type="text/x-handlebars-template" id="search-template">
<ul class='listview fluid'>
{{#each tweet}}
<li >
<div class='icon'>
<img src='{{user.profile_image_url}}'></img>
</div>
<div class='data'>
<h4>{{user.name}}</h4>
<p>{{format text}}</p>
<p class="timestamp" style="text-decoration:underline;">
<i>{{friendlyDate}}</i></p>
</div>
</li>
{{/each}}
</ul>
</script>
<script data-main="js/main" src="js/vendor/require.js"></script>
</body>
</html>
timeline view:
define(['jquery', 'handlebars', 'backbone', 'app/collection
/Timeline','app/view/ProfilePopupView'],
function($, Handlebars, Backbone, Timeline,ProfilePopupView) {
var com = com || {};
com.apress = com.apress || {};
com.apress.view = com.apress.view || {};
com.apress.view.TimelineView = Backbone.View.extend({
el: '#timeline',
template: Handlebars.compile($("#timeline-template").html()),
timeline: null,
events: {
'click .profile': 'showDialog'
},
initialize: function(options){
var self = this;
//create a collection for this view to render
self.timeline = new Timeline();//new
com.apress.collection.Timeline();
//initial render
self.render();
//force the fetch to fire a reset event
self.timeline.fetch({reset:true
});
self.listenTo(self.timeline, 'reset', self.render);
},
render: function(){
var self = this;
if(self.timeline.models.length > 0){
var output = self.template({tweet: self.timeline.toJSON()});
self.$el.append(output);
}
return self;
},
showDialog: function(options){
var self =this,
$target = $(options.currentTarget),
username = $target.data('user');
/**
* Reuse the profile view
**/
var profileView = new ProfilePopupView({user: username});
}
});
// export stuff:
return com.apress.view.TimelineView;
});
search view:
define(['jquery', 'backbone'], function($, Backbone) {
var com = com || {};
com.apress = com.apress || {};
com.apress.view = com.apress.view || {};
com.apress.view.SearchView = Backbone.View.extend({
el: '#search',
model: null,
events: {
'click #searchbutton': 'runSearch'
},
initialize: function(options){
var self = this;
self.model = options.model;
},
runSearch: function(e){
var self = this;
query = $('#searchbox').val();
e.preventDefault();
console.log('Run search against ' + query);
//force a reset
self.model.set('query', '', {silent: true});
self.model.set('query', query);
}
});
return com.apress.view.SearchView;
});
results view:
define(['jquery', 'backbone', 'handlebars','dialog'], function($,
Backbone, Handlebars,Dialog) {
var com = com || {};
com.apress = com.apress || {};
com.apress.view = com.apress.view || {};
com.apress.view.ResultsView = Backbone.View.extend({
el: '#results', /* or should be el="#timeline"???*/
model: null,
template: Handlebars.compile($("#search-template").html()),
initialize: function(options){
var self = this;
self.model = options.model;
self.model.fetch({
error: function(e){
self.model.trigger("app:error", {message: 'Error
retrieving timeline information'});
},
success: function(e){
self.model.trigger("app:success", {message: 'success
retrieving timeline information'});
}
});
self.listenTo(self.model,'change', self.render);
self.render();
},
render: function(){
console.log('Display now');
var self = this,
output = self.template({tweet: self.model.get('statuses')});
/* I want to delete this code and display the results
in the place of tweets*/
$.Dialog({
'title' : 'Search Results',
'content' : output,
'draggable' : true,
'overlay' : true,
'closeButton' : true,
'buttonsAlign': 'center',
'keepOpened' : true,
'position' : {
'zone' : 'left'
},
'buttons' : {
'OK' : {
'action': function(){}
}
}
});
}
});
return com.apress.view.ResultsView;
});
can anyone help me in doing what I want?

Controller undefinded in angular despite proper wiring

I am getting the following error:
Error: [ng:areq] http://errors.angularjs.org/1.3.2/ng/areq?p0=NavigationController&p1=not%20a%20function%2C%20got%20undefined
at Error (native)
at http://localhost:59838/bundles/angular?v=eGVVmShKFZLix9VnkpB8psikEOhD8WAVwpsLlHRCbyE1:6:416
at Nb (http://localhost:59838/bundles/angular?v=eGVVmShKFZLix9VnkpB8psikEOhD8WAVwpsLlHRCbyE1:19:417)
at ob (http://localhost:59838/bundles/angular?v=eGVVmShKFZLix9VnkpB8psikEOhD8WAVwpsLlHRCbyE1:20:1)
at http://localhost:59838/bundles/angular?v=eGVVmShKFZLix9VnkpB8psikEOhD8WAVwpsLlHRCbyE1:75:177
at http://localhost:59838/bundles/angular?v=eGVVmShKFZLix9VnkpB8psikEOhD8WAVwpsLlHRCbyE1:57:112
at r (http://localhost:59838/bundles/angular?v=eGVVmShKFZLix9VnkpB8psikEOhD8WAVwpsLlHRCbyE1:7:408)
at I (http://localhost:59838/bundles/angular?v=eGVVmShKFZLix9VnkpB8psikEOhD8WAVwpsLlHRCbyE1:56:496)
at g (http://localhost:59838/bundles/angular?v=eGVVmShKFZLix9VnkpB8psikEOhD8WAVwpsLlHRCbyE1:51:299)
at g (http://localhost:59838/bundles/angular?v=eGVVmShKFZLix9VnkpB8psikEOhD8WAVwpsLlHRCbyE1:51:316)
Here is my app.js:
(function () {
'use strict';
var app = angular.module('app', ['navigation']);
})();
here is the navigation controller:
function() {
var navigation = angular.module('navigation', []);
navigation.controller('NavigationController', function () {
this.tabs = [
{ title: 'First Tab', content: 'Controllers\FirstTab' },
];
});
})();
And here is the partial view that renders this: (It is currently not getting here)
<div ng-controller="NavigationController as nav">
<ul class="nav nav-pills">
<li ng-repeat="tab in nav.tabs">{{tab.title}}</li>
</ul>
</div>
To me (a noob in angular) everything looks good. What am I missing?
UPDATE:
Fiddle
You can check this:
var navigation = angular.module('navigation', []);
var app = angular.module('myApp', ['navigation']);
navigation.controller('NavigationController', function ($scope) {
$scope.tabs = [
{ title: 'First Tab', content: 'Controllers\FirstTab' },
{ title: 'Second Tab', content: 'Controllers\SecondTab' },
{ title: 'Third Tab', content: 'Controllers\ThirdTab' },
{ title: 'Fourth Tab', content: 'Controllers\FourthTab' },
{ title: 'Fifth Tab', content: 'Controllers\FifthTab' },
{ title: 'Sixth Tab', content: 'Controllers\SixthTab' },
{ title: 'Seventh Tab', content: 'Controllers\SeventhTab' }
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="NavigationController as nav">
<div ng-repeat="tab in tabs">
<b> {{ tab.title}} </b> {{ tab.content}}
</div>
</div>
</div>

Backbone Marionette events, Zurb Foundation's Reveal Modals

I'm building a modal popup by jamming a Backbone Marionette itemview into a Foundation Reveal modal. The modals appear but no events fire. Specifically, I'm trying to catch a click event.
I load Foundation from a Marionette Layout view.
'use strict';
define([
'jquery',
'underscore',
'backbone',
'region/actionbar',
'region/modal',
'text!/js/template/global.ejs',
'js/views/actionbar/actionbar.js',
'less!/style/global.less',
'css!/js/bower_components/foundation/css/foundation.css',
'/js/bower_components/foundation/js/foundation/foundation.js',
'/js/bower_components/foundation/js/foundation/foundation.reveal.js',
'marionette'
], function ($, _, Backbone, ActionBar, Modal, Template, ActionBarView) {
var GlobalLayout = Backbone.Marionette.Layout.extend({
template: _.template(Template),
el: 'body',
regions: {
content: "#content",
actionBar: ActionBar,
modal: '#modal'
},
initialize: function(){
},
onRender: function(){
// Load foundation
$(document).foundation();
},
title: function(title) {
// this.actionbar.title(title);
// document.title = "Workbench :: " + title;
}
});
var layout = new GlobalLayout();
layout.render();
return layout;
});
The popup is being loaded from a click event in a view in the actionbar region. Here's the Region:
'use strict';
define([
'jquery',
'underscore',
'backbone',
'marionette'
], function ($, _, Backbone) {
var ActionBar = Backbone.Marionette.Region.extend({
el: "#action-bar"
});
return ActionBar;
});
...and here's the View in that region. onSignUp() jams my SignUp modal into the Modal region. It then re-initializes foundation.
'use strict';
define([
'jquery',
'underscore',
'backbone',
'layout/global',
'/js/views/modals/sign-up.js',
'/js/views/modals/sign-in.js',
'model/user',
'text!/js/template/actionbar/actionbar.ejs',
'less!/style/global.less',
'marionette'
], function ($, _, Backbone, layout, SignUp_Modal, SignIn_Modal, User, Template) {
var ActionBarView = Backbone.Marionette.ItemView.extend({
initialize: function(){
this.setElement('#action-bar');
},
template: _.template(Template),
events: {
"click .sign-in" : "onSignIn",
"click .sign-up" : "onSignUp"
},
onSignUp: function(e){
// e.preventDefault();
layout.modal.show( new SignUp_Modal() );
$(document).foundation();
},
onSignIn: function(e){
// Prevent the link from doing anything.
e.preventDefault();
// Load modal popup that requests user to sign in
layout.modal.show( new SignIn_Modal() );
$(document).foundation();
}
});
return ActionBarView;
});
Finally, here's my SignUp_Modal view and its template.
'use strict';
define([
'jquery',
'underscore',
'model/user',
'text!/js/template/modals/sign-up.ejs',
'marionette'
], function ( $, _, User, Template){
var Modal = Backbone.Marionette.ItemView.extend({
events: {
'click #join': 'onJoin',
'click .me': 'onJoin'
},
template: _.template(Template),
onJoin: function(e){
// Check whether the click events do anything
console.log('Heard it');
}
});
return Modal;
});
Template:
<div id="signUp" class="reveal-modal" data-reveal>
<form>
<div class="row">
<div class="small-8">
<div class="row">
<div class="small-3 columns">
<label for="email" class="right inline">Email</label>
</div>
<div class="small-9 columns">
<input type="text" id="email" placeholder="Email">
</div>
</div>
<div class="row">
<div class="small-3 columns">
<label for="phone" class="right inline">Phone</label>
</div>
<div class="small-9 columns">
<input type="text" id="phone" placeholder="Phone">
</div>
</div>
<div class="row">
<div class="small-3 columns">
<label for="pass" class="right inline">Password</label>
</div>
<div class="small-9 columns">
<input type="password" id="pass">
</div>
</div>
<div class="row">
<label>Username will be...</label>
<input type="radio" name="username" value="email" id="username_email" checked><label for="username_email">Email</label>
<input type="radio" name="username" value="phone" id="username_phone"><label for="username_phone">Phone</label>
</div>
<div class="row">
<div class="small-3 columns">
Join
</div>
</div>
</div>
</div>
</form>
<div class="me">blaaaa</div>
<a class="close-reveal-modal">×</a>
</div>
I'm betting any of these would be helpful:
Boilerplate example showing how to implement Zurb Foundation with a backbone project, specifically where you're jamming a backbone view into a foundation modal?
Any general reasons why views don't hear click events?
Have I improperly loaded the view into the region?
The error occurs specifically when I click either the element with class="me" or id="join". Both of these should call onJoin() but neither do.
The events are not being trigger because foundation creates a new DOM element to hold the modal, this element is outside of your ItemView's instance's el, and as you might know Backbone only delegate events to the element associated with the view.

Backbone.js Event Not firing

I can't get this thing to add when i click the add button. I'm completely new to this.
JS code
function RecipeApp() {
var _Ingredient=Backbone.Model.extend(COOKBOOK.Domain.Ingredient),
_Ingredients = Backbone.Collection.extend({
model: _Ingredient
}),
_IngredientView = Backbone.View.extend({
tagName: "li",
initialize: function () {
this.model.bind("change", this.render, this);
},
render: function () {
var templateid = this.model.get('ViewID');
$(this.el).html(Mustache.to_html($("#"+templateid).html(),this));
}
}),
_AddView = Backbone.View.extend({
id:"divAddIngredient",
events: {
"click .btn": "create"
},
render: function () {
var tmpAddAnIngredient = $("#tmpMasterView").html(),
$submain = $("#submain");
$submain.html(Mustache.to_html(tmpAddAnIngredient, COOKBOOK.Domain));
},
initialize: function (ingredients) {
console.log("init enter");
this.render();
this._Ingredients = ingredients;
this._Ingredients.bind('add', this.add, this);
console.log("init leave");
},
//added functions
create: function () {
console.log("create");
var typename = this.$(".typeName").val(),
ingredient = _.detect(COOKBOOK.Domain.Ingredients, function (i) { i.TypeName === typename });
if (!!ingredient) {
this._Ingredients.create(ingredient);
}
},
add: function (ingredient) {
console.log('add');
var view = new _IngredientView(ingredient);
this.$("#divIngredients").append(view.render().el);
}
});
this.Ingredients = new _Ingredients();
this.AddView = new _AddView(this.Ingredients);
}
$(function () {
window.app = new RecipeApp();
//
});
And here is the mustache template
<script id="tmpTempDirectoryIngredient" type="text/html">
<div class="block-message">
<form>
<fieldset>
<legend>Create a Temporary Directory</legend>
<div class="clearfix">
<input type="text" name="DirectoryName" class="DirectoryName" />
</div>
</fieldset>
</form>
</div>
</script>
<script id="tmpMasterView" type="text/html">
<div class="block-message info" id="divAddIngredient">
<form>
<fieldset>
<legend>Add an Ingredient</legend>
<div class="clearfix">
<select class="typeName">
{{#Ingredients}}
<option value="{{TypeName}}">{{Name}}</option>
{{/Ingredients}}
</select>
</div>
<div class="clearfix">
<input type="button" class="btn primary" value="Add Ingredient" />
</div>
</fieldset>
</form>
</div>
<hr />
<div id="divIngredients">
</div>
</script>
it started working as soon as i explicitly set the el property of the _AddView to a tag that existed when the _AddView was created.
$(function(){
new Apps({el:$("body"),'records':[1,2,3,4,5]});
});
Here need to give el.
because of only after DOM is generating.....
The way you are passing Ingredients to the _AddView initialize, they will be accessible by this.options (see http://documentcloud.github.com/backbone/#View-constructor).
I think a better way is pass your ingredients collection into you _AddView like this:
this.AddView = new _AddView({collection: this.Ingredients});
Then within your definition of your view, always refer to this.collection instead of this._Ingredients. That is I think a more standard way to do it.

Resources