Ember, inject a service application wide - ember.js

I know this question is already posted but i don't find any updated or well explained response.
So i have a service "session" & "current-user" who have my session & current user (obvious) in memory and i need to have this service in every controllers, actually, in every controller i do
session: service(),
currentUser: service('current-user'),
My question is, how to make those services available in all controller without redeclare them in every controllers ?
Thank you.

Okay i had to post a question to finally find a response ...
So i used initializers, let's do it for my current-user service.
ember g initializer current-user
It create a new file in app/initializers/current-user.js and i put this into it
export function initialize(application) {
application.inject('route', 'currentUser', 'service:current-user');
application.inject('controller', 'currentUser', 'service:current-user');
application.inject('component', 'currentUser', 'service:current-user');
}
export default {
name: 'current-user',
initialize
};
In this code exemple, i inject the current-user service (thrid argument) inside routes, controllers & components (first argument) and it'll be named currentUser (second argument).
I hope it will help other ppl :)

Related

How to use adapter in an ember-engines

as the title says, I have some problems understanding how to use an adapter in an ember-engines.
I am currently running my application with ember#2.15, ember-data#2.15 and ember-engines#0.5.14.
I already used an adapter in my main application, but if I tried to reproduce a basic adapter in my application, the page is loading indefinitely.
In my route, I call my adapter with the findAll method:
model()
{
"use strict";
console.log('In my route');
return this.get('store').findAll('my-adapter-name', {reload: true});
}
And in my adapter, I respect the syntax that I used in my in-app adapter:
import DS from 'ember-data';
import Ember from 'ember';
export default DS.Adapter.extend({
findAll: function (store, type, sinceToken, snapshotRecordArray)
{
console.log("In my adapter");
return new Ember.RSVP.Promise(function (resolve, reject)
{
// I accede to my websocket service here, nothing to do with my question
});
},
/* *
* My other function, like findRecord, ect...
*/
});
As you can see, I put some console.log in my code, and I can access the message in my route, which is in my engine, but I can't access the message in my adapter, which is also in my engine.
I tried to put a console.log in an adapter in my application, and the message is properly shown, so I am sure this is because I can't access to the adapter in my engine, so if anybody has an idea to how we should configure our adapter in our ember-engines, this would be very appreciated.
For your information, this is an in-repo engines.
Just found it, this is a bit tricky, but your models (and adapters) should be in the myApp/lib/myEngine/app/models/, and not in myApp/lib/myEngine/addon/models.
I don't know if this is intended this way, but this is the only way I found to add model in your in-repo ember-engines.
EDIT
This will do the trick for the serializers and the transform.

Possible to make a route transition inside of a service in Ember?

I'm using ember-cli 1.13.8 and I have a service that handles most of my logic. Right now I have a function that listens to whether certain things are true or false and then can make a route change based upon that. I'd rather not have to call that function from inside every route since I want it to happen on every route. Its goal is to determine whether the player won and every interaction in the game drives this.
Inside of my game service:
init() {
...
if(true) {
console.log("you've won!");
this.transitionTo("congratulations");
}
},
Of course, this fails because this isn't a route like Ember expects. I know I can call this method from inside of every route instead but I'm wondering if there is a better way to do this.
Thanks
Edit
So far I've tried importing in the App and then trying to extend the Router. This seems like a bad idea though.
You can use the routing service (which is a private API):
routing: Ember.inject.service('-routing'),
init() {
...
if(true) {
console.log("you've won!");
this.get("routing").transitionTo("congratulations");
}
},
As of Ember 2.15, there is a public router service for exactly this use case. Just add router: Ember.inject.service(), to your Ember class and call this.get('router').transitionTo(...);, easy!
Generally this is a bad idea, but in some cases it's easier than passing through route actions in 100 places (personal experience).
The better way to do this from anywhere is to look the router up on the container:
Ember.getOwner(this).lookup('router:main').transitionTo(...);
this has to be some container allocated Ember object, which includes components, services, and Ember Data models.
Note also that if this will be called a lot, you will want to store the router as a property. You can do this in the init hook:
init() {
this._super(...arguments);
this.set('router', Ember.getOwner(this).lookup('router:main'));
}
...
this.get('router').transitionTo(...);
Ember.getOwner(this) works in Ember 2.3+, prior to that you can use this.get('container') instead.
Ember 1.13:
Create another service called routing:
import Ember from 'ember';
export default Ember.Service.extend({
_router: null,
init() {
this._super();
this.set('_router', this.get('container').lookup('router:main'));
},
transitionTo() {
this.get('_router').transitionTo(...arguments);
}
});
Then you can:
routing: Ember.inject.service(),
goSomewhere() {
this.get('routing').transitionTo('index');
}

Accessing Ember Controller Properties within the same controller

I'm very new to EmberJS 2.0 and trying to slowly understand it by building my own website with it. Anyways, I've managed to get Firebase integrated with Ember and my controller is able to authenticate correctly. However, I'd like to understand why when I execute:
this.send('toggleModal');
inside the authenticate action property function (.then()) it doesn't work but if I execute it outside then everything works fine.
1) Is the 'this' keyword getting confused with something other than the Ember controller?
Here is the sample:
// /app/controllers/application.js
import Ember from 'ember';
export default Ember.Controller.extend({
isShowingModal: false,
actions: {
toggleModal: function() {
this.toggleProperty('isShowingModal');
},
authenticate: function(username, pass) {
this.get('session').open('firebase', {
provider: "password",
email: username,
password: pass
}).then(function (data) {
console.log(data.currentUser);
console.log(session.isAuthenticated); //Why is 'session' not defined?
this.send('toggleModal'); //This doesn't work. Throws an error.
});
this.send('toggleModal'); //This works.
},
logOut: function() {
this.get('session').close();
}
}
});
2) Also, I've noticed that when using Emberfire I'm able to use the property 'session.isAuthenticated' within the template application.hbs however, shouldn't 'session' be an object that is injected to all routes and controllers using Torii? Why is that property inaccessible/undefined within the application.js controller? I'm using https://www.firebase.com/docs/web/libraries/ember/guide.html#section-authentication as a reference.
3) In the guide above the actions for authentication are put inside the route. However, according to this quora post the route should only handle template rendering and model interfacing. Is this post incorrect? The authentication logic should reside in the application.js controller correct? https://www.quora.com/What-is-the-best-way-to-learn-Ember-js
1) Is the 'this' keyword getting confused with something other than the Ember controller?
Yes. This is one of the most common sticking points of Javascript. There's a lot of articles out there about it, but this one looked pretty good. To solve it you'll either need to use an arrow function, bind the function to the current context, or save the context in a local variable. (Read that article first though.)
2) Also, I've noticed that when using Emberfire I'm able to use the property 'session.isAuthenticated' within the template application.hbs however, shouldn't 'session' be an object that is injected to all routes and controllers using Torii? Why is that property inaccessible/undefined within the application.js controller? ...
That's because the template pulls the property from the current context (your controller). Inside of your controller you'll have to use this.get('session') instead. (After you fix the issue I mentioned above.)
3) ... Is this post incorrect? ...
I wouldn't say incorrect, just a bit oversimplified. I would follow whatever conventions the library uses as that's probably the best way given the library's requirements.
You're partially right about this although it's not really confused. this (where you're modal call doesn't work) isn't scoped to the Controller anymore, because it's inside a function. Either:
replace the function (data) call with data => if you're using ember cli. Or
var _self = this; up top and reference _self instead.
This should at least get you started.

How to get access to global variable in template?

I want to create global object with settings which I need to get from REST API. I need to make one request to REST API and get settings and after that I want to get access to these settings from any controllers and from any templates. What can you advice, what is the best practice for that problem?
Concept
Good practice would be to use initializers. They allow injection of any data to routes, controllers or any other kind of object.
Lets take an example ( example from Ember.js official site )
1 . You have an Application and you have a logger service like this -
App = Ember.Application.extend();
App.Logger = Ember.Object.extend({
log: function(m) {
console.log(m);
}
});
2 . Now you want to have this function log to available on all routes like this -
App.IndexRoute = Ember.Route.extend({
activate: function(){
// The logger property is injected into all routes
this.logger.log('Entered the index route!');
}
});
3. Tell ember to inject an object named Logger to all routes. Use initializer Like this
//I want to inject something
Ember.Application.initializer({
//this dependency name is logger
name: 'logger',
//whenever ember runs
initialize: function(container, application) {
//register my logger object under a name
application.register('logger:main', App.Logger);
//and use this service 'logger' in all 'routes'
application.inject('route', 'logger', 'logger:main');
}
});
With this you can have your application level data / code available in all routes and controller.
Once you get your data in controller you can use it in templates pretty easily.
How to make API call with initializers ??
Initializer can be used to run after some other services has been resolved. Like in our case store. store is the object we need to make API call to server in good way (We can use $.getJSON() or anything else no issues)
Tell the initializers to run after store loaded
//I want to inject something but only after store resolved
Ember.Application.initializer({
//this dependency name is logger
name: 'logger',
//wait for store object to be loaded, we need it to make API call
after : 'store',
//whenever ember runs
initialize: function(container, application) {
//grab the store object from container
var store = container.lookup('store:main');
//now you the store make that API call
self.store.find('user',{current:true}).then(function(data){
//we have the data we can inject it
data = data.get('firstObject');
container.lookup('controller:base').set('user', data);
//user lookup success
console.log("We have found an user. Yeah ember rocks.");
});
}
});
The settings object you are describing should probably live inside ApplicationRoute's model hook. You can then retrieve it in all your other models by saying modelFor('application') (see here). There is also a needs API (see here) that lets you share stuff between controllers in the application.

How and when to use Ember.Application register and inject methods?

I'm trying to understand how to use Ember.Application register & inject methods
What use case are these functions designed for?
How are they to be used and when?
I'd really like to know!
Ember by default does dependency injection when it boots your application using mostly conventions, for example if you use ember-data then an instance of the store class is injected in every route and controller in your application, so you can later get a reference by simply doing this.get('store') inside any route or controller.
For example here is a code extract where the default store get's registered (taken from the source)
Ember.onLoad('Ember.Application', function(Application) {
Application.initializer({
name: "store",
initialize: function(container, application) {
application.register('store:main', application.Store);
...
}
container.lookup('store:main');
}
});
And then injected (source)
Application.initializer({
name: "injectStore",
initialize: function(container, application) {
application.inject('controller', 'store', 'store:main');
application.inject('route', 'store', 'store:main');
application.inject('dataAdapter', 'store', 'store:main');
}
...
});
In other words register and inject are methods to register dependencies and inject them yourself.
Let's assume you have a Session object which you populate after a server request on application start, and which you want to have a reference to in every controller, you could do something like this:
var App = Ember.Application.create({
ready: function(){
this.register('session:current', App.Session, {singleton: true});
this.inject('controller', 'session', 'session:current');
}
});
App.Session = Ember.Object.extend({
sessionHash: ''
});
This code would set the session property of every controller instance to a singleton instance of App.Session, so you could in any controller do this.get('session') and get a reference to it, and since it's defined as a singleton it would be always the same session object.
With register you can register controllers, models, views, or any arbitrary object type. inject, in the other hand, can inject onto all instances of a given class. For example inject('model', 'session', 'session:current') would also inject the session property with the session:current instance into all models. To inject the session object, let's say onto the IndexView you could do inject('view:index', 'session', 'session:current').
Although register and inject are very powerful you should use them wisely and only in the case you really know there is no other way to achieve your goal, I guess the lack of documentation is an indicator for discouragement.
Update - No good explanation without a working example
Since It's mostly a must to provide a working example with an explanation, there it goes: http://jsbin.com/usaluc/6/edit. Notice how in the example we can simply access the mentioned sessionHash by referring to the current controller's session object with {{controller.session.sessionHash}} in every route we are in, this is the merit of what we have done by registering and injecting the App.Session object in every controller in the application.
Hope it helps.
A common use case is to provide the current loggedin user property to controllers and routes as in https://github.com/kelonye/ember-user/blob/master/lib/index.js and https://github.com/kelonye/ember-user/blob/master/test/index.js