Accessing an injected object from inside of a class in EmberJS - ember.js

I want to re-open a class and define a new 'class' function. Inside this new function, I want to have access to an injected property. Is there a way to do this?
Injecting dependency
export default {
name: 'userManager',
initialize: function(container, application){
var userManager = Ember.Object.extend({
//Some stuff
});
application.register('manager:user', userManager);
application.inject('route', 'userManager', 'manager:user');
application.inject('model', 'userManager', 'manager:user');
application.inject('controller', 'userManager', 'manager:user');
}
};
Re-opening a class to add a class method
import Ember from 'ember';
var Person = Ember.Object.extend({});
Person.reopenClass({
//how do I access an injected object here?
})
export default Invoice;

Whats wrong with?
Person.reopenClass({
someMethod: function() {
var userManager = this.get('userManager');
}
})

Related

How to use mixin inside custom helper?

I have defined some helper functions inside a mixin; however, I am not sure how to uses these functions inside a custom helper.
I have referred to question below but seems ember no longer have Mixin.apply method.
Accessing an Ember.Mixin within a custom handlebars helper
If you got class based helper, then you can use Mixin as usual.
export default Ember.Helper.extend(YourMixinName,{
session: Ember.inject.service(),
onNewUser: Ember.observer('session.currentUser', function() {
this.recompute();
}),
compute() {
return this.get('session.currentUser.email');
}
});
The default helper cannot use mixin because it is stateless.
However, if you need a helper that interacts with your application. You can do so by making a class-based helper.
https://guides.emberjs.com/v2.11.0/templates/writing-helpers/#toc_class-based-helpers
Code snippet below is a class-based helper,
import Ember from 'ember';
export default Ember.Helper.extend({
compute([value, ...rest], hash) {
let dollars = Math.floor(value / 100);
let cents = value % 100;
let sign = hash.sign === undefined ? '$' : hash.sign;
if (cents.toString().length === 1) { cents = '0' + cents; }
return `${sign}${dollars}.${cents}`;
}
});

this.transitionToRoute not working in my controller Ember

I am using a controller to read the value selected on a drop down menu, take in parameters of some input fields and then save the record. It creates the record and takes in the information just fine. My problem lies when I try to transition to another page at the end of the action. I keep getting the error: Cannot read property 'transitionToRoute' of undefined
I am completely stumped. Any ideas?
Here is my controller code:
var teamId;
export default Ember.Controller.extend({
auth: Ember.inject.service(),
actions: {
onSelectEntityType: function(value) {
console.log(value);
teamId = value;
return value;
},
createProcess: function(processName, processDescription) {
var currentID = this.get('auth').getCurrentUser();
let team = this.get('store').peekRecord('team', teamId);
let user = this.get('store').peekRecord('user', currentID);
let process = this.get('store').createRecord('process', {
team: team,
user: user,
name: processName,
description: processDescription
});
process.save().then(function () {
this.transitionToRoute('teams', teamId);
});
}
}
});
Here is the corresponding route:
export default Ember.Route.extend({
auth: Ember.inject.service(),
model: function() {
var currentID = this.get('auth').getCurrentUser();
return this.store.find('user', currentID);
}
});
You should have clear understanding about this keyword in Javascript. The keyword this only depends on how the function was called, not how/when/where it was defined.
function foo() {
console.log(this);
}
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
Have a look at the MDN documentation to learn more.
You can cache the this in normal variable this and then access inside the call back.
var self = this;
process.save().then(function () {
self.transitionToRoute('teams', teamId);
});
ECMASCript 6 introduced arrow functions whose this is lexically scoped. Here, this is looked up in scope just like a normal variable.
process.save().then(() => {
this.transitionToRoute('teams', teamId);
});

Compare two Ember objects (created with Ember.Object.create method)

I created a custom object with the Comparable mixin and added it to a model as an attribute with Ember transforms
var customObject = Ember.Object.extend(Ember.Comparable, {
compare: function() {
debugger;
}
});
Once the model is ready I create a copy of the custom object and add it as an attribute to the so that I can compare the custom object when it changes to this original value
export default DS.Model.extend({
custom: DS.attr("custom-object"),
ready: function() {
this.set("originalCustom", Ember.Object.create(this.get("custom")));
},
isUpdated: function() {
return Ember.compare(this.get("custom"), this.get("originalCustom"));
}
});
I manually call isUpdated to check if the compare method is invoked, but it never gets hit.
What am I missing here?

The DS.Model `relationships` property is unavailable in record's `init`?

Official documentation for DS.Model describes:
method eachRelationship
property relationships
When i do:
App.Parent = DS.Model.extend({
children: DS.hasMany('child'),
init: function() {
this._super();
this.eachRelationship(function(foo, bar, baz) {
console.log('each relationship', foo, bar, baz);
});
}
});
...it prints out the children relationship.
However, when i do:
App.Parent = DS.Model.extend({
children: DS.hasMany('child'),
init: function() {
this._super();
console.log('realtionships', this.get('relationships'));
}
});
...it prints undefined!
Why? How do i access the relationships property during record initialization, without reverting to the eachRelationship method?
Demo: http://emberjs.jsbin.com/vapama/9/edit?js,output
relationships is defined on the class not on the instances (The static next to the property name tells us this).
var relationships = Em.get(App.Parent, 'relationships');
http://emberjs.jsbin.com/zebalupoba/1/edit
There is a _relationships (with an underscore) property available that is an Object
http://emberjs.jsbin.com/nudor/1/edit?html,js,console

Dependency injection with utility classes

In EmberJS, if I have a utility class I've injected into the container via an initializer, how can I inject dependencies into that utility class?
For example, one could inject a messages class with this initializer:
import Messages from 'app/utils/messages';
var injectMessagesInitializer = {
name: 'injectMessages',
before: 'authentication',
initialize: function (container, application) {
application.register('messages:main', Messages, {initialize: false, singleton: true});
application.inject('controller', 'messages', 'messages:main');
application.inject('component', 'messages', 'messages:main');
application.inject('router', 'messages', 'messages:main');
application.inject('route', 'messages', 'messages:main');
}
};
export default injectMessagesInitializer;
Now, I'd like to be able to inject a Notifier class into that Messages utility. Can I do something like the following?
import Notifier from 'notifier';
var injectNotifierIntoMessagesInitializer = {
name: 'injectNotifierIntoMessages',
after: 'injectMessages',
initialize: function (container, application) {
application.inject('messages', 'notifier', 'notifier:main');
}
};
export default injectNotifierIntoMessagesInitializer;
Inside the utility class:
var Messages = Ember.Object.extend({
showError: function (message, options) {
this.notifier.error(message, options);
},
showErrors: function (errors, options) {
options = options || {};
for (var i = 0; i < errors.length; i += 1) {
this.showError(errors[i].message || errors[i], options);
}
},
...
});
A couple things of note:
The notifier class is a simple notifier, something like ember-cli-growl that does one thing well, throws single notifications.
The messages class is a wrapper for the notifier, adding convenience methods like showError, showErrors, showInfo, showWarn. Essentially, it abstracts the throwing of notifications so we can pivot to a different type or class of notifications in the future.