문제

I am making a Rails app using Backbone on the frontend. I have two views, one for a Publication model and one for an Article model. In the Publication view there is a 'createFeed' function that gets executed when the user fills out a form and clicks the button. When that happens I would like the database to get updated then for the two views to get re-rendered. So far with no luck.

Here is the Backbone Router function that initially renders both views:

home: function(){
    var publications = new SimpleGoogleReader.Collections.Publications();
    publications.fetch({
      success: function(publications){
        var view = new SimpleGoogleReader.Views.PublicationsIndex({model: publications});
        view.render();
      }

    });

    var articles = new SimpleGoogleReader.Collections.Articles();
    articles.fetch({
      success: function(articles){
        var view = new SimpleGoogleReader.Views.ArticlesIndex({model: articles});
        view.render();
      }
    });
  },

This is the createFeed function in my Publication View in Backbone. The post requests work fine, now just trying to figure out how to update the views.

  createFeed: function(e){
    e.preventDefault();
    var feed_url = $('#new_feed_name').val();

    $.post('/publications', {url: feed_url}, function(){
      $.post('/articles/force_update', {feed_url: feed_url}, function(){
          // should I put something here?
      });
    });

  } 

I have tried copying the code I have in my Router's home function into the callback for createFeed which updated the articles just fine but caused problems when updating the publication view, I guess because that is having the view render itself from within one of its functions. I have also tried including this in the view as well but not working.

initialize: function() {
  this.listenTo(this.model, "change", this.render);
},

How to get createFeed to update both views after it sends the proper data to the database?

Any input is appreciated!

* UPDATE *

Rida BENHAMMANE and Jon McMillan thanks for the input.

I now have update the router's 'home' function as such:

 home: function(){
    var publications = new SimpleGoogleReader.Collections.Publications();
    var articles = new SimpleGoogleReader.Collections.Articles();
    var pubIndex = new SimpleGoogleReader.Views.PublicationsIndex({model: publications});
    var artIndex = new SimpleGoogleReader.Views.ArticlesIndex({model: articles});

    // create a method to replace the force_update post in your publications view
    articles.listenTo(publications, "add", articles.force_update);
    publications.fetch();
    articles.fetch();
  },

and the createFeed function with my Publication view like this:

  createFeed: function(e){
    e.preventDefault();
    var feed_url = $('#new_feed_name').val();

    this.model.create({
        url: feed_url
    });
  }

This is per Jon's suggestion. It works great in terms of making the post and rendering the Publication view. Of course now I have to write the code to post to articles and update it's view accordingly per Jon's comment.

Is this something I should do separately in the Articles view? Or can I do it here in my createFeed function in the Publication view? If I do it separately then would I now have two views both having functions for the same event?

SOLUTION! *

publication index view

  initialize: function() {
    this.listenTo(this.model, "sync", this.render);
  },

  render: function(){
    this.$el.html( this.template({publications: this.model.toJSON()}) );
    return this;
  },

  createFeed: function(e){
    e.preventDefault();
    var feed_url = $('#new_feed_name').val();
    var that = this;

    this.model.create(
      {url: feed_url},
      { success: function(data){
          $.post('/articles/force_update', {url: feed_url, publication_id: data.id}, function(data){});
        }
      }
    );

  }

Publication Router

  home: function(){

    var publications = new SimpleGoogleReader.Collections.Publications();
    var articles = new SimpleGoogleReader.Collections.Articles();
    var pubIndex = new SimpleGoogleReader.Views.PublicationsIndex({model: publications});
    var artIndex = new SimpleGoogleReader.Views.ArticlesIndex({model: articles});

    //method to replace the force_update post in your publications view
    articles.listenTo(publications, "sync", function(){
      // var articles = new SimpleGoogleReader.Collections.Articles();
      articles.fetch( {success: function(){}} );
    });

    publications.fetch();

  },

I can move on with my life after two days. Lol. Thanks for the input guys!!

도움이 되었습니까?

해결책

You can use sync like described in another post already made or a number of other events.

Refer to Collection.create() and Collection.fetch() for which events you can listenTo.

initialize: function() {
    this.listenTo(this.model, "sync", this.render);
},
createFeed: function(e){
    e.preventDefault();
    var feed_url = $('#new_feed_name').val();

    this.model.create({
        url: feed_url
    });
}

You can listen for the add event in the Router to trigger the second post. The view for the articles can listen for some event triggered by the force_update post to render, much like the initialize function above.

home: function() {
    var publications = new SimpleGoogleReader.Collections.Publications();
    var articles = new SimpleGoogleReader.Collections.Articles();
    var pubIndex = new SimpleGoogleReader.Views.PublicationsIndex({model: publications});
    var artIndex = new SimpleGoogleReader.Views.ArticlesIndex({model: articles});

    // create a method to replace the force_update post in your publications view
    articles.listenTo(publications, "add", articles.force_update);
    publications.fetch();
    articles.fetch();
}

By listening to sync, you can remove the fetch({success:fn}) callback.

Update

The main idea is to leverage Backbone's event system to talk between the collections and the views. If the standard use cases apply to you, use Backbone's defaults otherwise make use of trigger("custom-event").

Inside the declaration of SimpleGoogleReader.Collections.Articles

        // collection "add" event callbacks pass the model as the first n
        // param to the callback
        force_update: function(publication) {
            var data = {
                feed_url: publication.get("url")
            };

            var callback = _.bind(function() {
                this.trigger('force-update');
            }, this);

            $.post('/articles/force_update', data).done(callback);
        }
    });

Inside the SimpleGoogleReader.Views.ArticlesIndex

        initialize: function() {
            this.listenTo(this.model, "force-update", this.render);
        }

다른 팁

The best way to do it is :

1- Use the sync function of the backbone collection to persist its state to the server instead of using $.post()

2- Bind the sync event to the views rendering :

initialize: function() {
  this.listenTo(this.model, "sync", this.render);
}

3- Keep a reference to your collections somewhere, so whenever you want to update your server with the client state, call the collections sync method and if it completes successfully yours views will be rerendered.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top