What is wrong with this backbone router? - backbone.js

Yes I have included undescore library and I now bind my loadChisiamo but I still got this issue.This is main.js
app_start();
var Router = Backbone.Router.extend({
routes: {
"home" : "loadHome",
"chisiamo" : "loadChisiamo",
"*actions": "defaultRoute"
},
initialize: function(){
_.bindAll(this,'loadHome','loadChisiamo');
},
loadHome: function(e){
e.preventDefault();
console.log('loadHome');
var home = new home_view();
},
loadChisiamo: function(e){
e.preventDefault();
console.log('loadChisiamo');
var chiSiamo = new chiSiamo_view();
},
defaultRoute: function(actions) {
}
});
var app_router;
function app_start(){
views();
var topBar = new topbar_view();
var menu = new menu_view();
var home = new home_view();
//app_router = new Router();
Backbone.history.start({ pushState: true });
topBar.render();
menu.render();
home.render();
}
var topbar_view,, menu_view, home_view, chiSiamo_view;
function views() {
topbar_view = Backbone.View.extend({
el: '#header',
template: Handlebars.templates['topbarHome.ht'],
initialize: function() {
_.bindAll(this, "render");
},
render : function() {
this.$el.html(this.template());
}
});
menu_view = Backbone.View.extend({...});
home_view = Backbone.View.extend({...});
chiSiamo_view = Backbone.View.extend({...});
}
Now, once I uncomment app_router = new Router() I get this error 'undefined is not a function '. So it's like I didnt define my router but I did above. So what can be the problem? This is my index.html
<body>
<div id="container">
<div id='header' class="header"></div>
<div id='main' class="main">
<div id="navigation"></div>
<div id="contain"></div>
</div>
</div>
<script src="scripts/vendor/jquery/jquery.js"></script>
<script src="scripts/vendor/jquery-ui/jquery-ui-1.10.4.min.js"></script>
<script src="scripts/vendor/underscore/underscore-min.js"></script>
<script src="scripts/vendor/backbone/backbone-min.js"></script>
<script src="scripts/vendor/handlebars/handlebars.js"></script>
<script src="scripts/vendor/modernizr/modernizr.custom.js"></script>
<script src="scripts/vendor/plugins/jquery.slides.min.js"></script>
<script src="scripts/templates.js"></script>
<script src="scripts/main.js"></script>
</body>

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();
}

Read Countless Backbone Tutorials But Still Missing Something

UPDATE
I finally learned Backbone back in late 2017. I'd delete this post but StackOverflow says it's not wise to delete answered questions. Please ignore this question.
I've read countless posts here on StackExchange as well as countless tutorials across the Internet but I seem to be just off from understanding basic Backbone use and implementation.
I'm attempting to build a custom Twitter timeline using pre-filtered JSON that is generated from a PHP file on my work's server.
I feel close but I just can't seem to get things to work. At times I'm able to view 20 tweets in my console but am only able to get 1 tweet to render via my template.
Here is my current Backbone setup:
(function($){
if(!this.hasOwnProperty("app")){ this.app = {}; }
app.global = this;
app.api = {};
app.api.Tweet = Backbone.Model.extend({
defaults: {}
});
app.api.Tweets = Backbone.Collection.extend({
model: usarugby.api.Tweet,
url: "https://custom.path.to/api/tweets/index.php",
parse: function(data){
return data;
}
});
app.api.TweetsView = Backbone.View.extend({
el: $('#tweet-wrap'),
initialize: function(){
_.bindAll(this, 'render');
this.collection = new app.api.Tweets();
this.collection.bind('reset', function(tweets) {
tweets.each(function(){
this.render();
});
});
return this;
},
render: function() {
this.collection.fetch({
success: function(tweets){
var template = _.template($('#tweet-cloud').html());
$(tweets).each(function(i){
$(this).html(template({
'pic': tweets.models[i].attributes.user.profile_image_url,
'text': tweets.models[i].attributes.text,
'meta': tweets.models[i].attributes.created_at
}));
});
$(this.el).append(tweets);
}
});
}
});
new app.api.TweetsView();
}(jQuery));
And here is my current HTML and template:
<div id="header-wrap"></div>
<div id="tweet-wrap"></div>
<script type="text/template" id="tweet-cloud">
<div class="tweet">
<div class="tweet-thumb"><img src="<%= pic %>" /></div>
<div class="tweet-text"><%= text %></div>
<div class="tweet-metadata"><%= meta %></div>
</div>
</script>
<script> if(!window.app) window.app = {}; </script>
I also have a CodePen available for testing. Any advice would be greatly appreciated.
Like the comments suggest, additional reading and code rewrite may be needed. The simplest example for a view rendering multiple views is here adrianmejia's backbone tutorial example.
The snippet below includes an additional view and a couple of added functions along with updating the render and initialize functions. Search for 'cfa' to review changes.
(function($){
if(!this.hasOwnProperty("app")){ this.app = {}; }
app.global = this;
app.api = {};
app.api.Tweet = Backbone.Model.extend({
idAttribute: 'id_str'
});
app.api.Tweets = Backbone.Collection.extend({
model: app.api.Tweet,
url: "https://cdn.usarugby.org/api/tweets/index.php",
parse: function(data){
return data;
}
});
app.api.TweetView = Backbone.View.extend({
tagName: 'div',
template: _.template($('#tweet-cloud').html()),
initialize: function(){
},
render: function(){
var j = {};
j.pic = this.model.get('user').profile_image_url;
j.text = this.model.get('text');
j.meta = this.model.get('meta');
this.$el.html(this.template(j));
return this;
},
});
app.api.TweetsView = Backbone.View.extend({
el: $('#tweet-wrap'),
initialize: function(){
this.collection = new app.api.Tweets();
this.collection.on('reset', this.onReset, this);
this.collection.on('add', this.renderATweet, this);
this.collection.fetch();
},
onReset: function(){
this.$el.html('');
this.collection.each(this.renderATweet, this);
},
renderATweet: function (tweet) {
var tweetView = new app.api.TweetView({ model: tweet });
this.$el.append(tweetView.render().el);
},
});
}(jQuery));
$(document).ready(function(){
new app.api.TweetsView();
});
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>
<script src="https://static.usarugby.org/lib.min.js"></script>
<div id="header-wrap"></div>
<div id="tweet-wrap"></div>
<script type="text/template" id="tweet-cloud">
<div class="tweet">
<div class="tweet-thumb"><img src="<%= pic %>" /></div>
<div class="tweet-text">
<%= text %>
</div>
<div class="tweet-metadata">
<%= meta %>
</div>
</div>
</script>
<div id="footer-wrap"></div>
<script>
if(!window.app) window.app = {};
</script>

handsontable in an angularjs directive - render an anchor that has an ng-click

So I'm using Handsontable to render a grid. (Yes, I am NOT using the ngHandsontable. I started out with that but ran into problems and so I went with just rendering a Handsontable from an angularjs directive.)
I want one column to hold an anchor tag.
I want the anchor tag to have the angularjs ng-click directive.
Everything renders correctly but the ng-click is not called.
Here is my example.
var APP = angular.module('APP', ['controllers']);
angular.module('controllers',[])
.controller('testController', function ($scope) {
$scope.doNgClick = function() {
alert('ng-click');
// console.log('ng-click');
};
$scope.simple = [
{
test: "<a href='javascript:void(0);' ng-click='doNgClick()'>Test</a>"
// test: "<a ng-click='doNgClick()'>Test</a>"
}
];
});
APP.directive('htable',function($compile) {
var directive = {};
directive.restrict = 'A';
directive.scope = {
data : '='
};
directive.link = function(scope,element,attrs) {
var container = $(element);
// var safeHtmlRenderer = function (instance, td, row, col, prop, value, cellProperties) {
// var escaped = Handsontable.helper.stringify(value);
// td.innerHTML = escaped;
// return td;
// };
var settings = {
data: scope.data,
readOnly: true,
colHeaders: ['Link'],
columns: [
{
data: "test",
renderer: "html",
// renderer: safeHtmlRenderer,
readyOnly: true
}
]
};
var hot = new Handsontable( container[0], settings );
hot.render();
// console.log(element.html());
// $compile(element.contents())(scope);
};//--end of link function
return directive;
});
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="//handsontable.com/dist/handsontable.full.css">
</head>
<body>
<div ng-app="APP">
<div ng-controller="testController">
<div htable data="simple"></div>
</div
</div>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.24/angular.min.js"></script>
<script src="//handsontable.com/dist/handsontable.full.js"></script>
</body>
</html>
After much reading and digging here is my own answer.
//-- With help from the following:
//--
//-- http://stackoverflow.com/questions/18364208/dynamic-binding-of-ng-click
//-- http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-3-isolate-scope-and-function-parameters
//--
var APP = angular.module('APP', ['controllers']);
angular.module('controllers',[])
.controller('testController', function ($scope) {
$scope.click = function(msg) {
console.log('ctrl_doNgClick: ng-click: msg: '+msg);
};
$scope.simple = [
{
test: "<a href='javascript:void(0);' ng-click='dir_ctrl_click(\"blah1,blah1\")'>Test 1</a>"
},
{
test: "<a href='javascript:void(0);' ng-click='doClick(\"blah2,blah2\")'>Test 2</a>"
},
{
test: "<a href='javascript:void(0);' ng-click='doClick(\"blah3,blah3\")'>Test 3</a>"
}
];
});
APP.directive('htable',function($compile) {
var directive = {};
directive.restrict = 'A';
directive.scope = {
data : '=',
click : '&'
};
directive.controller = function($scope) {
$scope.dir_ctrl_click = function( msg ) {
console.log('controller: dir_ctrl_click: click via the directive controller method');
$scope.click()(msg);
};
};
directive.link = function(scope,element,attrs) {
var container = $(element);
scope.doClick = function(msg) {
console.log('link: doClick: click via the directive link method');
scope.click()(msg);
};
var linkHtmlRenderer = function (instance, td, row, col, prop, value, cellProperties) {
//-- here is the magic that works
//-- the method, in ng-click, must either be defined here in the link method or in the controller method (the example data contains both)
var el = angular.element(td);
el.html($compile(value)(scope));
return el;
};
var settings = {
data: scope.data,
readOnly: true,
colHeaders: ['Link'],
columns: [
{
data : "test",
renderer : linkHtmlRenderer,
readyOnly : true
}
]
};
var hot = new Handsontable( container[0], settings );
// hot.render();
};//--end of link function
return directive;
});
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="http://handsontable.com/dist/handsontable.full.css">
</head>
<body>
<div ng-app="APP">
<div ng-controller="testController">
<div htable data="simple" click="click"></div>
</div
</div>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.24/angular.min.js"></script>
<script src="http://handsontable.com/dist/handsontable.full.js"></script>
</body>
</html>

Backbone script doesn't work

I'm new to Backbone Framework and this is my first app. I couldn't see any rendering of my app's view in my browser. I've checked the error console and didn't find any errors. Could you guys have a look and help me? I appreciate your time on my behalf and many thanks in advance
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
<script src="http://documentcloud.github.com/backbone/backbone-min.js"></script>
<script src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
<script id="contactTemplate" type="text/template">
<h1> <%= name %> </h1>
<dl>
<dt> <%= address %> </dt>
<dt> <%= tel %> </dt>
<dt> <%= email %> </dt>
<dt> <%= type %> </dt>
</dl>
</script>
<script>
// Your code goes here
(function ($) {
/* Dummy JSON DataSet */
var contacts = [
{name:"Test1",address:"Test Address",tel:"0123",email:"test#test.com",type:"family"},
{name:"Test2",address:"Test Address",tel:"01234",email:"test#test.com",type:"friends"},
{name:"Test3",address:"Test Address",tel:"012345",email:"test#test.com",type:"office"}
];
/* Defining Model */
var Contact = Backbone.Model.extend({
defaults:{
name:'',
address:'',
tel:'',
email:'',
type:''
}
});
/* Defining Collection (Set of Models) */
var Directory = Backbone.Collection.extend({
model:Contact
});
/* View for rendering indivijual Model*/
var ContactView = Backbone.View.extend({
tagName:'div',
className:'contact-container',
template:$('#contactTemplate').html(),
render:function(){
var tmpl = _.template(this.template);
this.$el.html(tmpl(this.model.toJSON()));
return this;
}
});
/* View for rendering collection of Models */
var DirectoryView = Backbone.View.extend({
el:$("#contacts"),
intialize:function(){
this.collection = new Directory(contacts);
this.render();
},
render:function(){
var that = this;
_.each(this.collection.models, function(item){
this.renderContact(item);
},this);
},
renderContact:function(item){
var contactView = new ContactView({
model:item
});
this.$el.append(contactView.render().el);
}
});
/* Initializing the view */
var directory = new DirectoryView();
} (jQuery));
</script>
</head>
<body>
<div id="contacts">
</div>
</body>
</html>
Beware,
(function ($) {...})(jQuery)
won't guarantee that your code will be executed when the DOM is ready. At the time of rendering DirectoryView, <div id="contacts"> isn't yet available so $el is also undefined.
Putting your script after </body> or into document.ready will solve your problem.
You also have a typo here:
el:$("#contacts"),
intialize: function(){ // <- initialize: function()
this.collection = new Directory(contacts);
this.render();
}
#akoskm's answer is correct, and i changed your code a few look like this:
ContactView = Backbone.View.extend({
tagName: 'div',
className: 'contact-container',
template: $('#contactTemplate').html(),
render: function(){
var tmpl = _.template(this.template,this.model.toJSON());
this.$el.html(tmpl);
return this;
}
});
DirectoryView = Backbone.View.extend({
el: "#contacts",
initialize: function(options){
contacts = options.contacts
this.collection = (new Directory(contacts)).models;
this.render();
},
render: function(){
var that = this;
_.each(this.collection, function(item){
this.renderContact(item);
},this);
},
renderContact: function(item){
var contactView = new ContactView({
model: item
});
this.$el.append(contactView.render().el);
}
});

Clueless on preloading collection from server using Backbone.js and Tastypie

I'm trying to display a list of projects using backbone.js.
Basically, backbone should be able to .fetch() the projects into the Projects collection.
This works, as I can tell from the async request which is filled with projects.
But, how do I approach rendering them on page load? There's not much documentation about using the reset() method for 'bootstrapped models'. Any help is appreciated! Thanks.
app.js:
var oldSync = Backbone.sync;
Backbone.sync = function(method, model, success, error){
var newSuccess = function(resp, status, xhr){
if(xhr.statusText === "CREATED"){
var location = xhr.getResponseHeader('Location');
return $.ajax({
url: location,
success: success
});
}
return success(resp);
};
return oldSync(method, model, newSuccess, error);
};
(function($) {
window.Project = Backbone.Model.extend({});
window.Projects = Backbone.Collection.extend({
model: Project,
url: PROJECT_ENDPOINT,
parse: function(data) {
return data.objects;
}
});
window.ProjectView = Backbone.View.extend({
tagName: 'li' ,
className: 'project',
initialize: function() {
_.bindAll(this, 'render');
this.model.bind('change', this.render);
this.projects = new Projects();
this.projects.fetch(function(data) {
console.log("haha");
});
this.template = _.template($('#project-template').html());
},
render: function() {
var renderedContent = this.template(this.model.toJSON());
$(this.el).html(renderedContent);
return this;
}
});
})(jQuery);
Template:
.........
<script>
PROJECT_ENDPOINT = "{% url api_dispatch_list resource_name="project" %}";
</script>
<script type="text/template" charset="utf-8" id="project-template">
<span class="project-title"><%= title %></span>
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
You can add bootstrapped models to the template:
<script>
PROJECT_ENDPOINT = "{% url api_dispatch_list resource_name="project" %}";
INITIAL_DATA = <%= collection.to_json %>
</script>
And then in your view constructor replace this.projects.fetch(...) with this.projects.reset(INITIAL_DATA)
I like to set up my apps to have some sort of "start" function that i call with the json data for the preloaded items.
function MyApp(){
this.start = function(initialModels){
var myModels = new MyCollection(initialModels);
var modelsView = new MyModelsView({collection: myModels});
modelsView.render();
// ... other startup code here
}
}
and the html page has a script blog that looks something like this:
<script language="javascript">
var myApp = new MyApp();
myApp.start(<%= mymodel.to_json %>)
</script>
hope that helps

Resources