I'm creating a Twitter Bootstrap multi-step modal.
This is how I'm trying to get the workflow to work:
Here is my modal markup:
section#paymentModal.modal.fade(tabindex='-1', role='dialog' aria-labelledby='paymentModalLabel' aria-hidden='true')
div.modal-dialog
div#paymentModalContent.modal-content
div.modal-header
button.close(data-dismiss='modal', aria-label='Close')
span(aria-hidden="true")×
h4#paymentModalLabel.modal-title Please enter your access code
div#paymentModalBody.modal-body
div.modal-footer
button.btn-previous.btn.btn-warning.hide(type='button', data-orientation='previous') Previous
button.btn-next.btn.btn-primary(type='button', data-orientation='next') Next Step
Here are my backbone templates:
script(type="text/template", id="tmpl-accessCode")
div.modal-header
button.close(data-dismiss='modal', aria-label='Close')
span(aria-hidden="true")×
h4#paymentModalLabel.modal-title Please enter your access code
div#paymentModalBody.modal-body
input(type='text', placeholder='Enter Access Code')
div.modal-footer
button.btn-next.btn.btn-primary(type='button', data-orientation='next') Next Step
script(type="text/template", id="tmpl-payment")
div.modal-header
button.close(data-dismiss='modal', aria-label='Close')
span(aria-hidden="true")×
h4#paymentModalLabel.modal-title Please enter your billing information
div#paymentModalBody.modal-body
// billing information goes here
div.modal-footer
button.btn-previous.btn.btn-warning.hide(type='button', data-orientation='previous') Previous
button.btn-next.btn.btn-primary(type='button', data-orientation='next') Next Step
Here is my JS:
(function() {
'use strict';
app = app || {};
app.AccessCode = Backbone.Model.extend({
url: '/accessCode/'
});
app.Payment = Backbone.Model.extend({
url: '/payment/'
});
app.AccessCodeView = Backbone.View.extend({
el: '#paymentModalContent',
template: _.template( $('#tmpl-accessCode').html() ),
events: {
'click .btn-next': 'verifyAccessCode'
},
initialize: function() {
this.model = new app.AccessCode();
this.listenTo(this.model, 'sync', this.render);
this.render();
},
render: function() {
this.$el.html(this.template( this.model.attributes ));
},
verifyAccessCode: function() {
var accessCode = this.model.set({'name': 'thomas'});
accessCode.fetch({
success: function() {
// chance view to billing view
},
error: function() {
console.log('Access code doesn\'t exist');
}
});
}
});
app.BillingView = Backbone.View.extend({
el: '#paymentModalContent',
template: _.template( $('#tmpl-payment').html() ),
initialize: function() {
this.model = new app.Payment();
this.listenTo(this.model, 'sync', this.render);
this.render();
},
render: function() {
this.$el.html(this.template( this.model.attributes ));
}
});
$(document).ready(function() {
app.accessCodeView = new app.AccessCodeView();
});
}());
My question is how do I call BillingView
from the success function callback in AccessCodeView
? Doesn't it go against backbone principles to call a view from within another view?
Also, is there a better way for me to do this than the current approach I'm taking?
All help and advice is appreciated :)
A better way to do this is to decouple data loading and view creation. This can be effectively done by using Backbone.Events.
Create a Custom JS Object say AppController and have it extend Backbone.Events.
var AppController = _.extend({},Backbone.Events);
Define a custom event and an event handler that will display load data and display a view.
AppController.on("app:view_billing",function(payload){
payload.accessCode.fetch().done(function() {
// Create an instance of the billing view.
// Update the url if required using the navigate method with trigger:false
});
});
From your method now you can do this :
verifyAccessCode: function(e) {
var accessCode = this.model.set({'name': 'thomas'});
var payLoad = {accessCode:this.accessCode};
AppController.trigger("app:view_billing",payLoad);
}