how to create nested templates on Backbone - backbone.js

I'm new on Backbone and I'm trying to click on a Button on the toolbar (located on toolbar div), the button is called "New".
After click I want to open a new panel on a different div with id= "app-list".
But when pressing on the new button it always override the "app-list" div
Here is my code(I'm using Backbone and coffeescript):
class MyApp.Views.ToolbarAppView extends Backbone.View
el: "#toolbar-app"
events: "click #add_new": "newApp"
newApp: (e) ->
myapp = new MyApp.Models.App
#model = myapp
newPanel = new MyApp.Views.NewAppView({ el: #$el, model: #model, parent: #})
newParent.render()
class MyApp.Views.NewAppView extends Backbone.View
template: JST["myapp", "new_app_view"]
render: ->
fieldsPanel = new MyApp.Views.EditAppView({ el: #$el, model: #model, parent: #})
fieldsPanel.setElement('#app-list').render()
class MyApp.Views.EditAppView extends Backbone.View
template: JST["myapp", "edit_app_view"]
tagName: "tr"
className: "edit_data"
render: ->
#$el.html(#template({ el: #$el, model: #model, parent: #})

Without knowing how your HTML structure looks, it's not easy to deduce what might be the problem. However, there's something funny going on these two lines here:
fieldsPanel = new MyApp.Views.EditAppView({ el: #$el, model: #model, parent: #})
fieldsPanel.setElement('#app-list').render()
In the constructor you set the view's el to the ToolbarAppView's el, and on the following line you change the element to another one.
Try replacing the two lines with the following:
fieldsPanel = new MyApp.Views.EditAppView({ el:'#app-list', model: #model, parent: #})
If that fails, consider editing your question with more info, especially regarding the relevant parts of your HTML templates.

Related

Can't display Backbone/Underscore template in Jade view

I'm trying to link the template in my .jade view to my Backbone model, and it's just not displaying anything inside my template script.
My .jade view:
extends ../layout
block content
.page
script(type="text/template" id="createRecipeTemplate").
<div class="ingredients-pane">
<form id="ingredientForm">
*[form]*
</form>
*[etc.]*
</div>
script(src='/js/myBackboneFile.js')
myBackboneFile.js:
var Recipe = Backbone.Model.extend({
defaults: {*[defaults]*}
});
var Recipes = Backbone.Collection.extend({
url: '/api/recipes'
})
var recipes = new Recipes();
var RecipeView = Backbone.View.extend({
model: new Recipe(),
el: '.page',
initialize: function() {
this.template = _.template($('#createRecipeTemplate').html());
},
events: {
*[events]*
},
*[functions for my events]*,
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
var RecipeView = new RecipeView();
Everything's linked up - if I type 'RecipeView' into the browser console, it gives me:
n {cid: "view2", $el: n.fn.init[1], el: div.page}
I've tried a few variations on the jade template syntax - putting pipes at the beginning of each line, using the dot after the script tag (as above), and just indenting normally (with the template in both standard HTML and Jade syntax each time), but no joy.
Am I missing something obvious?

How to render a backbone collection into two views

I am using twitter bootstrap link. When the user clicks the link a bootstrap modal appears.
Now because of some bootstrap technical difficulties in modal rendering i need to seperate the link and put the modal out the navbar div.
So consider i have two separate div
<div id="linkDiv">
</div>
and
<div id="modalDiv">
</div>
Now i have only one View which makes a call to the server to get the collection
app.View.FriendRequestListView = Backbone.View.extend( {
templateModalLink: _.template($('#link').html()),
templateModal: _.template($('#modal').html()),
tagName: 'div',
initialize: function(){
this.friendRequestCollection = new app.Collection.FriendRequestCollection();
this.friendRequestCollection.bind("reset", this.render, this);
this.friendRequestCollection.fetch();
},
render: function() {
$(this.el).html(this.templateModalLink({
friendRequestCollection: this.friendRequestCollection}));
return $(this.el);
},
});
Than i can render only one div like following
var list = new app.View.FriendRequestListView();
$('#linkDiv').html(list.$el);
My question is , Is it possible to render two templates at the same time and add the two templates to different DIV like for example in my case i want to get update
templateModalLink template to linkDiv and templateModal template to modalDiv with the collection I am getting from the server.
You have to instantiate the collection before app.View.FriendRequestListView(s) and pass app.View.FriendRequestListView(s) the collection:
var friendRequests = new app.Collection.FriendRequestCollection();
friendRequests.fetch(
success: function(collection, response, options) {
var list1 = new app.View.FriendRequestListView({collection: collection});
var list2 = new app.View.FriendRequestListView({collection: collection});
$('#linkDiv').html(list1.$el);
$('#modalDiv').html(list2.$el);
}
);

How to attach Backbone.Marionette view to existing element without creating extra element

Say I have these two Backbone.Marionette views:
var FooView = Backbone.Marionette.ItemView.extend({
tagName: p,
id: 'foo',
template: this.templates.summary
});
var BarView = Backbone.Marionette.ItemView.extend({
template: this.templates.summary
});
And then I want to show them inside an app region, like so:
App.contentRegion.show(new FooView/BarView());
The first view would create a new element and append it to the region. I thought the second way would be more like a standard Backbone view and attach itself to the region without creating a new element, but it wraps it in a tag. Is there a way to avoid this without using something like setElement()?
For this, you should use the attachView method: https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.region.md#call-attachview-on-region

Tabs in Backbone

I'm new with Backbone and I'm making an example app in which I have to include tabs. The thing is that I have a collection of cities and I want to create one tab for each city (the collection fetchs from the server). I made a view called TabsView, which in the render function passes the collection to a template, and this one loops through the collection and renders the tabs.
What I want to do is that the first tab appears as 'active'. What I've done for the moment is that each tab has a href to a route in the router which changes it's class to active using jquery. Don't know if this is the best way to do this but it works. Maybe there's a better way. Also, when the user clicks a tab, I want to be able to render other view.
Hope I made myself clear. Thanks, cheers,
Martin
Ok I solved this problem doing something like the following:
var Tabs = Backbone.View.extend({
template: JST['tabs'],
events: {
'click li' : 'switchTab'
},
tagName: 'ul',
className: 'nav-tabs',
render: function() {
this.renderTabs();
return this;
},
renderTabs: function() {
this.$el.html(this.template({ cities: this.cities }));
this.$('li:first').addClass('active');
},
switchTab: function(event) {
var selectedTab = event.currentTarget;
this.$('li.active').removeClass('active');
this.$(selectedTab).addClass('active');
}
});
It works fine, maybe it can be improved.

triggering events in multiple views

I'm putting together an app using Backbone.js, which has two Views right now, an IndexView and a QuizPartial. The IndexView renders the bulk of the page (some graphs and whatnot), and it contains many QuizPartials. My issue is that when a user clicks a 'delete' link in one of the partials, the partial should be deleted and the appropriate model destroyed, while the IndexView renders a button to create a new quiz. However, I can't get the IndexView to respond to that event.
Code:
class QuizPartial extends Backbone.View
tagName: "div"
className: "quiz"
events:
"click a.delete": "delete_quiz" # Works fine
initialize: -> #render()
delete_quiz: ->
if confirm "Are you sure you want to delete this test?"
$(#el).remove()
#model.destroy()
false
And then the index view:
class IndexView extends Backbone.View
tagName: "div"
id: "quizzes_index"
events:
"click .quiz a.delete": "render_new_quiz_button" # Never fires
initialize: -> #render()
# etc...
Is there something I should be doing differently?
Thanks!
The actual UI event is done within the quiz view. You correctly remove the element and destroy the model. Now you have two choices:
Have your IndexView listen for the "remove" event on your Quiz collection.
Trigger a new event from your quiz view to notify whoever is listening

Resources