Backbone JS Button Click Event Not Working - backbone.js

I am new to backbone js and I'm struggling to display an alert when clicking on the button displayed in the html page. I am certain I'm doing something foolish, but when i click the button the event doesn't seem to be fired. I have tried to use both submit and click in the events section, but I can't seem to get it to work. I would be very grateful if someone could help me out, thanks!
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Event Test</title>
<script src="../../external/jquery.js"></script>
<script src="../../external/underscore.js"></script>
<script src="../../external/backbone.js"></script>
</head>
<body>
<div id="standard-input-form"></div>
<script>
var MovePalletView = Backbone.View.extend({
initialize: function() {
},
events: {
'submit' : 'move'
},
render: function(event) {
this.$el.append('<button type="button" value="Submit"></button>');
$("#standard-input-form").html(this.$el.html());
return this;
},
move: function() {
alert("You clicked it");
}
});
$(function(){
var movePalletView = new MovePalletView()
movePalletView.render();
})
</script>
</body>
</html>

In the event there are any other newbie's out there reviewing this question, this was the working code.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Dairy Tracker</title>
<script src="../../external/jquery.js"></script>
<script src="../../external/underscore.js"></script>
<script src="../../external/backbone.js"></script>
<script src="src/MovePallet.js"></script>
</head>
<body>
<form id="standard-input-form"></form>
<script>
var MovePalletView = Backbone.View.extend({
el: '#standard-input-form',
initialize: function () {},
events: {
'submit': 'move'
},
render: function (event) {
this.$el.append('<button type="submit" value="Submit"></button>');
return this;
},
move: function (e) {
e.preventDefault(); //this line keeps the page from refreshing after closing the following alert.
alert("You clicked it");
}
});
$(function(){
var movePalletView = new MovePalletView()
movePalletView.render();
});
</script>
</body>
</html>

Render function appends just HTML string which doesn't have any events bound. Instead append HTML element (just remove .html() part):
events: {
'click' : 'move'
},
render: function(event) {
this.$el.append('<button type="button" value="Submit"></button>');
$("#standard-input-form").html(this.$el);
return this;
},
However, this is not really a good solution, because you would have to use click event instead of proper submit. Much better approach is to initialize your MovePalletView with #standard-input-form as this.$el:
var MovePalletView = Backbone.View.extend({
el: '#standard-input-form',
initialize: function () {},
events: {
'submit': 'move'
},
render: function (event) {
this.$el.append('<button type="submit" value="Submit"></button>');
return this;
},
move: function (e) {
e.preventDefault();
alert("You clicked it");
}
});
A few notes. First of all, make sure you have button type="submit" it will trigger onsubmit event. Then you need to create View object on the form element as the root (el: '#standard-input-form'). Then you will be able to bind to its onsubmit event.

Related

pass data from model to view in backbone.js

i want to pass data from model to view and i want to get this data length in view and make for loop on it but the property of length get undefined and i can't pass data to view there is an error in template html
<html>
<head>
<link href='//fonts.googleapis.com/css?family=Lato:100' rel='stylesheet' type='text/css'>
</head>
<body>
<div id="container">Loading...</div>
<div class="list">
<button id="list">LIST</button>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js" type="text/javascript"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js" type="text/javascript"></script>
<script type="text/template" id="view_list">
</script>
<script type="text/javascript">
var app = {};
app.postModel = Backbone.Model.extend({
url: 'https://jsonplaceholder.typicode.com/comments',
defaults: {
postId: 0,
id: 0,
email:"",
body:""
}
});
app.viewlist = Backbone.View.extend({
el:$(".list"),
initialize:function(){
this.model = new app.postModel();
},
template: _.template($('#view_list').html()),
events:{
"click #list" : "list"
},
list:function(e)
{
this.model.fetch({
success: function (post) {
console.log(post.toJSON().length);
this.$el.html(this.template(post.toJSON()));
}
});
}
});
app.viewpost = new app.viewlist();
</script>
</body>
and the error in html say
Uncaught TypeError: Cannot read property 'html' of undefined
at success (backbone:49)
at Object.a.success (backbone-min.js:12)
at o (jquery.min.js:2)
at Object.fireWith [as resolveWith] (jquery.min.js:2)
at w (jquery.min.js:4)
at XMLHttpRequest.d (jquery.min.js:4)
Based on the error, looks like you don't have the view within the scope of the success function. This should work:
var view = this;
this.model.fetch({
success: function (post) {
console.log(post.toJSON().length);
view.$el.html(view.template(post.toJSON()));
}
});
Although you should probably think about adding a render function to the view, and possibly having the view listen to model changes in order to trigger it.
initialize: function() {
this.model = new app.postModel();
this.model.on('sync', this.render, this); // Backbone 0.9.2 way
// Backbone 0.9.9+ way
// this.listenTo(this.model, 'sync', this.render);
}
render: function() {
this.$el.html(this.template(this.model.toJSON()));
},
...
list: function(e) {
this.model.fetch();
}

AngularJs dynamic Event Handling for the whole page level

I want to create following event(s) using angularjs.
mousemove
keydown
DOMMouseScroll
mousewheel
mousedown
touchstart
touchmove
scroll
Now what I am trying is as following...,
<!DOCTYPE html>
<html ng-app="appname">
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.min.js"></script>
</head>
<body>
</body>
<script>
var app = angular.module('appname', []);
app.directive('myDirective', function() {
alert("Hello");
return {
link: function(scope, element) {
scope.appname.$on('mousemove', function() {
alert("mousemove");
});
scope.appname.$on('keydown', function() {
alert("keydown");
});
scope.appname.$on('DOMMouseScroll', function() {
alert("DOMMouseScroll");
});
});
}
});
</script>
</html>
But I cannot get it working. Let me get your suggestions.
Since each $scope inherits from the $rootScope and you are not using an isolated scope here, you can use $rootScope.$on to subscribe to the events for your whole application.
A great introduction can be found here.
After,I learned from this answer, I got it working in following code.
<!DOCTYPE html>
<html ng-app="testApp">
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.min.js"></script>
</head>
<body>
</body>
<script>
var app = angular.module('testApp', []);
app.run(['$document', function($document) {
var bodyElement = angular.element($document);
bodyElement.bind('click', function (e) {
console.log('click');
});
bodyElement.bind('mousemove', function (e) {
console.log('mousemove');
});
bodyElement.bind('keydown', function (e) {
console.log('keydown');
});
bodyElement.bind('DOMMouseScroll', function (e) {
console.log('DOMMouseScroll');
});
bodyElement.bind('mousewheel', function (e) {
console.log('mousewheel');
});
bodyElement.bind('mousedown', function (e) {
console.log('mousedown');
});
bodyElement.bind('touchstart', function (e) {
console.log('touchstart');
});
bodyElement.bind('touchmove', function (e) {
console.log('touchmove');
});
bodyElement.bind('scroll', function (e) {
console.log('scroll');
});
}]);
</script>
</html>
Demo Link

Marionette 'could not find template' - load external templates

I'm new with backbone, and also marionette. Idk why I'm get this error. My structure seems correct, but the error persists.
This is my index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="css/main.css">
</head>
<body>
<!-- Main App -->
<div id="main-area"></div>
<!-- Templates -->
<script id="main-tpl" src="templates/main.tpl" type="text/x-template"></script>
<!-- 3rd party Dependencies -->
<script src="vendor/jquery/dist/jquery.js"></script>
<script src="vendor/underscore/underscore.js"></script>
<script src="vendor/backbone/backbone.js"></script>
<script src="vendor/backbone.wreqr/lib/backbone.wreqr.js"></script>
<script src="vendor/backbone.babysitter/lib/backbone.babysitter.js"></script>
<script src="vendor/marionette/lib/backbone.marionette.js"></script>
<script type="text/javascript">
// External templates load
_.each(document.querySelectorAll('[type="text/x-template"]'), function (el) {
$.get(el.src, function (res) {
el.innerHTML = res;
});
});
var App = new Backbone.Marionette.Application();
_.extend(App, {
Controller: {},
View: {},
Model: {},
Page: {},
Scrapers: {},
Providers: {},
Localization: {}
});
App.addRegions({
Main: '#main-area'
});
App.addInitializer(function (options) {
var mainView = new App.View.Main();
try {
App.Main.show(mainView);
} catch(e) {
console.error('Error on Show Main: ', e, e.stack);
}
});
App.View.Main = Backbone.Marionette.Layout.extend({
template: '#main-tpl'
});
(function(App) {
'use strict';
App.start();
})(window.App);
</script>
</body>
and my template/main.tpl is only test html.
<div>sounds</div>
All 3rd party dependencies paths are correct.
The error that appears is this:
Error: Could not find template: '#main-tpl'
Can someone tell me where am I wrong?
Thanks.
EDIT:
I think the problem is because $.get is async and the template load after backbone try to render, how can I solve this?
You can update your HTML and replace
<script id="main-tpl" src="templates/main.tpl" type="text/x-template"></script>
with
<script id="main-tpl" type="text/html">
--- template code ---
</script>
Or use requireJs !text plugin to load template files into marionette views.
The problem is that the template loads after the app initialization.
Instead, try this:
$(function () {
var tplList = document.querySelectorAll('[type="text/x-template"]');
var tplCounter = 0;
_.each(tplList, function (el) {
$.ajax({
'url': el.src,
success: function (res) {
el.innerHTML = res;
++tplCounter;
if(tplCounter == tplList.length){
App.start();
}
}
});
});
});
define(['marionette','tpl!cell.tpl'],function(tpl){
var Mn = Backbone.Marionette;
var MyView = Mn.View.extend({
className: 'bg-success',
template: tpl,
regions: {
myRegion: '.my-region'
}
});
})
var model = new Backbone.Model({});
var myView = new MyView({model:model});

Backbone model not instantiated

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script type="text/javascript" src="backbone.js"></script>
<script type="text/javascript" src="jquery-min1.4.js"></script>
<script>
//MODEL CREATION
var person=Backbone.Model.extend(
{
initialize: function()
{
alert("hello backbone");
}
});
function perf()
{
var val=new person();
}
</script>
</head>
<body>
<button onclick="perf()">CLICK</button>
</body>
</html>
This is a simple code, alert is not invoked in the model when an instance of it is created in the perf() function which is called while clicking the button... Please help
Try to write your code in $(function() {}); block or $(document).ready(function () {}); block.
It should work.
You are missing a script reference to Underscore.js
<script type="text/javascript" src="underscore.js"></script>
Backbone requires it as a dependency.
Download it at http://underscorejs.org/ then put it above your script element for backbone.js and it will work fine.
Here's jsfiddle that included both suggestions by dcarson & Naresh J , http://jsfiddle.net/Rvn2L/1/
$(function () {
var person = Backbone.Model.extend({
initialize: function () {
alert("hello backbone");
}
});
function perf() {
console.log('1');
var val = new person();
}
window.perf = perf;
})

Make backbone wait to render view

I'm new to backbone and I have a collection of objects and a view that displays them as a list. It is set up so that every time an object is added to the collection the view is re-rendered. This is really inefficient because if I add 20 things to the collection all at once, it will be rendered 20 times when it only needs to be rendered one time after the last item has been added. How do I make backbone hold off on rendering until I'm done adding things to the collection?
Here is my code:
<html>
<head>
<meta charset="utf-8" />
<title>Looking At Underscore.js Templates</title>
</head>
<body>
<script type="text/template" class="template">
<ul id="petlist">
<% _.each(model.pets, function(pet) { %>
<li><%- pet.name %> (<%- pet.type %>)</li>
<% }); %>
</ul>
</script>
<div id="container"/>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script type="text/javascript" src="http://underscorejs.org/underscore.js"></script>
<script src="http://backbonejs.org/backbone-min.js"></script>
<script type="text/javascript">
var serviceData = [
{
name: "Peaches",
type: "dog"
},
{
name: "Wellington",
type: "cat"
},
{
name: "Beefy",
type: "dog"
}
];
$(document).ready(function() {
var Pet = Backbone.Model.extend({
name: null,
type: null
});
var Pets = Backbone.Collection.extend();
var AppView = Backbone.View.extend({
updateUi: function(model) {
_.templateSettings.variable = "model";
var template = _.template($("script.template").html());
var model = { pets: model.collection.toJSON() };
var html = template(model);
$("#container").html(html);
}
});
var pets = new Pets();
var av = new AppView();
pets.bind("add", av.updateUi);
pets.set(serviceData);
});
</script>
</body>
</html>
You could also create an extra method called, lets say, add.
So, if you add a new object, the application just adds a single object instead of rendering the hole collection again.
Somethin like this:
App.Model = Backbone.Model.extend();
App.Collection = Backbone.Collection.extend({
model: App.Model
});
App.CollectionView = Backbone.View.extend({
tagName: 'ul',
render: function(){
this.collection.each(function(model){
var objView = new App.ModelView({ model: model });
this.$el.append( objView.render().el );
});
return this;
},
showAddForm: function(){
// Here you show the form to add another object to the collection
},
save: function(){
// Take form's data into an object/array, then add it to the collection
var formData = {
type: $('select[name=type]').val(),
name $('input[name=name]').val()
};
// Once added to the collection, take the object/array and...
this.addElement(formData);
},
addElement: function(model){
var modView = new App.ModelView({ model: model });
this.$el.append( modView.render().el );
}
});
App.ModelView = Backbone.View.extend({
tagName: 'li',
template: _.template( "<li><%= name %> (<%= type %>)</li>" ),
render: function(){
this.$el.html( this.template( this.model.toJSON() ) );
return this;
}
});
Do you get the idea?
When you render the hole collection, the collectionView render method calls a modelView for each object/pet.
So, this way, when you get the info of a new pet/object you can just create an instance of ModelView, and append it to the actual rendered view.
Hope it helps.
You need to re-factor a couple of things on your code. For your specific case you need to use reset instead of set, to dispatch only one event when data is set. Also you could pass the collection to the view and the view could listen the reset event.
Additionally, to prevent the stress of the browser you could use document.createDocumentFragment that is a DOM holder that speed up the treatment of append. Check point number two for more reference:
http://ozkatz.github.io/avoiding-common-backbonejs-pitfalls.html
<html>
<head>
<meta charset="utf-8" />
<title>Looking At Underscore.js Templates</title>
</head>
<body>
<script type="text/template" class="template">
<ul id="petlist">
<% _.each(model.pets, function(pet) { %>
<li><%- pet.name %> (<%- pet.type %>)</li>
<% }); %>
</ul>
</script>
<div id="container"/>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script type="text/javascript" src="http://underscorejs.org/underscore.js"></script>
<script src="http://backbonejs.org/backbone-min.js"></script>
<script type="text/javascript">
var serviceData = [
{
name: "Peaches",
type: "dog"
},
{
name: "Wellington",
type: "cat"
},
{
name: "Beefy",
type: "dog"
}
];
$(document).ready(function() {
var Pet = Backbone.Model.extend({
name: null,
type: null
});
var Pets = Backbone.Collection.extend();
var AppView = Backbone.View.extend({
initialize : function(){
this.collection.bind("reset", av.updateUi);
},
updateUi: function() {
$items = document.createDocumentFragment();
this.collection.each(function(model){
var itemView = new ItemView({model : model});
$items.append(itemView.el);
itemView.render();
});
$("#container").html($items);
}
});
var pets = new Pets();
var av = new AppView({collection : pets});
pets.reset(serviceData);
});
</script>
</body>
</html>
You can also do:
pets.set(serviceData, { silent: true });
pets.trigger('add', pets);
And modify av.updateUi to work with whole collection and create the HTML at once, but 'reset' event would be probably more appropriate than 'add' in this case.

Resources