I started to use mixins from this post: Proper way of doing view mixins in Backbone
var MyMixin = {
foo: "bar",
sayFoo: function(){alert(this.foo);}
}
var MyView = Backbone.View.extend({
// ...
});
_.extend(MyView.prototype, MyMixin);
myView = new MyView();
myView.sayFoo(); //=> "bar"
Which works fine unless its a conflicting method in the mixing: Example render() in mixin and render() in the actual view.
How can I go about firing the mixin methods first then the actual view methods?
I might recommend using Backbone.Cocktail which provides a really succinct way of specifying mixins (that respect inheritance):
var Mixin = {
initialize: function() {
console.log("I'll be called as well as the class's constructor!");
}
};
var View = Backbone.View.extend({
mixins: [ MyMixin ]
});
I've detailed it in this blog post.
Why don't you simply use the other answer provided on that question: Backbone-Mixin Gist?
Related
Basically I couldn't understand the difference between Ember Object and an Ember Mixin.
If Ember.Mixin.create() is itself extended from Ember.Object then why don't we mix objects created by Ember.Object.create() instead of Ember.Mixin.create()?
Why dont we use Ember objects like this
let TestObject = Ember.Object.create({
init() {
this._super(...arguments);
this.set('list', Ember.A([]));
}
});
let TestComponent = Ember.Component.extend(TestObject, {});
Instead of using a Ember mixin like below
let TestMixin = Ember.Mixin.create({
init() {
this._super(...arguments);
this.set('list', Ember.A([]));
}
});
let TestComponent = Ember.Component.extend(TestMixin, {});
So I don't want to go into the historical aspects of mixins, other than you shouldn't really use them, and specifically your example will lead to many bugs because of the way state is shared between mixins.
In your mixin example would actually share state between different component instances when mutating the list.
Really, your best bet is to pretend that mixins never existed in the first place.
EDIT: Discussion on mixin depreciation https://github.com/emberjs/rfcs/issues/534
I've been diving into the scary stuff recently.. :) scary stuff being the source of popular js frameworks like backbone.js, angular.js, vue.js and so on.
I'll take Backbone as an example here. I am trying to figure out how is a model attached to the view?
Here is the code and if someone could just point out the part where this is happening, would be awesome!
https://github.com/jashkenas/backbone/blob/master/backbone.js
Actually, the part I don't understand is that there is not innerHTML called anywhere, so how is the element being populated with the data?
Backbone is not Angular, it doesn't bind model to html for you, also it does not actually renders views for you, you have to implement render methods in your views and call them when you find appropriate. In fact, I think it might be confusing to developer coming from 2-way binding frameworks. Backbone is all about giving all the control to the developer, but you have to do all the work yourself.
Minimal model => view flow example would be something like
var MyModel = Backbone.Model.extend({
defaults: {
test: 'test',
},
initialize: function (options) {
console.log(this.get('test'));
},
});
var MyView = Backbone.View.extend({
el: '#your-el',
initialize: function (options) {
this.template = _.template('<div><%= test %></div>');
this.listenTo(this.model, 'change', this.render);
},
render: function () {
// rendering happens here, innerHTML, $.html(), whichever you prefer
// and you can pass model data as this.model.toJSON()
// or you can pass an object with data
// also, you probably will need a templating library or use
// bundled underscore _.template(html, data) method to render blocks of html
// for example, with underscore
this.$el.html(this.template(this.model.toJSON()));
return this; // for chaining
},
});
var myModel = new MyModel();
var myView = new MyView({
model: myModel,
});
myModel.set('test', 'newValue'); // view should render after this call
Check the list of built-in events at backbonejs.org.
I'm trying to find best option to make Backbone views reusable. I goggled and found many different solutions but not sure which one suits my requirements. Basically I'm going to have many widgets filled with real time data and I need a base component that will handle service subscriptions
Is following best solution for this problem:
App.View.Base = Backbone.View.extend({
baseMethod: function( params ) {};
});
App.ExtendedView.Base = App.View.Base.extend({
// new stuff here
// overriding App.View.Base.baseMethod
baseMethod: function( params ) {
// overriding stuff here
App.View.Base.prototype.baseMethod.call(this, params); // calling super.baseMethod()
}
});
Is there any better approach? or should I use mixins?
I might be inclined to favour composition over inheritance here, and create a spinner view, and use instances of it in other views that require spinner functionality.
More info: Prefer composition over inheritance?
The typical rule-of-thumb I use for stuff like this is if there are any immutable methods in the base class that provide a common context for all your sub-classes, then inheritance makes sense. For instance, I've created a BaseView class for my Backbone application that looks something like this:
define(function() {
return Backbone.View.extend({
/**
* show() and hide() are immutable
*/
show : function() {
this.beforeShow();
this.doShow();
this.afterShow();
},
hide : function() {
this.beforeHide();
this.doHide();
this.afterHide();
},
doShow : function() {
this.$el.show();
this.trigger('displayComplete', {action : 'show'});
},
doHide : function() {
this.$el.hide();
},
//Override the following to extend behavior of the view
//before and/or after the view is shown/hidden.
beforeShow : function() {},
beforeHide : function() {},
afterShow : function() {},
afterHide : function() {}
});
});
This is a pretty simple example, but it has proven to make things much easier for development of my application, as my central controller object is given a common interface for showing and hiding views. I suppose you could use composition here as well, but that requires doing an explicit extend() at runtime. You get the same result in either case, but I just prefer to have the functionality available when I instantiate my views.
Another thought is that it really depends upon what you want to accomplish. Inheritance is much more rigid than composition, but again, it depends upon what you ultimately want to accomplish, and sometimes enforcing rigidity to maintain a context is a good thing.
I would like to use mixins with my BackBone Views.
Here is my mixin:
var mixin = {
events: {
"click" : "doStuff"
},
doStuff: function() { alert("bah!"); }
}
Here is how I mix it into two separate views:
var view1 = Backbone.View.Extend({ ... });
_.extend(view1.prototype, mixin);
var view2 = Backbone.View.Extend({ ... });
_.extend(view2.prototype, mixin);
The trouble I am running into is that the click event only seems to work in view1. If I initialize view2 first, then the click event only works in view2.
Any ideas what I am doing wrong?
Thanks (in advance) for your help.
You can override the extend method on backbone to due the sort of inheritance and merging you expect. You just need to dig through the documentation a little bit and the objects to find what you want.
This way you have a BaseObject then extend off of that your two objects.
Cheers! I have two controllers and I want to have access to takenSeatsNumbers from TravelClient.TourController.
TravelClient.TourController = Ember.ObjectController.extend({
needs: ['tour.seats']
});
TravelClient.TourSeatsController = Ember.ObjectController.extend({
takenSeatsNumbers: []
});
Do I use needs in the right way? And how to get takenSeatsNumbers from tour template?
As mentioned above, this is a current bug and so the above will seemingly work, but won't work in reality, as the jsFiddle demonstrates. The solution for the moment is to pass in the instance of the controller via this.controllerFor in the route. It's far from ideal, but it will suffice for now.
It occurs because Ember refers to controllers using the dot.notation, whereas if you use camelCase or *under_scores* then it will create you different instances.
The solution is to inject the controller from your route, like so:
TravelClient.IndexRoute = Ember.Route.extend({
setupController: function(controller) {
var tourSeatsController = this.controllerFor('tour.seats');
tourSeatsController.set('takenSeatsNumbers', [1,2,3]);
controller.set('tourSeatsController', tourSeatsController);
}
});
And then you can use it in your view as: {{tourSeatsController.takenSeatsNumbers.length}}.
This code is based on ember-pre4. The proxying of properties from another controller seems to be a pattern this way and could likely be generalized with the help of a mixin:
TravelClient.TourController = Ember.ObjectController.extend({
needs: ['tourSeats'],
someMethod : function(){
var tourSeatsController = this.get("controllers.tourSeats");
// do something with it
},
takenSeatsNumbers : function(){ //proxy the property
return this.get("controllers.tourSeats.takenSeatsNumbers")
}.property("controllers.tourSeats.takenSeatsNumbers")
});
TravelClient.TourSeatsController = Ember.ObjectController.extend({
takenSeatsNumbers: []
});