Call a function inside a controller from observer in Ember - ember.js

I have a controller like this
App.TestController = Ember.ArrayController.extend({
navigation:[],
somefunc:function(){
//do something
}
});
and have an observer for
globalvars = Ember.Object.create({
page : 1,
});
globalvars.addObserver('page', function() {
this.get('controller.controllers.Test').somefunc();
});
the problem is that i can't call the function inside the controller.

As i already mentioned in my comment, here a disclaimer:
You should explain in more detail, what you are trying to accomplish.
You are trying to access the controller in a strange way.
But here is an approach if you absolutely have to do it this way:
var App = Ember.Application.create({});
// put the global vars into the App object instead of polluting the global namespace
App.globalvars = Ember.Object.create({
page : 1,
});
Instead of putting the observer in the globalVars object, i would declare the observer in the controller:
App.TestController = Ember.ArrayController.extend({
navigation:[],
somefunc:function(){
//do something
},
globalVarsPageObserver : function(){
this.somefunc();
}.observes("App.globalvars.page")
});

Related

EmberJS : Call parent class function from child class init method

I have a parent class
MyBaseClass = Ember.Object.extend({
getData:function() {
return someData;
}
})
and a child class that when created needs to call a function in parent class
MyChildClass = MyBaseClass.extend({
sampleData:[],
init:function(){
this._super();
Ember.set(this, 'sampleData', this.getData());
}
})
My problem is, when i run this code i get "Uncaught TypeError: this.getData is not a function".
Any idea why this is happening? Or fix to this.
Write your init method this way without using ES6 syntax:
init: function() {
this._super.apply(this, arguments);
Ember.set(this, 'sampleData', this.getData());

React test; how to mock componentDidMount or overwrite it?

I'm trying to test a react component.
var Component = React.createClass({
componentDidMount: function () {
return this.setState({
name: 'blabla'
});
},
render: function () {
return (
<h1>{this.state.name}</h1>
);
}
});
Is there a way, during testing, to mock what componentDidMount returns or does? That would leave me to test it on it's own and just test the component render behaviour.
Thanks!
I prefer the following approach, but requires using ES6 classes.
// component.jsx
class Component extends React.Component {
componentDidMount() { return this.setState({name: 'blabla'}); }
render() { return (<h1>{this.state.name}</h1>); }
}
//component-spec.jsx
describe('Component', () => {
it('does stuff', () => {
let ComponentTest = class extends Component {
componentDidMount() {
// your override here
}
};
let component = TestUtils.renderIntoDocument(<ComponentTest />);
//expect(component...).toEqual(...)
});
});
The point is to create an on demand ChildClass inheriting the OriginalClass,
do whatever overrides and then TestUtils.renderIntoDocument(<ChildClass />)
The idea here, if I understand correctly, is that you're trying to stub out a function before a component is rendered in your test. In your case, componentWillMount is only called once in a component's lifecycle, immediately before the component is rendered. So you can't just render the component and then stub out the function, it must be done before the render occurs.
Let's take these components for example:
parent.js
var Child = require('./child.js');
var Parent = React.createClass({
render : function () {
return (
<div className="parent">
<Child/>
</div>
);
}
});
module.exports = Parent;
child.js
var Child = React.createClass({
test : function () {
return true;
},
render : function () {
if (this.test) {
throw('boom');
}
return (
<div className="child">
Child
</div>
);
}
});
module.exports = Child;
Here, we would want to stub out the test function before our Child component is rendered, otherwise, it will blow up.
I have been able to do this using jasmine-react. These helper functions provide some useful functionality when running tests, almost to the point where TestUtils can be ditched completely.
jasmineReact.render(component, [container]) will render an instance of component into the DOM node specified in [container]. This is like TestUtils.renderIntoDocument(), except it renders the component into an attached DOM node instead of a detached DOM node. It will also perform the necessary cleaning operations when the test is finished.
jasmineReact.spyOnClass(componentClass, functionName) will stub out a particular function belonging to a component class. This behavior is maintained until the end of the test, which means that you can call this function before a component is rendered. This, if I understand correctly, is what you're looking for.
So, using these two helper functions, I can write a test for the code shown above that looks something like this:
var React = require('react/addons'),
Parent = require('./parent.js'),
Child = require('./child.js'),
jasmineReact = require('jasmine-react-helpers');
describe('Parent', function () {
it('does not blow up when rendering', function () {
jasmineReact.spyOnClass(Child, 'test').and.returnValue(false);
var parentInstance = jasmineReact.render(<Parent/>, document.body); //does not blow up
expect(parentInstance).toBeTruthy(); //passes
});
});
Let me know if you have any questions.
I've found two ways to go about this (i'm sure there are more).
1) I've used sinon-chai and required in the base element class and then use rewireify to put a set a spy on the componentWillMount method. This works but not sure what test suites you're using.
2) Probably the easier way. Is to just use the TestUtils to get an instance of the component and then just manually run the componentWillMount method.
That second way would probably look something like (forgive the pesudo code):
it('should call state when it first mounts', function () {
var Component = require('../my-component');
var component = TestUtils.renderIntoDocument(<Component />);
component.setState({name: null});
component.componentWillMount();
expect(component.state.name).to.equal('blabla');
});

How to change the URL/route from within an observer

How can I force the application to change the URL/route when something happens that is triggered by an observer in a controller?
You use transitionToRoute:
// controllers/item.js
export default Ember.Controller.extend({
myObserver: function() {
if(this.get('someProperty')) {
this.transitionToRoute('someOtherRoute');
}
}.observes('someProperty')
});

AngularJS: Mock object injected to controller trough router's resolve

I'm trying to test a controller that receives an object trough router's resolve:
app.js:
...
.when('/confirm', {
templateUrl: 'views/confirm.html',
controller: 'ConfirmCtrl',
resolve: {
order: function(Order) {
return Order.current;
}
}
})
...
ConfirmCtrl.js:
angular.module('angularGeolocationApp').controller('ConfirmCtrl',
function($scope, order, ...) {
$scope.order = order
...
});
My Test looks like this:
'use strict';
describe('Controller: ConfirmCtrl', function () {
// load the controller's module
beforeEach(module('angularGeolocationApp'));
var ConfirmCtrl,
scope;
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
ConfirmCtrl = $controller('ConfirmCtrl', {
$scope: scope
});
}));
it('should get an order object', function () {
expect(_.isObject(scope.order)).toBeTruthy();
});
...
});
However first expectation fails:
PhantomJS 1.9.2 (Mac OS X) Controller: ConfirmCtrl should get an order object FAILED
TypeError: Attempted to assign to readonly property.
at workFn (/Users/jviotti/Projects/Temporal/angular/angular-geolocation/app/bower_components/angular-mocks/angular-mocks.js:2107)
Expected false to be truthy.
My assumption is that as I'm unit testing the isolated controller, the router doesn't have a change to run the resolve function and assign the correct value.
Is there a way to mock that order dependency?
I know I can get rid of the resolve stuff and inject Order and instantiate $scope.order to Order.current in the controller itself, but I'd like to keep the resolve approach.
Just put your own order into the constructor of the ctrl like this.
describe('Controller: ConfirmCtrl', function () {
// load the controller's module
beforeEach(module('angularGeolocationApp'));
var ConfirmCtrl,
scope,
order
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope) {
order = {};
scope = $rootScope.$new();
ConfirmCtrl = $controller('ConfirmCtrl', {
$scope: scope,
order: order
});
}));
it('should get an order object', function () {
expect(_.isObject(scope.order)).toBeTruthy();
});
...
});
regards

Calling a "base-class" method from an extended object

Let's say I have this:
App.ControllerMixin = Ember.Mixin.create({
setupController : function (entry) {
...
}
});
App.BaseEditController = Ember.ObjectController.extend(App.ControllerMixin, {
startEditing: function () {
...
this.setupController(entry);
},
});
App.ServicesEditController = App.BaseEditController.extend(App.ServicesMixin, {
setupController : function (entry) {
}
});
How can I call ControllerMixin.setupController from ServicesEditController.setupController?
You can call methods from super classes with this._super(). It is generally a good idea to add this call to each method you are overriding.
App.ServicesEditController = App.BaseEditController.extend(App.ServicesMixin, {
setupController : function (entry) {
this._super(entry);
}
});
Extending on my advise to add this call each overridden method, this is an example of a Mixin for a View. If your Mixin overrides didInsertElement, you should always add a call to this._super(). This ensures that "all" didInsertElement implementations get called, if multiple Mixins are applied.
App.SomeViewMixin = Ember.Mixin.create({
didInsertElement : function(){
this._super();
// ... perform your logic
}
});