According to http://emberjs.com/guides/object-model/classes-and-instances/ it is required to access properties using getters and setters:
When accessing the properties of an object, use the get and set accessor methods.
Make sure to use these accessor methods; otherwise, computed properties won't recalculate, observers won't fire, and templates won't update.
I understand that it is needed to use setters when changing property to let Ember know about the change so it can update bindings, but what about reading properties?
Example from http://emberjs.com/guides/object-model/classes-and-instances/
App.Person = Ember.Object.extend({
say: function(thing) {
var name = this.get('name');
alert(name + " says: " + thing);
}
});
var yehuda = App.Person.create({
name: "Yehuda Katz"
});
yehuda.say("Yes");
In the example above, this.get('name') is used to access property name, however method say is defined as a property of class App.Person and is accessed directly by dot notation. While there is a distinctive usage difference between method and property, in JavaScript, there's no difference in implementation of both. The example still works if I replace this.get('name') by this.name.
Are there any implementation differences in Ember regarding methods and properties of object?
Is it always safe to access methods directly?
Must all properties including computed properties be always accessed by getter? If not, when is it safe to access properties directly?
I definitely want to stick to best practise here, which is to use getter/setter every time, but I'd like to understand the internals of Ember.js :)
The definition of a method or a property in Ember is the same as in Vanilla JavaScript, but they are resolved different in Ember. You are not working with POJOs. Every time you extend from a Route/Controller/View, you are adding the Ember layer that processes methods and properties differently.
No, is not always safe. In your case it is because it is overly simple.
Yes, always access properties with get.
User interaction with your app is what causes changes in the properties of your objects, we handle those interactions with events. When an event in Ember is fired, it is not resolved immediately, instead it is put in a priority queue and resolved at a later time.
Properties are updated and read in an asynchronous form, if you access them directly using this there is no guarantee that you'll get the most up to date value.
Check: Managing Asynchrony
When you make a change to a property in Ember, it does not immediately propagate that change. Instead, it invalidates any dependent properties immediately, but queues the actual change to happen later.
So, when you change the value of a property, this is roughly what happens:
A property is changed
All dependent properties are invalidated
Queues the actual change for later
Wait for any other event handlers, for the current user, to finish
Flush the changes queue
Until here, the property is actually updated (and this would work as usual)
Imagine you use this to read a property, but some other event occurs that changes its value. The new value won't be available until the queue is flushed, but this reads immediately the property and returns the value of a property that is scheduled to be updated soon. You get stale data. The methods get and set manage this asynchrony for you and guarantee fresh values always.
When you have only one property, in the whole app, this asynchronous mechanism won't be noticed.
There are many different queues in Ember, and the fundamental mechanism behind all this is the run loop.
Related
I am having a problem with route-level actions that occur asynchronously occasionally not getting handled.
In my Ember app I sometimes receive the error:
Nothing handled the action 'X'. If you did handle the action, this error
can be caused by returning true from an action handler in a controller,
causing the action to bubble.
Where X is the name of some action. The problem is not that the action is bubbling or that the handler is not defined, because it works almost all the time.
The problem, rather, relates to to fact the this.send('X') is called in a promise callback, e.g., after saving a model:
model.save().then(() => {
this.send('X');
});
If the save encounters some network congestion or a delay on my server then the user might have navigated to another route by the time the promise is resolved. And that route might not have an action X defined (or worse perhaps it's the wrong action of the same name).
Is using actions here a fundamental design flaw?
If so, this would seem to severely limit the utility of actions, because they couldn't be used in any asynchronous context.
Or is there some way that transitions out of a route can delayed until any pending async stuff is resolved? (though this might create it's own undesirable symptoms)
IMHO there is not a design flaw in the case you have described. This is the nature of the promises. The same thing can happen within components and there might occur some errors related with trying to set properties on destroyed Ember components. There is a great addon I use to handle such cases: Ember Concurrency
If you take a look at this addon; you will see that there are similar cases explained, which are very similar to the one you have described. I would suggest benefiting from a popular, already heavily used library like this one instead of trying to tackle it by your own. My best regards.
For the simplicity of coding, I would suggest to move such actions to Application Controller and inject it wherever needed.
Application Controller can be injected as
import Ember from 'ember';
export default Ember.Controller.extend({
appController: Ember.inject.controller('application')
});
To use it in Template:
<button {{action 'X' target=appController}}> Login </button>
To invoke it from your code
this.get('appController').send('X');
You can also use Service to achieve this.
You can use isDestroyed guard check before calling send. But I would encourage you to use ember-concurrency addon for this use case. If you can go through How to do you check for isDestroyed? discussion forum, you will get the idea.
I have an audio-player Ember.js component which I'd like to send events to from anywhere:
this.get('audioPlayer').send('play');
To get access to the component, I set the component as a property on itself which exposes it to the controller (link).
Working example Ember 1.12: http://emberjs.jsbin.com/wokelikice/1/edit
Failing example Ember 1.13: http://jsbin.com/yaporapuwu/2/edit
This stopped working in Ember 1.13-beta and I thought I must be doing it wrong. Data down, actions up and all.
How would you architect an application with a global audio-player?
And how would you send actions on a component? (or is there a better way?)
I managed to get it working in 1.13 like so: http://jsbin.com/serunaxozi/1/edit
The only change is modifying the _register method as follows:
_register: function() {
this.get('attrs.register-as.update')(this);
}.on('init')
1.13 is making changes to the way components reference attributes. Attributes on the components are accessed through the attrs object to differentiate them from component variables. They also have value and update properties to make due for implicit one-way binding with two-way binding via the mut keyword.
Remember this is still work-in-progress, so right now we need to manually get the update method from the attribute and invoke it, but I'd imagine in future this will be done using a setter as follows:
this.set('attrs.register-as', this);
Also bear in mind that eventually components will be used with angle-brackets, and you would need to specifically say that an attribute is a two-way binding for Ember to generate that update method:
<audio-player title="Michael Jackson" test={{test}} register-as={{mut audioPlayer}} />
This is still a little buggy at the moment (using the angle-bracket syntax, attrs is not available in the method which is run with on('init')).
-- Edit--
Attributes will not be available inside init in the future and will instead have another hook didInitAttrs. See https://github.com/emberjs/ember.js/issues/11200.
I'm experiencing an issue with Glass Mapper in my current project that I haven't encountered before.
Directly after Sitecore has been initialized, the Database property in my GlassContext (ISitecoreContext) is null.
// After Sitecore initialization, sometimes the glass context database is not initialized yet.
if (this.glassContext == null || this.glassContext.Database == null)
{
this.glassContext = DependencyInjection.Container.Resolve<ISitecoreContext>();
// Now I have a valid this.glassContext.Database ...
}
When I ask my DI framework (Windsor, so Glass' default) for an instance, it returns me one with a valid Database property.
For the time-being I'm doing this check before retrieving any items and it only needs this check one time (after that it's good until the next initialization), but would really like to know what is causing this.
Probably interesting to know: all item requests (getting items, casting items, etc.) are done through one service which gets the ISitecoreContext initialized in its constructor.
The ItemService has lifestyle Singleton, the ISitecoreContext has lifestyle Transient
I think that your NewsService was first time injected before Sitecore has a valid context, therefor Glass also cannot be have a valid context (database). Because your ItemService has a Singleton lifetime, the constructor is only called once and also the resolving of ISitecoreContext is done once. This means, if your ItemService is resolved the first time before Sitecore has a valid context, then your glassContext will be null. After you manually set the glassContext property in the Singleton instance, the next time it won't be null (but maybe not valid because you are in another request).
I would suggest you setting both dependencies either to Transient or to PerWebRequest.
As stated in other comments, sometimes this is due to not specifying an appropriate lifestyle. Transient may give you memory leaks if you do not find an appropriate way to Release it. I personally often use the NoTrackLifestyle that ships with Glass Mapper, since it behaves more like Transient from other containers.
There are also occasions where you can attempt to resolve the service too early, this in particular can happen when running in pipeline entries etc where the context has not yet been resolved for the request. In these instances you can use either a named instance where you specify the database and / or it's name as a dependency.
Bear in mind in all cases, the sitecore context / service by default relies on the CONTEXT database, if Sitecore hasn't resolved it yet - neither will glass have.
When using it with the new Glass Delegate functionality, I have found it necessary sometimes to rely on a factory implementation that delays the getting of the service, it's not perfect, but serves it's purpose since the fluent configuration often won't have a context available at the time of instantiation. By adding a small factory, it can be delayed until the delegate code is actually called.
public interface ISitecoreServiceFactory
{
// Gets the Sitecore service from the container
ISitecoreService GetService();
}
There are also instances sometimes with this when Glass is used in the creation of SPEAK / Sheer UI dialogs.
I am learning Ember.js and going through some of the guides. I was reading about observers here:
http://emberjs.com/guides/object-model/observers/
I wanted to play around with the example so I copied and pasted it into my js file. After adding an alert statement to the observer callback, I was surprised to find it was not invoked.
http://jsbin.com/UWEseSo/2/edit?js,output
I was able to find that if you add:
person.get('fullName');
Before the call to set the firstName, the observer callback will be invoked. If I set the first name again immediately after the callback would again not be invoked.
Can anyone explain what is going on here?
Thank you.
EDIT-------
I've traced through the code a little more and I now I have an idea on why this behavior may be like this. Although the example seems like there is a bug it may just be an optimization. I observed earlier that if I called "get" the observer would work. If I did not call "get" the observer would not work. I believe Ember.js may just being smart about this and intentionally not bothering to invoke the observer if no "get" was called. They may be doing this because if there was no "get" there is no reason to invoke the observer because the application can not possibly be showing out of date information.
Once "get" is called an internal flag is set to ensure the observer will be invoked on the next "set".
It looks like you got the explanation right for this behaviour all by yourself, and to confirm your assumptions there is indeed a change that was introduced in rc8 for performance reason mainly.
You can read here the full article on that, under UNCONSUMED COMPUTED PROPERTIES DO NOT TRIGGER OBSERVERS
This means basically that if you need to observe a computed property but aren't currently retrieving it, just get it in your init method.
Hope it helps.
I'm used to thinking about a single-page application startup happening like this: 1. Bootstrap some data into critical models, 2. Instantiate a master controller, and 3. Call it's render() method to kick things off.
How is this accomplished with Ember? Following the (meager, sigh) examples in the documentation, it seems like things sort of kick off on their own when the page loads -- templates are compiled, views render like magic when the page loads. I feel like I am missing something fundamental. It there an example online of a more complex app, say something with tabbed or dynamically loaded views?
Lightbulb, going off it is not.
I've started a blog series about getting up and running with Ember on Rails. Here's Part 1:
http://www.cerebris.com/blog/2012/01/24/beginning-ember-js-on-rails-part-1/
I hope you'll find it useful, even if you're not planning to use Ember with Rails. Most of the interesting details are client-side and thus server-independent. The posts so far cover creating an Ember.Application object, loading data dynamically through a REST interface, and then rendering an Ember view on a page in handlebars. I hope it's enough to get you started.
When you extend an ember Application object you can provide a ready function which will be called when the application starts. You have to make sure to call this._super() or else it will break your application. Check out my sample sproucore 2.0 application (ember is the new name of sproutcore 2.0).
The way that ember works is that it sets up a run loop which responds to events. Whenever an event fires, the run loop basically calls the necessary handlers and runs any bindings that need to be updated. Since everything typically happens in the run loop you often don't really write any code to update things. Instead you write bindings which are fired when needed.
Another thing I've done is use an Em.StateManager to bootstrap.
App.Loader = Em.StateManager.create({
start: Em.State.create({
enter: function(mgmt, ctx) {
// this code will execute right away, automatically
}
})
});
Since you use create instead of extend, the object will be instantiated immediately. If you define a state called start, it will be recognized as the default initial state (or you can specify another one by name). So the new StateManager object will immediately enter the initial state, and when the StateManager enters a new state, it will always look for a method of that state called enter and fire it if present.
A state manager is the natural place to initialize your app because the object provides ways for you to micromanage execution order during an async loading process without entangling yourself in too many callbacks.