class Car extends Backbone.Model {
// instance methods
someMethod(){}
static manufacturersByCountry(){
// custom logic to query manufacturers
}
}
var Car = Backbone.Model.extend({
// instance methods
}, {
// class methods
manufacturersByCountry: function(country) {
// custom logic to query manufacturers
}
});
initialize: function() {
// my custom stuff
Backbone.View.prototype.initialize.call(this);
}
var persistAuth = function() {}; // private
var Model = Backbone.Model.extend({
initialize: function() { // public
persistAuth.call(this)
}
}, {
triggers: {} // static
});
define(function (require, exports, module) {
'use strict';
require('css!css-event-widgets');
var tplList = require('text!templates');
var Marionette = require('marionette');
function constructor (options) {
var self = this;
var template = _.template(getChunks(tplList)('#todo'));
var openWidget = function (e){
var url = self.model.get('url');
if (!url) return;
e.preventDefault();
};
var events = function () {
var obj = {};
obj['click @ui.listItem'] = openWidget;
return obj;
};
Object.assign(self, {
ui: {
listItem: '.js-event-widget-list-item'
},
template: template,
events: events
});
Marionette.CollectionView.apply(self, arguments);
}
return Marionette.CollectionView.extend({constructor: constructor});
});
var UserView = Backbone.View.extend({
render: function() {
React.renderComponent(new UserComponent(), this.el);
return this;
}
});
var Router = BackboneRouteControl.extend({
routes: {
‘users’: ‘users#index’,
‘users/:id’: ‘users#show’,
‘users/:id/edit’: ‘users#edit’
}
});
var UsersController = function() {
return {
index: function() {
...
},
show: function(id) {
...
},
edit: function(id) {
...
}
};
};
var myRouter = new Router({
controllers: {
users: new UsersController()
}
});
// WRONG
initialize: function() {
this.listenTo(this.model, 'change', this.render);
}
// GOOD
modelEvents: {
'change': 'render'
}
var CollectionView = Backbone.View.extend({
render: function() {
var fragment = document.createDocumentFragment();
_.each(this.collection.models, function(item) {
var view = new MyView({
model: item
});
fragment.appendChild(view.render().el); // Appending to fragment
}, this);
this.$el.html(fragment); // Populating the DOM
}
});
Note: From Marionette v3.x, Marionette.View replaces Marionette.LayoutView and Marionette.ItemView.
CollectionView in most cases does not need template:
var collectionView = new Marionette.CollectionView({
childView: new Marionette.View({}),
collection: new Backbone.Collection([])
});
var setByPath = function (model, path, value) {
var iter = function (model, prop, key) {
var next = key + 1;
if (path.length === next) {
return model.set(prop, value);
}
return iter(model.get(prop), path[next], next);
}
return path.reduce(iter, model);
}
ES5
const setByPath = (model, path, value) => {
const iter = (model, prop, key) => {
const next = key + 1;
if (path.length === next) {
return model.set(prop, value);
}
return iter(model.get(prop), path[next], next);
}
return path.reduce(iter, model);
}
setByPath(model, 'foo.bar'.split('.'), 5); // model.toJSON() -> {foo: {bar:5}}
Person = Backbone.Model.extend({
get: function (attr) {
if (typeof this[attr] == 'function') {
return this[attr]();
}
return Backbone.Model.prototype.get.call(this, attr);
},
name: function() {
return this.firstName + " " + this.lastName;
},
toJSON: function() {
var attr = Backbone.Model.prototype.toJSON.call(this);
attr.name = this.name();
return attr;
}
});
Подписаться на все события
const extend = (what, how) => ((fn => function (...args) {how.apply(this,args);fn.apply(this,args);})(what));
// All View triggers
Backbone.View.prototype.delegate = extend(Backbone.View.prototype.delegate, function (eventType, selector, listener) {
this.$el.on(eventType+'.delegateEvents' + this.cid, selector, () => console.log('[ui event]', `${eventType} ${selector}`, this.el));
return this;
});
// All View private method triggers
Backbone.View.prototype.trigger = extend(Backbone.View.prototype.trigger, function (eventType, payload) {
console.log('[trigger]', eventType, payload, this.el);
});
// Subscribe to all Backbone events
Backbone.Events.on('all', function (eventType, payload) {
console.log('[event]', eventType, payload, this.el);
});
// All View public method triggers
Marionette.View.prototype.triggerMethod = extend(Marionette.View.prototype.triggerMethod, function (eventType, payload) {
console.log('[triggerMethod]', eventType, payload, this.el);
});
// Turn on debug mode
Backbone.Radio.DEBUG = true;
// Subscribe to all Radio channels
_.forEach(Backbone.Radio._channels, channel => Backbone.Radio.tuneIn(channel.channelName));
// trigger
Backbone.View.prototype.trigger('...')
// triggerMethod
Backbone.View.prototype.trigger('childview:...')
initialize: function (){
...
this.listenTo(this, "bookingEventHeader:incMessage", this._onIncomingMessage);
}
...
_triggerMessage: function (actionName, data) {
var msg = MnHelper.Message.create(actionName, data);
this.triggerMethod("bookingEventHeader:message", msg)
},
В чём различие bookingEventHeader:incMessage
от bookingEventHeader:message
, почему не может быть одного типа сообщения - общего?
В компоненте m-booking-event-header
очень сильно разбиты события на разные области, хотя всё это просто события, главное, чтобы названия различались.
Ещё я заметил сильную связь между компонентами завязанную на событиях - во многих зависимых компонентах названия событий захардкожены.
Т.к. в Backbone есть встроенный механизм событий...
triggers: {
'click @ui.selectItem': 'ModuleName:action'
},
...
events: {
'click a': 'showModal'
},
...
// Incomming events
childViewEvents: {
'SubModuleName:action': 'onModuleNameAction' // onModuleNameAction === ModuleName:action
},
...
onModuleNameAction: function () {} // onModuleNameAction === ModuleName:action
Я предлагаю:
var TRIGGER_SELECT_ITEM = 'click @ui.selectItem';
var TRIGGER_CLICK = 'click a';
var EVENT_SELECT_ITEM = 'ModuleName:action'; // ModuleName:action === ModuleName.onAction
var EVENT_SHOW_MODAL = 'showModal';
var TRIGGER_EVENT_SELECT_ITEM = ModuleName.triggers.EVENT_SELECT_ITEM;
...
// Public methods
// shared events
triggers: function () {
var e = {};
e[TRIGGER_SELECT_ITEM] = EVENT_SELECT_ITEM; // TRIGGER_SELECT_ITEM === EVENT_SELECT_ITEM
return e;
},
...
// local events
events: function () {
var e = {};
e[TRIGGER_CLICK] = 'showModal';
return e;
}
...
childViewEvents: function () { // childViewEvents v3+ === childEvents v2.4.4
var e = {};
e[TRIGGER_EVENT_SELECT_ITEM] = 'itemSelected';
return e;
},
...
// Static methods:
triggers: {
SELECT_ITEM: TRIGGER_SELECT_ITEM
}