0
votes

I'm trying to use the event aggregator to fire a method off of a model's view. The problem is, when I fire the update or save method for the ItemView, it iterates through all models in the collection. How do I get it to not only fire properly for the model which the view represents (or a new modal in the save method's case), but also prevent it from firing for every model in the collection?

This application consists of a collection of Items, each Item has a model which is rendered into an ItemView and listed on the page. If a user clicks the edit item icon, then a ModalView is instantiated and the current Item model data is injected into the ModalView.

The ModalView which gets loaded with a template for the respective task. For this instance, i'm loading a template to edit the Item. Here's a summary of the relevant code:

var ModalView = Backbone.View.extend({
  tagName: "section",
  className: "modal",
  events: {
    'click .close': 'close',
    'click .minimize': 'minimize',
    'click .maximize': 'maximize',
    'click .save-item': 'saveItem',
  },
  html: null,
  initialize: function(options) {
    this.template = _.template(ModalTemplate);
    this.vent     = options.vent;
  },
  saveItem: function() {
    this.vent.trigger('item.save');
  },
});

The item collection's view is here:

var ItemsView = Backbone.View.extend({
  tagName: 'ul',
  className: 'item-items',
  render: function(){
    var self = this;
    // Make it flex GRRRR
    this.$el.addClass('flex-item');

    this.collection.each(function(item) {
      var date = item.get('created_at');
      var itemView = new ItemView({ model: item, vent: App.vent });
      this.$el.append(itemView.render().el);
    }, this);
    return this;
  }
});

Finally, the item model's view which contains the edit method that fires the ModalView

var ItemView = Backbone.View.extend({
  tagName: 'li',
  className: 'item',
  events: {
    'click .edit-item': 'edit'
  },
  initialize: function(options) {
    this.template = _.template(ItemTemplate);
    options.vent.bind("item.save", this.save);
    options.vent.bind("item.update", this.update);
  },
  save: function() {
    var attributes, item;
    item = new App.api.item.model();
    attributes = getMeta(true);
    item.save(attributes)
    .done(function(res) {
      Ui.modal.destroy();
      // Re-render items
      App.routers.main.render.User.sidebar();
      App.routers.main.render.Item.items(function() {
        Ui.resizeContent();
      });
    })
    .fail(function(res) {
      console.log(res);
    });
  },
  update: function() {
    console.log('update') // fires App.api.item.collection.length times
    var attributes, item;
    item = App.api.item.collection.get(App.rendered.modal.$el.data('id'));
    attributes = getMeta();
    item.save(attributes)
    .done(function(res) {
      Ui.modal.destroy();
      // Re-render items
      App.routers.main.render.Item.items(function() {
        Ui.resizeContent();
      });
    })
    .fail(function(res) {
      console.log(res);
    });
  },
  edit: function() {
    Ui.modal.new(ItemModalTemplate, this.model.attributes);
    App.rendered.modal.$el.attr('data-id', this.model.get('_id'));
    // New Editor
    var editor  = document.querySelector('#item-editor');

    window.editor = new MediumEditor(editor, editorOptions);
  }
});

Obviously I'm missing something fundamental here because console.log('update') in the save method of the ItemView fires for every item in the collection. What I was trying to do was keep the logic for save, and update in the view for the Item for organizational purposes.

Many thanks.

1

1 Answers

1
votes

Instead of options hold the model itself in the ItemModelView so you can call save directly without need for events.

Replace this Ui.modal.new(ItemModalTemplate, this.model.attributes); with UI.modal.new(ItemModalTemplate, this.model), and this this.vent.trigger('item.save'); with this.model.save()