Lazy loading belongsTo - ember.js

I have a child and a parent model that are linked via DS.belongsTo. In my child/index template I link to the parent:
{{linkTo "parent" parent}} go to parent {{/linkTo}}
Now here's my issue: Ember Data sideloads all of the parent models (even though I specified async: true in the belongsTo relationship) one by one. This seems to be caused by linkTo because when I remove that line this behavior stops.
How do I prevent ED beta 3 from doing this? The use case is that my child model is a partial model of the parent so this behavior defeats the point of my setup (and seems unnecessary).

While #kinpin2k's answer would work, I found a better one: I just discovered that {{link-to}} accepts ids as arguments, too.
In my case I changed parent: DS.belongsTo('parent') to parent_id: DS.attr('string'). There was no need to change any of my back end since that's how Active Model Serializer returns it anyways. I then change my template to:
{{link-to "parent" parent_id}} go to parent {{/link-to}}
and everything works nicely because (as #kingpin2k nicely explained) Ember does not access the parent model anymore.
EDIT: Updated to reflect new syntax: {{linkTo}} is now {{link-to}}

It's isn't Ember Data, it's Ember accessing the model. Async means don't load it until someone tries to access it, using it in a link-to is considered using it.
You could add it to an action, and then transition to the route instead of using the link0to

Related

What is the best way for all instances of an Ember component to share a variable?

I have an Ember component which is essentially a panel. There can be multiple instances of this panel on a page, but only one can be "active" at any given time. Each instance of the component must be aware if any of the other panels become "active" so they can remove their "active" state. I would really rather not move the JavaScript to make this happen to a parent component. Instead, I would like to keep it within this component. In Angular, I used to use a static variable to do this. What is best way to do this in Ember?
I would really rather not move the JavaScript to make this happen to a
parent component
Do you want to avoid having the parent component dealing with anything related to panel "activity"? If so, why?* If not:
Ember automatically gives each component's tag (unless it's a tagless component) an id that is accessible from the js code as elementId. You could create a property activePanelId on the parent component and pass it to all panels: {{pa-nel activePanelId=activePanelId}} and then check in each panel
{{#if (eq elementId activePanelId)}}
{{!whatever is different on the active panel}}
{{/if}}
or use it in the js code:
isActive: Ember.computed('activePanelId', function() {
return this.get('activePanelId')===this.get('elementId');
},
If the panel becomes active by an action related to itself (e.g. clicking on it), just set activePanelId to the elementId in the respective action - since the property activePanelId exists only once on the parent component, all other panels to which it is passed will take note.
If using the elementId feels to hacky, you might as well give each panel a distinct name and store the activePanelName in the calling component.
*If you really do not want the property in the parent component, you could move it to a service that you then inject into the panel components, but I cannot yet imagine a good reason for preferring that.
#arne.b 's anwser sums it pretty well, the best way of handling component's state with common parent data, but if you are dead serious about not using a parent component there is kind of way to get it done.
Example:
import Ember from 'ember';
export default Ember.Component.extend({
sharedObject: {},
sharedArray: [],
});
In the above component you can use sharedObject or sharedArray to exchange state with multiple instances of the component. Any changes in the object or array will be reflected to all the instances of the same component.
A sample Ember twiddle.

Is there a way to have an Ember link-to helper fire on keyPress?

I am in the process of getting our product to WCAG 2.0. I know with actions I can specify that it fire on="keyPress". Before I start replacing all of our link-to's with actions, is there support for specifying link-to events? I haven't happened across anything hinting at it in the docs.
Edit: The link-to's I'm having issues with have a tagName that is different from an anchor.
Consider passing eventName property to link-to component.
{{#link-to 'users' eventName='mouseEnter'}} Users {{/link-to}}
This will transitionTo users route when mouse over the link-to element.
Note: I am not sure how do you use keyPress event for link-to component
I'm reworking my markup so that the link-to's to use their default tagName (a), which solves my problem. This isn't the accepted answer as the issue still remains that when you use a tagName that is different than the default, there doesn't appear to be a way to transition on key events. My primary use case is working with link-to's as table rows.

Ember observer fires on array controller when it shouldn't

Update
Here's a bin of my problem: http://emberjs.jsbin.com/ruwet/8/edit?html,js,console,output4
I have a simple filtered property on an array controller:
import Ember from 'ember';
export default Ember.ArrayController.extend({
activeEncodes: function() {
return this.filterBy('model', 'isActive');
}.property('model.#each.isActive');
});
I'm connected to a websocket and am updating encodes in my store with
store.store.push('encode', data);
Even though it's just updating a certain property on my data (progress), activeEncodes is being recalculated. This is causing some visual jank in my templates.
If I use model.#each.id, it doesn't recalculate, but any other property seems to trigger the CP to recalculate (even if that property is not changing).
Any idea why this is happening?
When you push it causes the entire model to invalidate. This is then considered a new model which fires any observers watching anything on that model (since it sees it as a new model). It's tangentially related to Ember data model reload causes item in {{each}} to be removed/inserted back - losing current state as well.
id is likely a special case, I believe it lives outside of the scope of the underlying properties on the model (same reason you don't define the id on the model). I'm just guessing on that though.

Ember ArrayController cannot be sorted by property defined in itemController

I want to sort an ArrayController by a property defined/computed in the itemController. See this JSBin. If you sort by firstName (defined in the model), it works fine, but if you sort by lastName (defined in the itemController), it doesn't work. Make sure to play with sortAscending: true or false. Any idea how to make this work?
Here is another simpler JSBin that exhibits the same behavior (the first JSBin is closer to my actual code).
The sortable mixin is applied on the content, not on the controllers of the content.
Code: https://github.com/emberjs/ember.js/blob/v1.1.2/packages/ember-runtime/lib/mixins/sortable.js#L72
You'll probably want to add whatever logic you're adding on the controllers to the models.
The particular use case that you mentioned before was best suited on the model. Really the place where you draw the line on controller and model is wishy washy. If the property needs to persist across controllers then you should add it to the model, especially if the controller isn't a singleton controller. If it's a singleton controller and the model never changes underneath it, then the property can live on the controller.
It's important to note that defining a property on the model doesn't mean you have to get it from the server, nor save it to the server.
App.User = DS.Model.extend({
name : DS.attr(), // this will be saved to the server
something: 31 // this isn't a DS attr, it isn't going anywhere
});
As a note, I lied earlier about something.
You can talk to your child controllers from your parent controller.
From inside of the parent controller, you can access the child controllers using objectAt and iterating over the parent controller.
In this example this is the parent controller
console.log(this.objectAt(0));
this.forEach(function(itemController){
console.log(itemController);
});
http://emberjs.jsbin.com/AQijaGI/1/edit

How to link to nested resources in Ember.js?

Assume you have the following routes in an Ember application.
App.Router.map(function() {
this.resource('series', function() {
this.resource('serie', { path: '/:serie_id' }, function() {
this.resource('seasons', function() {
this.resource('season', { path: '/:season_id' }, function() {
this.resource('episodes', function() {
this.resource('episode', { path: '/:episode_id' });
})
});
});
});
});
});
How would I link to a specific episode using the linkTo helper that Handlebars provides? In other words, how does Ember figure out what the other parameters of the URL should be, that is, the serie_id and episode_id? The documentation states that I should pass an episode model to the episode route as shown below.
{{#linkTo "episode" episode}}
This is to link to the following URL structure.
/series/:serie_id/seasons/:season_id/episodes/:episode_id/
When I use the linkTo helper like that, Ember throws an error telling me that it cannot call get with id on undefined. I assume that it uses the episode model to figure out what the serie_id and episode_id are and my guess is that the model needs to conform to a specific convention (structure or blueprint) for Ember to find these ids.
These are the aspects that I find most difficult about Ember. It isn't very transparent even if you use Ember in debug mode. Any pointers or references are much appreciated.
UPDATE 1: After some digging, I found out that the route's serialize method is a key element in accomplishing this. However, when I use the linkTo helper as illustrated above, the model passed to the route's serialize method is undefined for some reason (even though it is not when passed to the linkTo helper. The question that led to this discovery can be found here.
UPDATE 2: It turns out that the serieSeason route's serialize method receives the wrong model, an episode instead of a season, when the link is generated. It isn't clear, though, why it is receiving the wrong model. Where does the model parameter of the serialize method come from?
UPDATE 3: The linkTo helper works fine if I return static data from the serialize method of each route involved, which means that the linkTo helper isn't involved in the problem.
It turns out that the answer could be found in the properly documented source of Ember ... because that is what one does after searching the web for several days.
The answer is simple. The linkTo helper accepts more than one model. For each dynamic segment of the destination URL, you pass a corresponding model. Each passed model will become the model of the corresponding route in the destination URL. In the example that I describe above, this results in the following.
{{#linkTo "episode" serie season episode}}
The serie model will be passed to the serie route, the season model to the season route, and the episode model to the episode route. What confuses many developers is that the route's model hook isn't triggered when you use the linkTo helper. This isn't too surprising if you realize that the developer provides (or can provide) the model for the corresponding route by passing one or more models (or zero).
Because there isn't much documentation for deeply nested resources, it wasn't trivial to find out how the linkTo helper does its job under the hood. Diving in Ember's source definitely helps getting up to speed with the framework.