what is not making that my code render the collection? - backbone.js

I'm having a hard time trying to figre out what's wong with my code?
the thing that i'm tryng to make is get a collection o models and display them
here are my models
var MessageModel = Backbone.Model.extend({
defaults : {
id: "",
from:"",
titleMessage:"",
bodyMessage:"",
bodyMessageTrim:""
}
});
My Collection
var MessageListCollection = Backbone.Collection.extend({
url: '../js/dataDummy/populateJsonMessages.json',
model: MessageModel
});
My Views
var MessageListItemView = Backbone.View.extend({//view for a row in the message list
template: _.template($('#tpl-message-item-list').html()),
render: function(eventName){
this.$el.html(this.template(this.model.toJSON() ));
return this;
},
});
var MessageListView = Backbone.View.extend({//view por all messages listed
className:'messages',
render: function(){
this.collection.each(function(model){
var msgListAll = new MessageListItemView({model:model});
console.log(msgListAll.el);
this.$el.append(msgListAll.render().el);
}, this);
return this;
});
Finally my Routes
//global model variables so i can interact with the different views
var myMessageModelAction = new MessageModel();//whole message information
var myMessageListAction = new MessageListCollection();//all the messages to be listed
var AppRouter = Backbone.Router.extend({
routes:{
"messages": "messagesList"
},
messagesList: function(){
var myMessageList = new MessageListCollection();
myMessageList.fetch();
console.log(myMessageList);
var myMessageListView = new MessageListView({collection:myMessageList});
console.log(myMessageListView);
myMessageListView.render();
console.log("dame esto");
console.log(myMessageListView.el);
$('#rendered').html(myMessageListView.render().el);
}
});
var appRouter = new AppRouter();
Backbone.history.start();
The File that is been called inside the collection code is just a json plain text but if it helps here it is
[
{"id": "1", "from":"user1", "titleMessage":"Welcome to the Team", "bodyMessage":"Congratulations you passed the selection tests", "bodyMessageTrim": "Congratulations you passed..."},
{"id": "2", "from":"user2", "titleMessage":"First Task", "bodyMessage":"Hello you have to make some changes in the UI", "bodyMessageTrim": "Hello you have to..."},
{"id": "3", "from":"user2", "titleMessage":"Re:Welcome to the Team", "bodyMessage":"No problem if it's anything you might need just let me know", "bodyMessageTrim": "No problem if it's..."},
{"id": "4", "from":"user2", "titleMessage":"Re:First Task", "bodyMessage":"Ok i am going to talk to the design team to give you all the assets", "bodyMessageTrim": "Ok i am going to talk..."},
{"id": "5", "from":"user2", "titleMessage":"Re:Re:First Tak", "bodyMessage":"Ok that is it great work", "bodyMessageTrim": "Ok that is it..."},
{"id": "6", "from":"user1", "titleMessage":"Meeting Tomorrow", "bodyMessage":"Hi this is just a notice that tomorrow we will have a meet with all new members", "bodyMessageTrim": "Hi this is just a..."}
]
The index looks like this
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>test</title>
<link rel="stylesheet" href="../assets/bootstrap.min.css">
<link rel="stylesheet" href="../assets/index.css">
</head>
<body>
<!-- Templates -->
<script type="text/template" id="tpl-message-item-list" >
<div class="messageItem">
<div><%= from %></div>
<div><%= titleMessage %></div>
<div><%= bodyMessageTrim %></div>
</div>
</script>
<div class="jumbotron">
<div class="container" id="rendered">
<p>Looks like you are in the wrong place run now to a safe place</p>
</div>
</div>
<!-- Libraries -->
<script src="../js/lib/jquery-2.1.4.min.js"></script>
<script src="../js/lib/underscore-min.js"></script>
<script src="../js/lib/backbone-min.js"></script>
<!-- Relevant Scripts -->
<!--script src="../js/app.js"></script-->
<script src="../js/views/appIndex.js"></script>
<script src="../js/models/appIndex.js"></script>
<script src="../js/collections/appIndex.js"></script>
<script src="../js/routers/routes.js"></script>
</body>
</html>
Any help is good due i'm lost and i have like 3 days playing with backbone
and all that i'm having in response is a blank screen where it should be loaded my data.
Also the collections is reached and all the data is in place just the problem is the render of it

The reason is that Backbone View, by default, expects an el parameter when you initialize it. meaning the render will write the stuff inside that el.
if you already have some div in html page, then you can initialize backbone view like this:
var messageItemView=new MessageItemView({model:model,el:'#somediv'});
Then when render, it will write to that div.
However, it looks like you are creating a view without an element in the page, which makes sence if you do render().el, this will return the html text, and you append to main html.
while this makes sense, the backbone constructor does not know this. if you see this fiddle, you can see, after you initialize the MessageListItemView, the $el is null. It needs to be constructed before you do
this.$el.html(xxxx);
A hacky fix is to add a
render: function(eventName){
this.$el=$(this.el);// this create the $el element;
this.$el.html(this.template(this.model.toJSON() ));
return this;
},
A more standard is to do it by overwrite the initialize function and do setElement();
Same thing needs to be done for MessageListView too

You are calling colleciton.fetch but not waiting for it to get data before you create collectionView.
var def = myMessageList.fetch(); return a deferred. def.done(function(){ /* rest of the code here */}) should fix the problem.

Related

Backbone Marionettejs view does not change when model changed

I follow the example from this book https://leanpub.com/marionette-gentle-introduction. My problem is that the view does not rerender when i change the model by clicking on the button. As the answer from this question , i don't need to do anything because Backbone/MarionetteJS smart enough to change the view.
Here is the code
<!DOCTYPE html>
<html lang="en">
<head>
<title>Demo marionettejs</title>
<script src="./vendors/jquery/dist/jquery.js" type="text/javascript"></script>
<script src="./vendors/underscore/underscore.js" type="text/javascript"></script>
<script src="./vendors/backbone/backbone.js" type="text/javascript"></script>
<script src="./vendors/backbone.marionette/lib/backbone.marionette.js" type="text/javascript"></script>
</head>
<body>
<div id="main-region" class="container">
<p>Here is static content in the web page. You'll notice that it gets
replaced by our app as soon as we start it.</p>
</div>
<script type="text/template" id="contact-template">
<p><%- firstName %> <%- lastName %> : <%- time %> </p> <br />
<button>Change model</button>
</script>
<script type="text/javascript">
var ContactManager = new Marionette.Application();
ContactManager.Contact = Backbone.Model.extend({});
ContactManager.ContactView = Marionette.ItemView.extend({
template: "#contact-template",
initialize: function () {
this.currentMeterId = null;
},
events: {
"click button": "changeModel"
},
modelEvents: {
"change": "modelChanged"
},
changeModel: function() {
this.model.set("time", (new Date()).toString());
},
modelChanged: function() {
console.log("Model changed : " + this.model.get('time'));
},
//EDIT
onRender: function() {
//Create jsTree here.
}
});
ContactManager.on("before:start", function () {
var RegionContainer = Marionette.LayoutView.extend({
el: "#app-container",
regions: {
main: "#main-region"
}
});
ContactManager.regions = new RegionContainer();
});
ContactManager.on("start", function () {
var alice = new ContactManager.Contact({
firstName: "Alice",
lastName: "Arten",
time: "#"
});
var aliceView = new ContactManager.ContactView({
model: alice
});
ContactManager.regions.main.show(aliceView);
});
ContactManager.start();
</script>
</body>
</html>
#Edit
This code is just sample. In my real app, I have an ajax task that changes DOMs in the view. This ajax task creates a tree (jsTree) in onRender event. If i use modelEvents: {"change": "render"}, my jsTree will be reload and lost its state. So I want only update the model values in the view, others DOMs is retain.
The accepted answer to the question you pointed points to another question which has the following:
modelEvents: {
'change': "modelChanged"
},
modelChanged: function() {
console.log(this.model);
this.render();
}
And the most upvoted answer suggests the same:
modelEvents: {
'change': 'fieldsChanged'
},
fieldsChanged: function() {
this.render();
}
a comment to the most upvoted answer suggests
just {'change': 'render'} does the trick too
Which means you can do
modelEvents: {
'change': 'render'
}
So somehow you need to tell marionette invoke render on model changes.
I don't think backbone and marionette couple is smart enough to know whether you need to render view on model changes or you don't want to unless you tell them ;)

Angular: Setting default value in a dropdown

I have set up a plunker with basically below code.
I am unable to see the default value [Bank Account Number] getting selected in the drop down. I see that model is getting updated. But for some reasons, my default value do not get chosen. Can someone help me?
//index.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#1.0.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js" data-semver="1.0.7"></script>
<script src="script.js"></script>
<script src="services.js"></script>
</head>
<body ng-controller="homeCtrl">
<h1>Other Criteria: {{ otherCriteria.optionText }}</h1>
<div>
<select data-ng-model="otherCriteria"
data-ng-options="o as o.optionText for o in criteria">
</select>
</div>
</body>
</html>
//services.js
app.factory("homeService", [
"$q",
function($q) {
function _getDropdownValues() {
var deferred = $q.defer();
var dropdownValues = [{"optionValue":"Bank_Account_Number","optionText":"Bank Account Number","selected":false},{"optionValue":"Bank_Security_Number","optionText":"Bank Security Number","selected":false},{"optionValue":"Cusip","optionText":"Cusip","selected":false},{"optionValue":"Transaction_Description","optionText":"Description","selected":false}];
deferred.resolve(dropdownValues);
return deferred.promise;
}
return {
getDropdownValues: _getDropdownValues
}
}
]);
//script.js
var app = angular.module("app", []);
app.controller("homeCtrl", function($scope, homeService) {
$scope.otherCriteria = {
optionValue: "Bank_Account_Number",
optionText: "Bank Account Number",
selected: false
};
homeService.getDropdownValues()
.then(function(dropdownValues) {
$scope.criteria = dropdownValues;
})
});
Try this plunker.
It's always a better idea to reference a default value via the index of the collection (however you want to reference it)
$scope.criteria = dropdownValues;
$scope.otherCriteria = $scope.criteria[0];
You can find more information here
Basically: Angular.JS uses native JavaScript comparison for comparing the objects. In JavaScript, unrelated to Angular.JS or anything, comparing objects (object literals) is “by reference”, so it doesn’t factor the similarity of the objects. Only checks if the two references compared point to the same object in memory or not

Why doesn't this.$el.append() work?

I'm trying to follow along http://addyosmani.github.io/backbone-fundamentals. I'm not getting how $el is supposed to work in a view.
Here's my HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Dashboard</title>
</head>
<body>
<h1>Dashboard</h1>
<ol class="foo" id="recent-station">
</ol>
<!-- Templates -->
<script type="text/template" id="station-template">
<li><%= station %></li>
</script>
<!-- Javascript -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js"></script>
<script src="static/js/script.js"></script>
</body>
</html>
And script.js is:
var RecentStation = Backbone.Model.extend( {
defaults: {
station: "",
},
initialize: function() {
console.log('initialized: ' + JSON.stringify(this));
this.on('change', function() {
console.log('changed: ' + JSON.stringify(this));
})
}
});
var RecentStationView = Backbone.View.extend( {
tagName: 'ol',
id: 'recent-station',
initialize: function() {
this.model.bind('change', _.bind(this.render, this));
},
render: function() {
console.log('render');
this.$el.append('<li>foo</li>');
$('ol#recent-station').append('<li>bar</li>');
return this;
},
});
var recent = new RecentStation();
var recentView = new RecentStationView({model: recent});
recent.set('station', 'My Station');
The interesting stuff is happening in the render function. I can see "render" logged to the console, and the "bar" text gets appended to the node, but not the "foo" text. I thought this.$el and $('ol#recent-station') were the same thing, but obviously not. What am I missing?
If you don't specify a dom element using el attribute, one will be created using tagName,id,className, and attributes from the view.
In your case you don't specify an el attribute in your view so you create an element that looks like:
<ol id='recent-station'></ol>
You then append <li>foo</li> into it, but your view element is still not in the DOM.
$('ol#recent-station') returns the dom element included in your html which is different than your view element, but has the same attributes.
So, in your example you would need to specify an existing element by supplying an el attribute.
var RecentStationView = Backbone.View.extend( {
// remove tagName and id
el:'#recent-station',
/* rest of your code below */
A fiddle with the changes, http://jsfiddle.net/DsRJH/.

Underscore templating error with backbonejs [duplicate]

This question already has an answer here:
Underscore.js Template Issue - Cannot call method 'replace' of null
(1 answer)
Closed 9 years ago.
When this html code with Backbonejs is opened Chrome Java script console is throwing the following error - uncaught TypeError: Cannot call method 'replace' of undefined ,
but when i remove this one line of code containing usage of underscore templating this.template = _.template($('#listing').html())
from the List_view's initialize method its working fine . Why is the usage of underscore templating throwing the error ??
Here is the code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Example Backbone Whisky APP</title>
</head>
<body>
<script src="LIB/json2.js"></script>
<script src="http://underscorejs.org/underscore.js"></script>
<script src="http://code.jquery.com/jquery.js"></script>
<script src="http://backbonejs.org/backbone.js"></script>
<script type = "text/template" id="listing">
<li>%= value %</li>
</script>
<script>
Whisky = Backbone.Model.extend();
firstWhisky = new Whisky({
name : 'Blenders Pride'
});
Whiskies = Backbone.Collection.extend({
Model:Whisky ,
url:"#"
});
first_view = Backbone.View.extend({
el : 'body',
initialize : function() {
this.$el.empty();
this.render();
} ,
render : function() {
this.$el.append("<h1>The Whisky APP</h1>");
this.list_view = new List_view();
this.$el.append(this.list_view.render().el);
return this ;
}
});
List_view = Backbone.View.extend({
tagName : 'ul' ,
initialize : function() {
this.template = _.template($('#listing').html());
} ,
render : function() {
this.$el.empty();
this.$el.append("<li>Royal stag</li>");
this.$el.append("<li>Signature </li> ");
return this ;
}
});
index_view = new first_view();
</script>
</body>
</html>
The problem is that your call to $("#listing").html() is returning undefined as the element isn't available yet. You'd need to wait for the DOM to have loaded to access the element by ID. You could confirm this by doing a simple alert inline. You need to delay the retrieval until the DOM is ready.
In this case, it's because you've got the script tags in the body, making them unavailable at the time that you've requested them. Move the script tags (and templates), and it will work:
http://jsbin.com/obahux/2/
One issue you'll have is that your syntax is wrong, you should be using <% and %> for executing code or emitting values:
<script type = "text/template" id="listing">
<li><%= value %></li>
</script>
That's because, in your first_view initialize function you're clearing el with this.$el.empty() that makes body empty and there is nothing in there, all scripts and templates in there will be ommited.
You can find a better solution for clearing it. or just wrap that in another div tag

template not loading in backbone.js ( TypeError: text is undefined )

I'm learning backbone.js and I'm pretty much in the beginning. I want to add a template through underscore template method but it's not working for me. I searched for this error but couldn't fix it myself. How can I move forward if it's not showing the template. Need some help guys.
Here is the code (this code is from addyosmani's book backbone-fundamentals):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>testing</title>
</head>
<body>
<script src="scripts/jquery.js"></script>
<script src="scripts/underscore.js"></script>
<script src="scripts/backbone.js"></script>
<script>
var TodoView = Backbone.View.extend({
tagName: 'li',
// Cache the template function for a single item.
todoTpl: _.template( $('#item-template').html() ),
events: {
'dblclick label': 'edit',
'keypress .edit': 'updateOnEnter',
'blur .edit': 'close'
},
// Re-render the titles of the todo item.
render: function() {
this.$el.html( this.todoTpl( this.model.toJSON() ) );
this.input = this.$('.edit');
return this;
},
edit: function() {
// executed when todo label is double clicked
},
close: function() {
// executed when todo loses focus
},
updateOnEnter: function( e ) {
// executed on each keypress when in todo edit mode,
// but we'll wait for enter to get in action
}
});
var todoView = new TodoView();
// logs reference to a DOM element that cooresponds to the view instance
console.log(todoView.el);
If the template is defined after your script it will not work.
wrap your entry point into
$(function(){
var todoView = new TodoView();
});
so you dont get this kind of error.
I got the same error. Make sure that template with defined id exists on the page.
In my case I used wrong id for template, and this was a reason of error "TypeError: n is undefined".

Resources