What's difference between Mixins and Services on Emberjs - ember.js

I'm trying to follow the best practice Ember and their potentiality and this question comes to my mind what is the difference between Mixins and Services and how you are using each of them?
I have some services/mixins and work pretty good but I want to be sure I'm doing it right.

A mixin is when you want different objects to have the same behaviour/data. Say you want several controllers to trigger the same action, but change one argument:
// app/mixins/change-name.js
export default Ember.Mixin.create({
actions: {
changeName(item) {
item.set('name', this.get('name'));
}
}
});
// app/controllers/some-controller
import ChangeName from '<app-name>/mixins/change-name';
export default Ember.Controller.extend(ChangeName, {
name: 'Some Controller'
});
Notice that the controllers will have the same action, but it's not shared, each has its own. You can also extend mixins from the object itself since they're added to the _super() chain.
One gotcha to keep in mind is that primitive by-reference data types like the array are still pass by reference. So if you have a Mixin with an array property, make sure to use Ember.computed on the array to create new instances each time the Mixin is used. Otherwise simply using a generic [] will lead to all the Mixin uses pointing to the same array. Different reference values, all pointing to the same thing.
Services can be seen as a sort of mutable shared data. If you have a set of data or behaviour that needs to be accessed from different parts of your application, it's a good candidate for a service.
One such example would be a shopping basket, for example. Regardless of where you are in your application, you will need to refer to the same shopping basket in order to manipulate its data.

Related

Passing parameters between routes in Ember 2.x

While going from one route to another, I want to pass some data (especcially arrays). How is it possible?
Why can't we use query-params with arrays?
Is it a problem storing data in a specific service during transition?
Note:
I know there are some old questions those are nearly the same with this question. But their selected answers are no more applicable for Ember 2.x. Those questions are: 1, 2.
I´m not sure if queryparams won´t work with arrays as I only used it with single ids, but it would not be a good solutions even if it worked, there´s a limit on how much you can send by parameters and you should not bother any user with your data.
Just create a model to save your data for local use, so you can simply use the ember store
Use a service you´ll have to inject in every controller you want to use your data
I would prefer the model/store variant so you´ll be able to observe and just follow the normal flow which is also good if someone else has to maintain your code.
UPDATED
After testing with "transition.data"; not updating the history seems as a problem for us. So we again use "queryParams". The constraint is: do not pass a complex object between routes
OLD ANSWER
I'm using transition object for this purpose in an action while routing as the following:
let transition = router.transitionTo(route, model);
transition.data[propName] = propValue;
Also I wrote a component to use this code as link-to.

Ember 2.0 Controllers or Just Components...?

I have read that Ember2 is attempting to remove controllers. I was even linked to this RFC https://github.com/ef4/rfcs/blob/routeable-components/active/0000-routeable-components.md. However, I have been following the tutorial, and they insist on making a Controller. Do we still need to make Controllers or is this out of date?
Controllers are still needed (and thus haven't been deprecated) for two reasons: query parameters, and because components aren't routable yet. You can follow the tutorial's use of controllers without it causing you too much grief later on.
However, if you want to pull ahead of the tutorial, you can use components instead, barring the two caveats above. There is no way around using controllers for query parameters, but you can avoid the lack of routable components using this simple hack:
Let's say you're creating a Route called Dashboard. The tutorial will tell you to create corresponding Controller and Template as well. Go ahead and do that, but delete the Controller. Create a component called dashboard-main, move the logic from the Controller to the component.js file and the Template to the component's Template. Then, in the Dashboard Template, just refer to the component:
{{dashboard-main items=model foo=foo bar=bar ...}}
Depending on what you're doing in the Route, you still may need the setupController() method (that's still the only way you can move values other than the model from the route to the template so that they can be passed to the component), and of course your controller/component implementation may have other minor changes, but that's the basic gist of it.
To be most ready for when controllers are deprecated, you should avoid them by using components instead.

How can I have a component inherit several attributes from the controller?

New to Ember.js.
I'm trying to create robust components that will delegate to the controller for various attributes. I know that I can bind individual attributes like this, but it seems verbose.
{{#my-component attr1=attr1 attr2=attr2}}
Hello
{{/my-component}}
It seems like it might be a common case to want to delegate everything to the controller. Is there a recommended pattern for doing so?
Your example code would be considered the correct way.
You could technically pass in a single object (possibly composed from the controller), but I would recommend against that. A component shouldn't really know much about where the data is coming from as attr1 could be a model property and attr2 could be a property of the view which doing some sort of computation. By passing in the single object you limit the flexibility of the component.
In addition to flexibility I tend to prefer the long argument list as it is clear what your component accepts; even if it is a bit more verbose. If your component is taking a huge list of arguments it may be a sign that the component is trying to do too much and you may want to break it down into smaller components.
App.MyComponentComponent = Ember.Component.extend({
attr1: function() {
return this.get('targetObject.attr1');
}.property('targetObject.attr1'),
attr2: function() {
return this.get('targetObject.attr2');
}.property('targetObject.attr2')
});
From Ember docs:
"If the component is currently inserted into the DOM of a parent view, this property will point to the controller of the parent view."
Use with caution.

What type of controller should I use to represent a complex object which is not a (persisting) model?

I'm writing a calendar application, which will need to display events by month.
While I'll need to create objects to represent the calendar months, I take it that these these CalenderMonth objects should NOT be 'models' (in Ember terminology), since the CalendarMonth objects won't persist to the server (whereas the Event objects will). Instead, the CalendarMonths will be 'objects', build with a CalendarMonth 'class', extending Ember.Object
So then, what sort of controller do I use as a proxy to the (frequently changing) CalendarMonth object? A (vanilla) controller? An ObjectController? An ArrayController?
ObjectController seems like the way to go, since it really is my intention for the the controller to act as proxy to a single object. I think I'm only thrown by the fact that in the corresponding route object, I'd be assigning the CalendarMonth object as the controller's MODEL. When, it's not a model, it's just an object.
Put another way, my question is:
Is it bad practice to assign an Ember object which is NOT a model to an ObjectController's 'model' property?
It is not bad practice to use a normal JS object as a controller's model/content. All that matters is how the view is going to render the model. If you're only going to display a single event at a time, or a single month for all events in that month, then the ObjectController is your best bet.
An ArrayController is used for when you want to loop round your model/content in the controller and display each item in the view. I don't think you should worry too much about what controller you should use, it will become pretty obvious which one you want as soon as you decide how to create your view.
When Ember talks about using a Model for your controller, you can use your own Ember Object if you wish and then reference it in the controller, but it doesn't matter if that is a natural JS object or Ember Object. A controller sees both just fine.

accessing the model from the template

Playing around with ember, I found that sometimes the model is stored on the controller's content property, sometimes the model is directly available on the controller as well. I do not understand however, when this is the case.
Let me explain it by an example which I found when assembling my ember MVC.
Setup A - The start
I defined a custom Member object, corresponding MemberRoute, MemberView classes and a template with the name member.
The Member object had some attributes such as id, nickname, etc.
NOTE: no controller of the form MemberController was defined, thus by ember's convention, it provides the controller on its own.
Setup B - The customization
Same as setup A, but now there is a MemberController defined that contains some action methods that are triggered from within the template.
The strange behaviour (resp. what I do not completely understand)
in setup A, I can refer to the Member's attributes directly with {{id}} or {{nickname}}.
in setup B, I have to use {{content.id}} or {{content.nickname}}
As documented in ember's documentation, MemberView does
setupController : function(controller, member) {
controller.set('content', member);
},
So, could somebody help me to understand why the difference and where the difference is? Currently, my guess would be either
that the context of the template is different (possibly there is a code piece missing in the setup of the controller?)
or
the default controller that is provided by ember automatically, has some additional magic that is not directly avaiable for customized controllers.
Any help to understand this is highly appreciated. It already took my quite a while to come as far as this. I first thought it could be the modularization introduced by the project setup with requireJS (well, I still think that could have a influence). Ember is v1.0pre4.
Thanks in advance!
Patrick
So, could somebody help me to understand why the difference and where the difference is? Currently, my guess would be either
that the context of the template is different (possibly there is a code piece missing in the setup of the controller?)
or
the default controller that is provided by ember automatically, has some additional magic that is not directly avaiable for customized controllers.
It's hard to say for sure without seeing your code, but my best guess is that your MemberController extends Ember.Controller. The default provided by ember (in this scenario) would have been an Ember.ObjectController. If that's what you want, change your MemberController definition to:
App.MemberController = Ember.ObjectController.extend({
myProperty: 'value'
});
An objectController acts as a proxy to it's content property, typically that is an ember model. So if things are wired up correctly you should never need to access a model via the 'content` property. If you ever see something like:
{{content.id}} or {{content.nickname}}
it's a sign that you should change to an ObjectController. See EMBER GUIDES: REPRESENTING A SINGLE MODEL! for a more detailed explanation.
an ObjectController acts as proxy to the object set to the controller's content. When no controller is defined, Ember will create a controller for you and set its content by default to whatever object is returned by the model() function, if defined, in the route. The behaviour should be the same whether you define your own controller or let Ember define one for you
The default context in the template is the controller itself i.e. this = an instance of your controller or the generated one. When you try to access nickname in that context, Ember will first try to resolve it against the controller itself and if nothing is found, it resolves it against its content, i.e the object if you already manually set it to the controller's content.
Finally, there is no default implementation of the model() function in the Route except when you're using dynamic urls, say /foo/id that resolves against /foo/:id, Ember uses the id provided to load a Foo object with the id provided, thus providing a default implementation to the model() function. At the end it boils down to the same mechanism, only automated for your convenience.
I suggest you listen to this for more insights on how things are automated for you by Ember. But when it comes to the content being displayed, there is no magic you have to manually wire the content of the controller.