TL;DR
Here are some handy globals you can use in your Ember.js app to debug faster, even without ember inspector
If you would like to use the addon version:
You can also find it as gist
In this blog post you will learn how to add some nice globals to help you while developing your Ember.js app.
One of the things that makes Ember.js ecosystem a breeze is the Ember Inspector. Quite often as Ember.js devs we use it to grab the current controller, a service, the route current model or a component to debug it, even while writing this post I learned a few new things about the inspector, I've never used the Promises tab before 🤒, I love it!
But from time to time quick fixes and checks starts to feel a little bit annoying. Specially in long debugging sessions and of course if you like autosaving files in VSCode, like I do.
Also from time to time you need a few ember objects in the console to debug correctly, or build up some complex object, so having the $E
reserved for a particular inspector object is not necessarily enough.
Another good reason to do so, is that sometimes you are testing your app in a browser that doesn't have ember-inspector available or installed, so this gives you a set of tools to handle this!
Here is an excellent Intro To Ember Inspector if you are not familiar 😄
Off we go, Global instance-initializer
One of the files I keep bringing from project to project, is the so called instance-initializer/globals.js
ember generate instance-initializer globals
Here I quote the Ember.js Application and Instances
Every Ember application is represented by a class that extends Application. This class is used to declare and configure the many objects that make up your app.
As your application boots, it creates an ApplicationInstance that is used to manage its stateful aspects. This instance acts as the "owner" of objects instantiated for your app.
Essentially, the Application defines your application while the ApplicationInstance manages its state.
So in this instance-initializer, we receive the application instance, which I use to create or derivate globals that keeps me productive.
//instance-initializer/globals.js
export function initialize(application) {}
export default {
name: "globals",
initialize,
};
First we might want to ensure we only add these while on development
//instance-initializer/globals.js
export function initialize(application) {
let { environment } = application.resolveRegistration('config:environment')
if ( environment !== 'production') {
}
}
export default {
name: "globals",
initialize,
};
Basic useful globals
//instance-initializer/globals.js
export function initialize(application) {
let { environment } = application.resolveRegistration('config:environment')
if ( environment !== 'production') {
/**
This basically exposes the application, pretty useful because
you can use stuff like this from the console.
App.lookup('route:some-route').actions.doSomething();
*/
window.App = application;
/*
This will gives us access to the store easily, to make fast queries or checks!
Fast and easy:
var s = App.store.peekRecord('some-model', 1);
App.store.createRecord('some-model', {name: 'Alberto'})
*/
window.App.store = application.__container__.lookup("service:store");
}
}
export default {
name: "globals",
initialize,
};
After using App.lookup() directly for some time, I found too time consuming to time the type of object I was looking for
App.lookup("service:some-service");
App.lookup("route:some-route");
So I started to add a function shorcuts.
//instance-initializer/globals.js
export function initialize(application) {
let { environment } = application.resolveRegistration('config:environment')
if ( environment !== 'production') {
...//to avoid making this too long
window.App.service = function(name) {
return application.lookup(`service:${name}`)
}
// or a shortcut for every ember types.
let objects = [
'service',
'controller',
'route',
'model'
];
objects.forEach(type => {
window.App[type] = function(name) {
return application.lookup(`${type}:${name}`)
}
})
}
}
export default {
name: 'globals',
initialize
}
While it's almost the same typing, first its truly easier to type, but also, the chrome console autocompletes, so a win.
App.controller("auth.projects");
App.model("some-model");
App.route("auth.projects");
And the most recent addition who actually made me write this blogpost, my ultimate gift 😅.
//instance-initializer/globals.js
export function initialize(application) {
let { environment } = application.resolveRegistration('config:environment')
if ( environment !== 'production') {
class CurrentContext {
get model() {
return application.lookup(
`controller:${application.lookup("service:router").currentRouteName}`
).model;
}
get controller() {
return application.lookup(
`controller:${application.lookup("service:router").currentRouteName}`
);
}
get route() {
return application.lookup(
`route:${application.lookup("service:router").currentRouteName}`
);
}
}
window.App.ctx = new CurrentContext();
}
}
export default {
name: "globals",
initialize,
};
We create this CurrentContext
class just to have native getters, to avoid having to call methods. It uses the currentRouteName
from Service Router
to get the current model, route or controller, so this is effectively a super shortcut for quick debugging stuff!
var model = App.ctx.model; //current route model!
var controller = App.ctx.controller; //current route controller!
var route = App.ctx.route; //current route route!
What do you think about these shortcuts? Do you plan to use some of them? do you have any secret one you would like to share to the #emberjs community? Please do!
If you would like to use the addon version:
You can also find it as gist