官术网_书友最值得收藏!

Rendering third-party plugins

A common issue when rendering views is not rendering plugins from others because they are designed to work with traditional web applications but not with SPA; this is because many plugins are DOM-dependent, which means that the target element should exist in the actual DOM. To see this issue more clearly, let me show you an example with the jQueryUI Calendar plugin. Let's add a birthdate field to our ContactEditor, replacing the age field.

// index.html
// ...
<div class="form-group">
  <label for="birthdate">Birth date</label>
  <input id="birthdate " type="text"
    class="form-control" value="<%= birthdate %>" />
//...

And make the proper changes in the view:

class ContactForm extends ModelView {
  // ...
  serializeData() {
    return _.defaults(this.model.toJSON(), {
      name: '',
      birthdate: '',
      // ...
    });
  },
  saveContact(event) {
    event.preventDefault();
    this.model.set('name', this.$el.find('#name').val());
    this.model.set('birthdate',
      this.$el.find('#birthdate').val()
    );
    // ...
  },
// ...
});

To show a calendar on the birthdate field we need to call $('#birthdate').datepicker()somewhere, but what is the best place to do that?

// ... edit-contact.js
class ContactEditor {
  // ...

  showEditor(contact) {
    var contactForm = new ContactForm({model: contact});
    this.region.show(contactForm);
    contactForm.$('#birthdate').datepicker();

    this.listenTo(contactForm, 'form:save', this.saveContact);
    this.listenTo(contactForm, 'form:cancel', this.cancel);
  };
};

After calling the show() method on the region object, the contactForm view is live in the DOM, so it makes sense to call the datepicker() method after that. However this is not a good strategy because our controller object knows about DOM elements, which are not its responsibility.

Views should be responsible for dealing with the DOM, so rendering third-party plugins is included. Another approach could be to extend the render() method on the FormView class but we already have the onRender() callback, which is called after the rendering process.

// ... edit-contact.js
var ContactForm extends ModelView {
  // ...
  onRender() {
    this.$('#birthdate').datepicker();
  },
  //...
});

But this is not going to work because we are rendering the view on a region. Did you remember the show() method?

class Region {
// ...
  openView(view) {
    this.ensureEl();
    view.render();
    this.$el.html(view.el);
  }
// ...
}

The showing process first renders the view in memory and after that makes it available on the DOM. That's why this doesn't work. The intent of the onRender() method is to make template changes before making them available on the DOM. We need to add a new callback method that will be called when the view is in the DOM.

class Region {
// ...
  openView(view) {
    this.ensureEl();
    view.render();
    this.$el.html(view.el);

    // Callback when the view is in the DOM
    if (view.onShow) {
      view.onShow();
    }
  }
// ...
}

Remember to make this feature available in CollectionView too.

// common.js
class CollectionView extends Backbone.View {
  // ...
  onShow() {
    var children = this.children || {};
    _.each(children, child => {
      if (child.onShow) {
        child.onShow();
      }
    });
  }
}

So, our ContactForm will end with something like this.

// apps/contacts/contactEditor.js
class ContactForm extends ModelView {
  // ...

  // Call the onShow method for each children
  onShow() {
    // Ensure that children exists
    var children = this.children || {};

    _.each(children, child => {
      if (child.onShow) {
        child.onShow();
      }
    });
  }
  //...
}

Remember, most third-party plugins need to have the element in the DOM or they will not work, so you should call the plugin only after rendering the view. The best place to call plugins is in the extended view class so the responsibility for DOM manipulation is encapsulated in the view.

主站蜘蛛池模板: 农安县| 广德县| 城步| 根河市| 阿克陶县| 咸宁市| 阿荣旗| 嘉义市| 昭觉县| 隆安县| 华容县| 泰安市| 杭州市| 云安县| 河津市| 德钦县| 涟水县| 嘉义县| 长春市| 满洲里市| 樟树市| 孟津县| 邛崃市| 喀喇沁旗| 宣恩县| 徐闻县| 松阳县| 天峨县| 克什克腾旗| 茂名市| 驻马店市| 浑源县| 陵水| 西和县| 郎溪县| 清涧县| 尼木县| 师宗县| 庄河市| 杭锦后旗| 崇明县|