template code :
<script type="text/template" id="baseTemplate">
<% collection.each(function() { %>
<div>
<%= collection %>
</div>
<% }); %>
</script>
<div id="baseContainer"></div>
and other code is :
//model
var PageModel = Backbone.Model.extend({
defaults: {
"id":null,
"title":"",
"content":""
},
});
//collection
var PageCollection = Backbone.Collection.extend({
defaults: {
model: PageModel
},
model: PageModel,
url: 'api/get_page/?id=6'
});
//view
var PageView = Backbone.View.extend({
el: $('#baseContainer'),
initialize: function () {
this.collection = new PageCollection();
this.collection.bind("reset", this.render, this);
this.collection.bind("change", this.render, this);
this.collection.fetch();
},
render: function () {
var html = _.template($("#baseTemplate").html(), { collection: this.collection });
this.$el.html(html);
console.log(html);
return this;
}
});
var page = new PageView();
problem is that its return and object how can i get values from object? api link is http://furqankhanzada.com/backbonejs/api/get_page/?id=6 and here you can see object in browser console http://furqankhanzada.com/backbonejs/
i need to get title, content , attachments -> images -> Gallery Large -> url (attachments using each() ).
Not sure whether this is proper solution or not, but you can give it a try.
An alternative can be like,
var html = _.template($("#baseTemplate").html(), { models: this.collection.models });
Pass models instead of directly passing collection. And in the template you can do something like this,
<script type="text/template" id="baseTemplate">
<% _.each(models, function(mdl) { %>
<div>
<%= mdl.get('title') %>
<%= mdl.get('content') %>
<% _.each(mdl.get('page').attachments, function(attachment) { %>
<%= attachment.images["Gallery Large"].url %>
<% }) %>
</div>
<% }); %>
</script>
<div id="baseContainer"></div>
Please modify the markup as per your needs. But this solution is too specific to the problem :( :(
Related
I am wondering how to log the model used in a Backbone.Marionette CompositeView's template?
The <% console.log(model) %> I am using causes an error Uncaught ReferenceError: model is not defined
Is there a way to log the content of the model from the template?
Here is a fiddle to my code: http://jsfiddle.net/16L1hen4/
Here is my Template and JavaScript
Template:
<div id="main"></div>
<script type="text/template" id="tree-template">
<li><%- name %></li>
<% //This console.log fails and I don't know why %>
<% console.log('inside template model =',model) %>
</script>
JavaScript:
var App = new Backbone.Marionette.Application();
App.addRegions({
mainRegion: '#main'
});
var TreeModel = Backbone.Model.extend({
});
var TreeCollection = Backbone.Collection.extend({
model: TreeModel,
url: 'https://api.mongolab.com/api/1/databases/backbone-tree/collections/tree?apiKey=akey'
});
// Tree branch view
var CompositeView = Backbone.Marionette.CompositeView.extend({
tagName: 'ul',
template: _.template( $('#tree-template').html() )
});
// Tree root view
var CollectionView = Backbone.Marionette.CollectionView.extend({
tagName: 'div',
className: 'js-tree-root',
childView: CompositeView,
});
var treeCollection = new TreeCollection();
treeCollection.fetch().done(function () {
var collectionView = new CollectionView({collection: treeCollection});
App.mainRegion.show(collectionView);
});
Edit: In a regular Backbone.View I can pass the model to the data as a property. Notice in this example that the View's model is passed to the template with a data property which can be logged in the template. This could be useful in the template to test for the existance of properties on the model. I am not sure how to do this using a Marionette CompositeView
var jsonData = {
"color": "red"
};
var TheModel = Backbone.Model.extend({
});
var TheView = Backbone.View.extend({
el: '#main',
tagName: 'ul',
template: _.template( $('#the-template').html() ),
render: function () {
var tmpl = this.template({data: this.model.toJSON()});
this.$el.html( tmpl );
}
});
var theModel = new TheModel(jsonData);
var theView = new TheView({model: theModel});
theView.render();
<div id="main"></div>
<script type="text/template" id="the-template">
<li><%- data.color %></li>
<% //Log the current model that the template uses %>
<% console.log('template model =',data) %>
</script>
This happens to be related to the anwser I posted on your question here : Backbone Marionette Composite View Rendering Template
and is cause by the same issue. model being undefined in the template context.
The data passed to your template is the following:
{_id: Object, name: "Level 1", children: Array[2]}
and model is undefined in this context.
If you want to log/control the data passed to your template you have should use SerializeData in such a way:
var CompositeView = Backbone.Marionette.CompositeView.extend({
tagName: 'ul',
serializeData: function(){
var data = Backbone.Marionette.CompositeView.prototype.serializeData.apply(this, arguments);
console.log(data);
return data;
},
template: _.template( $('#tree-template').html() )
});
I asked question the other day on this app; after some good advice, I moved on and I now think this is a different issue.
Before, I was not getting any display on the screen/no errors or any console.logs. After working on it some more, I now have my model/view and some of my render function working.
I think the issue is with my template or with my append. Below is the full code as it stands now. There are //comments where I think there maybe some issues.
Any help with this would be greatly appreciated.
EDIT :: Thanks for the advice Niranjan. I made some the changes you mentioned; I took away the counter and sample data. With these new changes, my newsFeed.js is no longer being read and so I am unclear as to how to populate my collection. When I console.log out my collection I get an empty array with my defaults shown, but with the json file not being read in the first place how do I get anything to work?
EDIT#2 :: Thank you again Niranjan. With the changes you suggested and a few of my own, I now have the code below. The issue I have right now, Is my array is being populated far too many times. the JSON file has 8 entries in total and because of my _.each statement in my template it is looping 8 times where I only want it to loop once and then to split the array into separate entries. I tried first splitting it during my response parse but this didn't work, do you have any advice for this?
below the code is links to the live views of code and html/broswer content including a link to the JSON file.
My end goal is to click on one title and have the corresponding content show.
(function(){
var NewsFeedModel = Backbone.Model.extend({
defaults: {
title: '',
content: ''
}
});
var NewsFeedCollection = Backbone.Collection.extend({
model: NewsFeedModel,
url : 'newsFeed.js',
parse: function(response) {
console.log('collection and file loaded');
return response.responseData.feed.entries;
}
});
var NewsFeedView = Backbone.View.extend({
el : '.newsContainer ul',
template: _.template($("#feedTemp").html()),
initialize: function(){
var scopeThis = this;
_.bindAll(this, 'render');
this.collection.fetch({
success: function(collection){
scopeThis.render();
}
});
this.collection.bind( 'add', this.render, this);
console.log('View and Template read');
},
render: function () {
this.$el.html(this.template({
feed: this.collection.toJSON()
}));
console.log(this.collection.toJSON());
}
});
var newsFeedCollection = new NewsFeedCollection();
var newsFeedView = new NewsFeedView({
collection: newsFeedCollection
});
var title = newsFeedCollection.find('title');
var content = newsFeedCollection.find('content > title');
$(document).on("click", "#add", function(title, content) {
console.log("I have been clicked");
if($(title) == $(content)){
console.log('they match');
}
else{
console.log('they dont match');
}
$('.hide').slideToggle("slow");
});
}());
This is my underscore template.
<div class="span12">
<script id="feedTemp" type="text/template">
<% _.each(feed, function(data) { %>
<div id = "titleContent">
<%= data.title %>
<div id="content" class="hide">
<%= data.content %>
</div>
</div>
<% }); %>
</script>
</div>
I am using google drive as a testing ground; links for the full html/code.
https://docs.google.com/file/d/0B0mP2FImEQ6qa3hFTG1YUXpQQm8/edit [code View]
https://googledrive.com/host/0B0mP2FImEQ6qUnFrU3lGcEplb2s/feed.html [browser View]
https://docs.google.com/file/d/0B0mP2FImEQ6qbnBtYnVTWnpheGM/edit [JSON file]
There are lot more things in your code that can be improved.
Here is the JSFIDDLE.
Please go through the comments mentioned in the code.
For trying out things in Underscore's template, check Underscore's Template Editor.
Template:
<button id=add>Add</button>
<div class="newsConatiner">
<ul></ul>
</div>
<script id="feedTemp">
<% _.each(feed, function(data) { %>
<div id = "titleContent">
<h2> <%= data.title %> </h2>
<div id="content">
<%= data.content %>
</div>
</div>
<% }); %>
</script>
Code:
(function () {
var NewsFeedModel = Backbone.Model.extend({
//url: 'newsFeed.js',
defaults: {
title: '',
content: ''
}
});
var NewsFeedCollection = Backbone.Collection.extend({
model: NewsFeedModel,
url: 'newsFeed.js',
parse: function (response) {
console.log('collection and file loaded');
return response.responseData.feed.entries;
}
});
var NewsFeedView = Backbone.View.extend({
el: '.newsConatiner',
//template should not be inside initialize
template: _.template($("#feedTemp").html()),
initialize: function () {
_.bindAll(this, 'render');
this.render();
//ADD event on collection
this.collection.bind('add', this.render, this);
console.log('View and Template read');
},
/*
This initialize will fetch collection data from newsFeed.js.
initialize: function () {
var self = this;
_.bindAll(this, 'render');
this.collection.fetch({
success: function(collection){
self.render();
}
});
//ADD event on collection
this.collection.bind('add', this.render, this);
console.log('View and Template read');
},
*/
render: function () {
//This is how you can render
//Checkout how this.collection is used
this.$el.html(this.template({
feed: this.collection.toJSON()
}));
}
});
//Initialized collection with sample data
var newsCounter = 0;
var newsFeedCollection = new NewsFeedCollection([{
title: 'News '+newsCounter++,
content: 'Content'
}]);
//Created view instance and passed collection
//which is then used in render as this.collection
var newsFeedView = new NewsFeedView({
collection: newsFeedCollection
});
$('#add').click(function(){
newsFeedCollection.add(new NewsFeedModel({
title: 'News ' + newsCounter++,
content: 'Content'
}));
});
}());
I am new in backbone. I create a form, Now I want to show data in front end with rest service. my code is:
Template:
<script type="text/template" id="details">
<ul>
<% _.each(persons, function(person) { %>
<li><label>emailId : </label><%= person.emailId.emailId %></li>
<li><%= person.emailId.emailId %></li>
<% }); %>
</ul>
</script>
Model , Collection and View
<script type="text/javascript">
var UserModel = Backbone.Model.extend({});
var EntityList = Backbone.Collection
.extend({
model : UserModel,
url : 'http://192.168.1.3:8080/cofinding/business_profile/searchBusiness/123456789'
});
var View = Backbone.View.extend({
el : '#mydiv',
template : _.template($("#details").html()),
initialize : function() {
var self = this;
this.coll = new EntityList();
this.coll.fetch({
success : function() {
self.render();
}
});
},
render : function() {
// the persons will be "visible" in your template
this.$el.html(this.template({
persons : this.coll.toJSON()
}));
return this;
}
});
var view = new View();
</script>
Above code showing my data from service. But I need when I click on submit button.
Let's say you have the following button on your page:
<button id="submit">Submit</button>
Your View will need to define an events object that tracks what happens when a user clicks on your button:
var View = Backbone.View.extend({
events: {
'click #submit': 'fetchEntityList'
},
el: '#myDiv',
//etc...
});
You can then define the function that is executed. It should probably do something similar to what you currently have in initialize:
fetchEntityList: function() {
var self = this;
this.coll.fetch({
success : function() {
self.render();
}
});
}
The fetchEntityList function will now be executed whenever a user clicks Submit. It will fetch your EntityList collection and render it on the page.
hello guys i got my result what i want:
<body>
<div class="container">
<h1>User name</h1>
<hr>
<div class="page"></div>
</div>
<script type="text/template" id="edit-user-template">
<table border="1" cellpadding="4">
<tr>
<th>Email Id</th>
<th>Is Verified</th>
</tr>
<% _.each(users, function(user) { %>
<tr>
<td><%= user.get('emailId').emailId %></td>
<td><%= user.get('emailId').isVerified %></td>
</tr>
<tr>
<td><%= user.get('emailId').emailId %></td>
<td><%= user.get('emailId').isVerified %></td>
</tr>
<% }); %>
</table>
</script>
<script>
var Users = Backbone.Collection
.extend({
url : 'http://192.168.1.3:8080/app/business_profile/searchBusiness/123456789'
});
var UserList = Backbone.View.extend({
el : '.page',
render : function() {
var that = this;
var users = new Users();
users.fetch({
success : function() {
var template = _.template($('#edit-user-template')
.html(), {
users : users.models
});
that.$el.html(template);
}
})
}
});
var Router = Backbone.Router.extend({
routes : {
'' : 'home'
}
});
var userList = new UserList();
var router = new Router();
router.on('route:home', function() {
userList.render();
//console.log('we have loaded the home page');
});
Backbone.history.start();
</script>
I have a collection which contains one model. In my template I should be able to do:
<% _.each(collection, function(model) { %>
<p>logged in <%= model.username %>!</p>
<% }); %>
But I've found I need to do:
<% _.each(models, function(model) { %>
<p>logged in <%= model.attributes.username %>!</p>
<% }); %>
I'm not sure exactly what the problem is but the model isn't being populated properly. Anyone know why this is happening and how I can set the values within the model so I can loop over a collection of models and access the values simply with model.username ?
Thank you in advance.
Here's my model and collection:
var AccountModel = Backbone.Model.extend({
defaults:
{
username: "bob"
}
});
var AccountCollection = Backbone.Collection.extend(
{
model: AccountModel,
url: "/php/account-details.php",
parse: function(data, xhr)
{
return data
},
initialize: function()
{
}
});
Here's my fetch function:
fetchAccountCollection: function(){
var $this = this;
$this.homepageAccountCollection = new AccountCollection();
$this.homepageAccountCollection.fetch(
{
dataType: "json",
cache: false,
success: function(collection)
{
Backbone.trigger('accountcollection:loaded', collection);
},
error: function()
{
console.log("fetchAccountCollection: error");
}
});
},
When the success function is called the trigger invokes the render function within the controller:
renderAccount: function(collection)
{
var $this = this;
$this.loginPageView = new LoginView(
{
el: '#login-form',
template: 'loggedin-template',
collection: collection
});
$this.loginPageView.render();
},
When $this.loginPageView.render(); is called the following code is executed:
render: function()
{
var collection = this.options.collection;
var tpl = _.template($(this.options.template).html(), collection);
this.$el.html(tpl);
return this;
},
The value of the username is being returned from a PHP script like so:
$array=array('username' => $user['username']);
echo json_encode($array);
Underscore's each method (and many others) are mixed directly into the collection. Use collection.each(function () { ... }) instead of _.each(collection ...).
The problem is that your passing a Backbone.Collection to your template, so when you end up calling the following in your template:
_.each(models,function(model) { ... });
You are iterating through collection.models array which is an array of Backbone.Model's. Since a Backbone.Model stores model values within the attributes property, you have to access via model.attributes.username, you could also use model.get('username'), which would work as well.
As you stated, you would like to access via model.username, and you can do that by calling collection.toJSON() before passing it to the template, you have to put it in an object such as, {collection:collection.toJSON()};. Check out the documentation for toJSON. The method exists for both Backbone.Collection and a Backbone.Model.
The code would be the following:
render: function() {
var collection = this.options.collection;
var tpl = _.template($(this.options.template).html(), {collection:collection.toJSON());
this.$el.html(tpl);
return this;
}
Then you could use your template like:
<% _.each(collection, function(model) { %>
<p>logged in <%= model.username %>!</p>
<% }); %>
Here is a minimal JSBIN DEMO.
As a side note: It looks like your using a version of backbone < 1.1.0. Just be aware this.options goes away in the newer versions. When you upgrade be sure to have a look at the Change Log.
I’m working with backbone, this is the static data I have:
var emailfields = new EmailFields([
new EmailField({ id: "data-email", name: "Email" }),
new EmailField({ id: "data-first-name", name: "First Name" }),
new EmailField({ id: "data-last-name", name: "Last Name" }),
]);
I want to create n (n > 1) drop-down lists populated with the same data (emailfields). If any of the values is selected I want to notify the user that he cannot select the same field again.
This is my view:
EmailFieldSelectView = Backbone.View.extend({
initialize: function() {
_.bindAll(this, "addSingleEmailField", "add");
this.add();
},
addSingleEmailField: function(emailfield) {
$("select").each(function() {
$(this).append(new EmailFieldView({ model: emailfield}).render().el);
});
},
add: function() {
this.collection.each(this.addSingleEmailField);
},
});
This is my initialization:
window.emailview = new EmailFieldSelectView({
collection: emailfields
});
In order to populate each select with the same data I’m using $("select").
Is there a better way to do that (I feel this looks like a hack)?
Thanks.
What you've got seems like a reasonable way to approach things. You could use a template to reduce the javascript and need for a view to create select list options.
<script type="text/template" id="exampleTemplate">
<select id="list1">
<% _(emailFields).each(function(emailField) { %>
<option value="<%= emailField.id %>"><%= emailField.name %></option>
<% }); %>
</select>
<select id="list2">
<% _(emailFields).each(function(emailField) { %>
<option value="<%= emailField.id %>"><%= emailField.name %></option>
<% }); %>
</select>
etc.
</script>
Then the view becomes -
EmailFieldSelectView = Backbone.View.extend({
template: _template($('#exampleTemplate').html());
initialize: function() {
_.bindAll(this, "addSingleEmailField", "add");
this.render();
},
render: function() {
this.$el.html(this.template({ emailFields: this.collection.toJSON() }));
return this;
}
});