this.transitionToRoute not working in my controller Ember - ember.js

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);
});

Related

How to unit test an ember controller

I have a single action defined in an ember controller that calls 2 separate functions that are part of the controller. I'd like to mock out those functions in a unit test in order to confirm if the action method called the correct function.
My controller looks like this:
export default Ember.Controller.extend({
functionA() {
return;
},
functionB() {
return;
},
actions: {
actionMethod(param) {
if(param) {
return this.functionA();
}
else {
return this.functionB();
}
}
}
});
In practice, the controller works, however in the unit test, functionA and functionB are both undefined. I tried to log this to the console, but can't find where functionA and functionB are, so I'm unable to properly mock them. I expected them to be in the top level of the object next to actions, but instead I only found _actions with actionMethod properly defined.
My unit test looks like below
const functionA = function() { return; }
const functionB = function() { return; }
test('it can do something', function(assert) {
let controller = this.subject();
// I don't want the real functions to run
controller.set('functionA', functionA);
controller.set('functionB', functionB);
controller.send('actionMethod', '');
// raises TypeError: this.functionA is not a function
// this doesn't work etiher
// controller.functionB = functionB;
// controller.functionA = functionA;
// controller.actions.actionMethod();
}
Does anyone have any ideas on how I can replace those functions in the testing environment? Or perhaps, is there a better way to test this functionality or set up my controller?
edit
typo: this.subject to this.subject()
To replace the functions of the controller in the unit test, you can pass parameter to the this.subject() function:
let controller = this.subject({
functionA(){
//this function overriddes functionA
},
functionB(){
//this function overriddes functionB
},
});
Look at the sample twiddle.
This method is especially useful for replacing the injected service of the controllers.
Introduce corresponding property you are dealing with, let us say name property,
So your controllers would be looking like this,
import Ember from 'ember';
export default Ember.Controller.extend({
name:'',
functionA() {
this.set('name','A');
},
functionB() {
this.set('name','B');
},
actions: {
actionMethod(param) {
if(param) {
return this.functionA();
}
else {
return this.functionB();
}
}
}
});
And you can test for the name property value after calling actionMethod.
test(" testing functionA has been called or not", function(assert){
let controller = this.subject();
controller.send('actionMethod',true);
//If you would like to call functionA just say controller.functionA()
assert.strictEqual(controller.get('name'),'A',' name property has A if actionMethod arguments true');
controller.send('actionMethod',false);
assert.strictEqual(controller.get('name'),'B',' name property has B actionMethod arguments false');
});

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?

How do I check if an ember computed property has a setter defined?

Say I have an Ember.Object obj, with a property propPath.
I'm trying to implement:
function isComputedPropertyWithNoSetter(obj, propPath) {
// what do I do here?
// something involving Ember.meta(obj) perhaps?
}
So I can do:
var hasStaticProp = Ember.Object.extend({ prop: 5 }).create();
isComputedPropertyWithNoSetter(hasStaticProp, 'prop');
// => false
var hasComputedPropertyWithSetter = Ember.Object.extend({ prop: function (k, v, d) { }.property() }).create();
isComputedPropertyWithNoSetter(hasComputedPropertyWithSetter, 'prop');
// => false
var hasComputedPropertyNoSetter = Ember.Object.extend({ prop: function () { }.property() }).create();
isComputedPropertyWithNoSetter(hasComputedPropertyNoSetter, 'prop');
// => true
I'm writing 'tree-walking' state serialization code for a large established ember codebase. When I restore state, I want a guard check to make sure I never accidentally overwrite a read-only (getter only) computed property with a static value.
I need to implement this function so I can do....
if (!isComputedPropertyWithNoSetter(obj, propPath) {
// not going to accidentally overwrite a computed property with a static value
Ember.set(obj, propPath, serializedStaticValue);
}
I realize this is fairly dicey, and the solution might be a not entirely recommended hack.

Accessing an injected object from inside of a class in EmberJS

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');
}
})

Teach me how to design a nested computed property in ember.js

I have a handful of computed properties defined on a component. I'd like to refactor these computed properties to live within a messages object on the component. When I make a call to get one of the computed properties elsewhere, I'm returned an instance of Ember's ComputedProperty object, rather then the translation string I expected. Looking at the documentation, Ember.get should invoke the computed property and return the object itself, the property value or null.
What am I missing? How would I go about structuring these nested computed properties so that I can access them using the get/set interface elsewhere in the component?
App.ValidatedDateComponent = Ember.Component.extend({
format: null,
label: null,
messages: {
invalidDateMsg: (function() {
return I18n.t('%{date} must be a valid date. %{format}', {
date: this.get('label'),
format: this.get('format')
});
}).property('label', 'format')
},
validate: function(value, status) {
if (!moment(value).isValid()) {
return status(false, Ember.get(this.messages, 'invalidDateMsg'));
} else {
return this._super(value, status);
}
}
});
Ember only supports defining computed properties while extending Ember.Object class, the exception to the rule is while defining a Ember.Mixin.
Defining the top level of the nest
var nest = Ember.Object.extend({
foo: function() {
return "something";
}.property()
});
Creating an instance of it
App.IndexController = Em.ArrayController.extend({
messages: nest.create()
});
Template
{{messages.foo}}
http://emberjs.jsbin.com/UhUvOvU/1/edit
So in your case you could, if you really wanted to, do:
messages: Em.Object.extend({
invalidDateMsg: function() {
return I18n.t('%{date} must be a valid date. %{format}', {
date: this.get('label'),
format: this.get('format')
});
}.property('label', 'format')
}).create(),