The View in Backbone is used to reflect the appearance of the Model in your app. They listen to events and respond accordingly.
In the next tutorial, I will not tell you how to bind Model and Collection to View, but will mainly discuss how View uses JavaScript template libraries, especially Underscore.js's _.template.
Here we use jQuery to manipulate DOM elements. Of course, you can also use other libraries, such as MooTools or Sizzle, but the official documentation of Backbone recommends that we use jQuery.
Next, we use the search box as an example to create a new View:
SearchView = Backbone.View.extend({ initialize: function(){ alert("Welcome to Backbone!"); }});var search_view = new SearchView();Whether it is a Model, View or Collection, the initialize() method will be automatically fired when instantiated.
el attribute
The el attribute refers to a DOM object that has been created in the browser. Each View has an el attribute. If it is not defined, Backbone will create an empty div element as the el attribute.
Let's create an el property for the View and set it to #search_containe.
<div id="search_container"></div><script type="text/javascript"> SearchView = Backbone.View.extend({ initialize: function(){ alert("Welcome to Backbone!"); } }); var search_view = new SearchView({ el: $("#search_container") });</script>At this time, the el attribute of the View refers to the div element whose id is search_container. We are bound to this div element at this time, so any event we want to trigger must be in this div element.
Loading templates
Backbone is strongly dependent on Underscore.js, so we can use small templates in Underscore.js.
Now, let's add a render() method and call it in initialize() so that the render() method will be automatically triggered when the View is initialized.
This render() method will load the template into the el property of the View through jQuery.
<script type="text/template" id="search_template"> <label>Search</label> <input type="text" id="search_input" /> <input type="button" id="search_button" value="Search" /></script><div id="search_container"></div><script type="text/javascript"> SearchView = Backbone.View.extend({ initialize: function(){ this.render(); }, render: function(){ // via Underscore Compile and generate template var template = _.template( $("#search_template").html(), {} ); //The generated template is loaded into the el attribute this.$el.html( template ); } }); var search_view = new SearchView({ el: $("#search_container") });</script>Add listening events
We use the events property of the View to add listening events, remembering that listening events can only be added to child elements of the el property. Now, let's add a listen event to the child element button.
<script type="text/template" id="search_template"> <label>Search</label> <input type="text" id="search_input" /> <input type="button" id="search_button" value="Search" /></script><div id="search_container"></div><script type="text/javascript"> SearchView = Backbone.View.extend({ initialize: function(){ this.render(); }, render: function(){ var template = _.template( $("#search_template").html(), {} ); this.$el.html( template ); }, events: { "click input[type=button]": "doSearch" }, doSearch: function( event ){ // When the button is clicked, alert alert( "Search for " + $("#search_input").val() ); } }); var search_view = new SearchView({ el: $("#search_container") });</script>Pass parameters to the template
The template can use the parameters passed from the View in the form of <%= %>.
<script type="text/template" id="search_template"> <!-- Use the passed parameters through <%= %> --> <label><%= search_label %></label> <input type="text" id="search_input" /> <input type="button" id="search_button" value="Search" /></script><div id="search_container"></div><script type="text/javascript"> SearchView = Backbone.View.extend({ initialize: function(){ this.render(); }, render: function(){ //Define the parameters that need to be passed var variables = { search_label: "My Search" }; // Generate templates through Underscore and pass the parameters var template = _.template( $("#search_template").html(), variables ); // Load the compiled HTML into the Backbone "el" this.$el.html( template ); }, events: { "click input[type=button]": "doSearch" }, doSearch: function( event ){ alert( "Search for " + $("#search_input").val() ); } }); var search_view = new SearchView({ el: $("#search_container") });</script>Handle DOM events
A very important feature of view is to help us automatically bind interface events. Recall how we used to bind events to interface tags? Maybe it's like this:
<p> <input type="button" value="Create" id="create" /> <input type="button" value="Read" id="read" /> <input type="button" value="Update" id="update" /> <input type="button" value="Delete" id="delete" /> </p> <script type="text/javascript"> function createData() { // todo } function readData() { // todo } function updateData() { // todo } function deleteData() { // todo } function deleteData() { // todo } $('#create').on('click', createData); $('#read').on('click', readData); $('#update').on('click', updateData); $('#delete').on('click', deleteData); </script>This is a typical example of binding DOM events through jQuery. If you are developing or have developed some complex application, you may have tried to organize these codes better in some way so that they look more structured and easier to maintain.
Backbone's view object provides us with an automatic binding mechanism for events to better maintain the relationship between DOM and events. Let's take a look at the following example:
<p id="view"> <input type="button" value="Create" id="create" /> <input type="button" value="Read" id="read" /> <input type="button" value="Update" id="update" /> <input type="button" value="Delete" id="delete" /> </p> <script type="text/javascript"> var MyView = Backbone.View.extend({ el : '#view', events : { 'click #create' : 'createData', 'click #read' : 'readData', 'click #update' : 'updateData', 'click #delete' : 'deleteData' }, createData : function() { // todo }, readData : function() { // todo }, updateData : function() { // todo }, deleteData : function() { // todo }, deleteData : function() { // todo } }); var view = new MyView(); </script>In this example, we put 4 buttons in a tag with id view and associate this tag with the view class MyView.
When defining the view class, we declare an events property, which represents the list of user events in the view, and is described as follows:
Event name selector: Event handler functionThe event name can be any event supported by the DOM object, the selector can be any selector string supported by jQuery or Zepto (including label selector, class selector, id selector, etc.), and the event handler should be the method name that has been defined in the view class itself.
The view object automatically parses the description in the events list, that is, use jQuery or Zepto to get the DOM object described by the selector and binds the event handler function to the event name. These operations will be automatically completed when the view class is instantiated. We can care more about the structure of the view class itself, rather than deliberately considering how to bind events.
Another issue you may be worried about: if the view's DOM structure is dynamically generated, does Backbone provide corresponding methods for dynamic binding and uninstalling events?
Actually, you don't need to worry about this issue, because the events in events are bound to the el element of the view object through the delegate() method, rather than the element described by the selector. Therefore, no matter how the structure within the view changes, events in events are valid.
(If you're familiar with jQuery, you might understand the delegate() method it provides. This method actually binds the event to the parent layer element, and then triggers the event by checking the target child element during the event bubble.)
The view object binds events through the delegate() method, which means that we do not need to care about the impact of view structure changes on events. It also means that the element corresponding to the selector in events must be within the el element of the view, otherwise the bound events will not take effect.
Nevertheless, there are some cases where we may still need to manually bind and undelegateEvents() and undelegateEvents() methods are used to dynamically bind and undelegateEvents(), which you can learn about by looking at the API documentation.
Render views and data
Views are mainly used for interface events binding and data rendering. However, the view object only provides a render() method related to render(), and it is an empty method without any logic and no references to anywhere. We need to overload it to implement our own rendering logic.
The view may contain a lot of interface logic. It is recommended that all view subclasses overload the render() method and use it as the entry method for the final rendering. In team development, coding strictly in accordance with specifications can help others better understand and maintain your code.