0

My app is designed that router is changed then rendering other view but, I don't know that how communication for created other view object.

router.js

    var app = app || {};
(function() {
    'use strict';
    var views = app.view = app.view || {};
    app.Router = Backbone.Router.extend({
        routes: {
            '*home': 'homeRoute',
            'about': 'aboutRoute',
            'contact': 'contactRoute'
        },
        initialize: function() {
            // create the layout once here
            this.layout = new views.Application({
                el: 'body',
            });
        },
        homeRoute: function() {
            var view = new views.Home();
            this.layout.setContent(view);
        },
        aboutRoute: function() {
            var view = new views.About();
            this.layout.setContent(view);
        },
        contactRoute: function() {
            var view = new views.Contact();
            this.layout.setContent(view);
        }
    });
})();

view.js

var app = app || {};
(function() {
    'use strict';
    //views linitalize
    var views = app.view = app.view || {};
    views.Application = Backbone.View.extend({
        initialize: function() {
            // caching the jQuery object on init
            this.$content = this.$('#content');
            this.$loading = this.$('#loading');
        },
        setContent: function(view) {
            var content = this.content;
            if (content) content.remove();
            this.showSpinner();
            content = this.content = view;
            console.log(view);
            //content rednering
            this.$content.html(content.render().el, this.hideSpinner());
        },
        showSpinner: function() {
          this.$loading.show();
        },
        hideSpinner: function() {
          this.$loading.hide();
        },
    });
    views.Home = Backbone.View.extend({ });
    views.About = Backbone.View.extend({
      initialize: function(){
        this.render();
      },
      render: function(){
        var template =  _.template("<strong>About page</strong>");
      }
    });
    views.Contact = Backbone.View.extend({
      my_template: _.template("<strong>Contact page</strong>");
    });
})();

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <ul class="pills">
        <li><a href="#/">Home</a></li>
        <li><a href="#/about">About</a></li>
        <li><a href="#/contact">Contact</a></li>
    </ul>
    <div id="content"></div>
    <div id="loading">load the page...</div>
    <div id="sumMenu"></div>
    <script src="lib/jquery-3.1.1.min.js"></script>
    <script src="lib/underscore.js"></script>
    <script src="lib/backbone.js"></script>
    <script src="lib/backbone.localstorage.js"></script>
    <script src="routers/router.js" ></script>
    <script src="views/view.js" ></script>
    <script src="views/app.js" ></script>
  </body>
</html>

If you look at this code, you'll understand. It's hard to communicate what I said above.

Look at the view.js, I wrote 3 views property (home, about, contact) and those contained code that doesn't run.

my_template: _.template("<strong>Contact page</strong>");

I really want to know that after object create, how to set the objects value and rendering?

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Liquid.Bear
  • 333
  • 6
  • 21

1 Answers1

2

The code is heavily inspired by my other answer, but you need to read the Backbone documentation (and also Underscore's) to understand what's going on, what you're doing and what needs to be done to add features to it. Otherwise, you'll always drift away from the working code into a new mess that you don't understand.

The Backbone doc is short and sweet and the source code is filled with comments. Don't read all of Underscore's doc, but read at the least the documentation for the functions you're using (like _.template).


The Router routes

Since you copy-pasted the exact code from my other answer without first checking if it works, you copied a mistake that I made. The more specific routes should be defined first and the catch-all route last.

routes: {
    'about': 'aboutRoute',
    'contact': 'contactRoute',
    // put the catch-all last
    '*home': 'homeRoute',
},

When instantiating a new Router, its constructor calls _bindRoutes which parses routes from the last to the first.

_bindRoutes: function() {
  if (!this.routes) return;
  this.routes = _.result(this, 'routes');
  var route, routes = _.keys(this.routes);
  while ((route = routes.pop()) != null) {
    this.route(route, this.routes[route]);
  }
},

Routes added later may override previously declared routes.


The render function

What do you think the following will do?

render: function(){
    var template =  _.template("<strong>About page</strong>");
}

So all that's doing now is:

  • it creates a new function,
  • puts it in a local variable named template
  • and do nothing else.

or even this:

my_template: _.template("<strong>Contact page</strong>");

my_template property on views is not standard Backbone, so if you do nothing with it, it won't do something by itself.

To understand, you need to know that the Underscore _.template function takes a template string as argument (and optionally a settings object) and returns a new pre-compiled template function which takes an object as an argument. (More info and examples)

Backbone view's render function is left to the developer to override. It should ideally render something and be idempotent.

A simple view could be:

views.About = Backbone.View.extend({
    template: _.template("<strong>About page</strong>"),
    render: function() {
        this.$el.html(this.template());
        return this;
    }
});

A good convention is to return this at the end of render to enable chained calls.

And you should be doing this because you're chaining calls in your code:

content.render().el

jQuery and el

Why do you pass this.hideSpinner()?

this.$content.html(content.render().el, this.hideSpinner());

While it do change the HTML of the #content div with the view's el, using this.hideSpinner() returned value as a second parameter makes no sense.

jQuery's .html function only takes one parameter.


Where to put a loading spinner?

Not within synchronous DOM manipulation. It's useless to put a spinner that before being seen is removed.

A loading spinner makes sense when there is asynchronous loading of some sort, and that you want to inform the user that the page hasn't crashed or froze.

Say you want to load news for the home page.

homeRoute: function() {
    console.log("showing the spinner");
    this.layout.showSpinner();

    var collection = new Backbone.Collection({
            url: "/you/api/url/for/latest/news" // simple example
        }),
        view = new views.Home({
            collection: collection
        });

    collection.fetch({
        context: this,
        success: function() {
            console.log("removing the spinner");
            this.layout.hideSpinner();
            this.layout.setContent(view);
        }
    });

    console.log("End of homeRoute function");
},

In the console, you'll see the logs in the following order:

showing the spinner
End of homeRoute function
removing the spinner

More information, see:

Community
  • 1
  • 1
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
  • thank you sir. your very kind :) i have some more question that above the your answer i write **_bindRoutes** then construction call autoload it? and also render **return this;** too? – Liquid.Bear Dec 21 '16 at 01:47
  • @SeanSin `_bindRoutes` is a "private" function of Backbone's Router. It's called in any Router constructor. I included it in my answer as a reference. `return this` in render is a convention, I quoted the documentation on this. The default [`render`](https://github.com/jashkenas/backbone/blob/7da4ed73e7402baf614a50a6551d47ace68b5239/backbone.js#L1348-L1353) does this by default and enables chaining function calls. – Emile Bergeron Dec 21 '16 at 05:54