Let's build the client for our feature List repositories
. Each item in the list consists of a repository name, a short description, and a checkbox; which allows us to add or remove the repository from the project.
What follows is an HTML template ./templates/repositories.hbs
for a repository item:
<li> <label class="checkbox inline"> <input id="{{id}}" type="checkbox" {{enabled}} value="{{name}}"><h4 class="media-heading repoItem">{{name}}</h4> <small>{{description}}</small> </label> </li>
Let's add a Repository
model. We add a function Repository
that extends the Backbone Model
type and add a hash of default values for the four properties in our model. The enabled
property signifies that a repository is included in the selected project.
Vision.Repository = Backbone.Model.extend({ defaults: { id : "" , name: "" , description: "" , enabled: "" } });
Let's implement a collection for our Repository
model. We start by defining a function RepositoryList
, which extends the Backbone Collection
type. We add the projectId
of the selected project, and set the model type as Vision.Repository
. We then add a url
method and use the web API route /project/:id/repos
to get a list of repositories for a project.
The initialize
method is called when the collection is instantiated; from here, we assign the selected projectId
. The parse
method is called when a fetch is performed and will parse the response; here we assign our MongoDB _id
to the response.id
.
Vision.RepositoryList = Backbone.Collection.extend({ projectId: '', model: Vision.Repository, url : function() { return '/project/' + this.projectId + '/repos'; }, initialize: function(items, item) { this.projectId = item.projectId; }, parse: function( response ) { response.id = response._id; return response; } });
We now implement a view for a single repository. We add a function, RepositoryView
, that extends the Backbone View
type and add a tagName
and assign li
to it. This tag will be wrapped around our RepositoryView
function; our DOM element is a ul
tag. We include a viewTemplate
function and assign our precompiled handlebars template templates/repositories.hbs
to it. The render
method renders the view; we pass the repository
model to our viewTemplate
function, which is then added via $el
to our DOM element, and we return the view.
Vision.RepositoryView = Backbone.View.extend({ tagName: "li", viewTemplate: visiontemplates["templates/repositories.hbs"], render: function () { this.$el.html(this.viewTemplate(this.model.toJSON())); return this; } });
Let's implement a view for our RepositoryList
called RepositoryListView
. We start by defining a function, RepositoryListView
, that extends the Backbone View
type and adds a Repositories
array for our repository list. We add an initialize
method; if projectId
is empty we return. A valid projectId
results in rendering the view; first, we clear the DOM element, and we then assign a new RepositoryList
function to the views collection
. We initialize the list with our Repositories
array and our projectId
, we then call fetch
in our collection, and then we call render
for a successful fetch.
The render
method uses underscore to loop through the repository collection called collection.models
, calling add(item)
for each project. We include an add
method that instantiates a RepositoryView
function, passing to it a repository
model. We then append a rendered RepositoryView
to our DOM element via $el
and return the view.
Vision.RepositoryListView = Backbone.View.extend({ Repositories: [], initialize: function (args) { if (!args.projectId) return; var me = this; this.$el.html(''), this.collection = new Vision.RepositoryList(this.Repositories, { projectId : args.projectId }); this.collection.fetch({success: function(){ me.render(); }}); }, render: function () { _.each(this.collection.models, function (item) { this.add(item); }, this); }, add: function (item) { var repositoryView = new Vision.RepositoryView({ model: item }); this.$el.append(repositoryView.render(this.editMode).el); return repositoryView; } });
Let's make a few changes to our ProjectView
and add a click event when selecting a project. We start by defining an events
hash with a single event called click a, that calls the repository
method. The repository
method grabs projectId
from our model and then calls the trigger
method on event_aggregator
for the event repository:join
, passing projectId
. We will listen to this event on ProjectListView
.
events: { "click a" : "repository" }, repository: function() { var data = { projectId: this.model.toJSON()._id } this.event_aggregator.trigger('repository:join', data); },
Let's hook up the other side of the previous event and add an event binder to ProjectListView
. We add an event_aggregator.bind
statement to our initialize
method, binding the event repository:join
to the repository
method. The repository
method triggers a join
event on the router.
initialize: function () { this.event_aggregator.on('repository:join', this.repository, this); this.collection = new Vision.ProjectList(this.Projects); this.render(); }, repository: function(args){ this.trigger('join', args); },
Let's complete the picture and change router to listen to the join
event. We add a repositoryListView
function to the router and add a listenTo
event to the initialize
method that calls the join
method. The join
method calls repository
, which instantiates the RepositoryListView
function, passing projectId
.
repositoryListView:'', initialize : function(){ this.project(); this.listenTo(this.projectListView , 'join', this.join); }, join : function(args){ this.repository(args); }, repository : function(args){ this.repositoryListView =new Vision.RepositoryListView({ el: 'ul#repository-list', projectId: args.projectId }); },
Now, when you click on a project item's name in ProjectView
, RepositoryListView
is displayed.
18.191.223.123