How to remove these deprecation on console on ember^2.0 - ember.js

while refreshing my site i am always getting some deprecation like this on console :
A property of <Ember.OutletView:ember666> was modified inside the didUpdate hook. You should never change properties on components, services or models during didUpdate because it causes significant performance degradation. [deprecation id: ember-views.dispatching-modify-property]
How to remove these deprecation on console on ember^2.0
I am not using Ember CLI.

Usually it means, that you need to do the work inside the didReceiveAttrs method, rather than the didUpdate. However, it you must have it in didUpdate, you can do something like this:
didUpdate() {
Ember.run.scheduleOnce('afterRender', this, => {
// some code
});
}
However it most likely will do some rendering twice (however it already does it twice - hence the deprecation).

Romans solution worked well for me, except for some syntax problems. I needed to set a default value to a child component. Heres the code:
initDefValue: function() {
const valEmpty = Ember.isEmpty(this.get("value"));
if (valEmpty) {
Ember.run.scheduleOnce('afterRender', this, () => {
this.sendAction("initValue", this);
});
}
}.on("didReceiveAttrs"),

Related

Ember Mirage: route answered only if debugger is ran

I'm facing a weird issue with Ember mirage. I try to use it inside an integration test.
The code looks like this:
moduleForComponent('editors/steps/call-handler', 'Integration | Component | editors/steps/call handler', {
integration: true,
beforeEach: function () {
startApp();
this.server = startMirage();
...
},
afterEach: function () {
this.server.shutdown();
}
});
test('...', function (assert) {
...
this.server.post('/projects/12/actionwords/1/switch/', () => {
assert.ok(true, "switch route is called");
return {
... some JSON data
}
});
this.render(hbs`{{editors/steps/call-handler
...
}}`);
... and then some manipulation of the component
});
Now the test fails when I run it this way. The weird part is, if I place a debugger just before rendering the component, the test will pass.
I guess there are some timeout issues sooner or later that the debugger hides. Usually, I would only render the component in a callback to ensure the route has been correctly setup but this.server.post returns nothing not has any callbacks (except if I missed something in the doc).
I also tried setting the timing option (just in case) but it doesn't change anything (as expected).
I also tried to add an homemade sleep function to wait one second without the debugger and then the tests work fine. Of course if I can have a clean way to get them working, I'd prefer ;)
Did anyone face the same kind of issues and found a way to solve it ?
Best regards,
Vincent

How do I get the BeforeObserver equivalent in Ember 2.3?

To preface this, I must clarify that I am using the legacy-controller and the legacy-view for the interim period while transitioning to Ember 2.3, found here:
https://github.com/emberjs/ember-legacy-controllers
Now, I have a property called currentTopPost on my (legacy) controller.
In Ember 1.7, I had this setup:
// before observer
currentTopPostBeforeObserver: function(){
...
}.observesBefore('currentTopPost'),
// observer
currentTopPostBeforeObserver: function(){
...
}.observes('currentTopPost'),
The reason I had it this way was that when the currentTopPost changed, I wanted it save the old topPost before it switched its value to the new property, as it was a Post object (I had a Post model).
Of course, in 1.7, I saved the old post in the beforeObserver and then did whatever else I had to do in the observer. Now, In Ember 2.3, I have this set up:
currentTopPostObserver: Ember.observer('currentTopPost', function(){
...
}),
Which works fine as far as performing functions with the new value goes. But I've lost the ability to process an action before the value changes. Now according to an answer to this question:
How can an observer find out the before and after values of the observed property in Ember.js?
the observesBefore function has been deprecated and we should be following this:
doSomething: Ember.observer( 'foo', function() {
var foo = this.get('foo');
var oldFoo = this.get('_oldFoo');
if (foo === oldFoo) { return; }
// Do stuff here
this.set('_oldFoo', foo);
})
However, on trying to use this.get("_oldCurrentTopPost"), I get nothing. How do I access the old value of this property before it changes ?
What I use as a replacement is:
propWillChange(prop) {
//your new before observer
},
propDidChange: Ember.observer('prop', function() {
let prop = this.get('prop');
if (this._oldProp !== prop) {
this.propWillChange(this._oldProp);
this._oldProp = prop;
}
//Do stuff
})
Of course, on the first run, _oldProp will be undefined, but that's expected, right? It is the first time prop is being changed.
I also disagree that observers shouldn't be used. I agree that observers should be avoided if possible, because many people don't fully grasp their side-effects, but in many cases they are very useful, especially when building 3rd party plugin integrations.
Since the question specifically asks about a beforeObserver replacement, here it is. However, I recommend to reconsider if your use case can be rebuilt without observers if possible.
Twiddle: https://ember-twiddle.com/045b7b9c1562ceb6bbdc
As far as I can tell, there is no particularly nice way to get that mechanism back. Observers themselves are "considered harmful" in many cases, but I'll try my best to give you a practical alternative solution.
The best quick and relatively dirty way to do this that I can think of is to make a "proxy" computed property with a getter and setter. Within the setter you can get the previous value of the "real" property, call out to a function to do whatever, and then set the new value on the real property.
Here's an example that you could use:
myProxyProperty: Ember.computed('myRealProperty', {
get() {
return this.get('myRealProperty');
},
set(key, value) {
const oldValue = this.get('myRealProperty');
this.doSomethingWithOldValue(oldValue);
this.set('myRealProperty', oldValue);
}
})
Unfortunately I don't know of a better way of doing this in new Ember at the moment.

Need help figuring out what this Ember unloadAll does

I have this route that currently, when I transition back to it, gives me this great big error with a stack trace that doesn't help me figure out what is going wrong.
Error while processing route: project.details Assertion Failed: calling set on destroyed object Error: Assertion Failed: calling set
on destroyed object
at new Error (native)
at Error.EmberError (http://starqa.fmr.com/assets/vendor.js:22615:21)
at Object.Ember.default.assert (http://starqa.fmr.com/assets/vendor.js:15716:13)
at Object.set (http://starqa.fmr.com/assets/vendor.js:26367:22)
at exports.default.mixin.Mixin.create.set (http://starqa.fmr.com/assets/vendor.js:41034:20)
at Ember.Object.extend.flushCanonical (http://starqa.fmr.com/assets/vendor.js:69769:14)
at ember$data$lib$system$relationships$state$has_many$$ManyRelationship.flushCanonical
(http://starqa.fmr.com/assets/vendor.js:71525:22)
at Queue.invoke (http://starqa.fmr.com/assets/vendor.js:11425:18)
at Object.Queue.flush (http://starqa.fmr.com/assets/vendor.js:11490:13)
at Object.DeferredActionQue
Through just going through my routes and commenting out stuff, I found this in my projects route:
export default Ember.Route.extend(AuthenticatedRouteMixin, {
model: function(params) {
if (params.q) {
return this.store.find('project', params);
} else {
var _this = this;
Ember.run(function() {
_this.store.unloadAll('project');
});
return this.store.findAll('project', {reload: true});
}
}
And if I comment out lines 7-9:
/*
Ember.run(function() {
_this.store.unloadAll('project');
});
*/
then the error goes away and the transition worked. This bit of code was written by somebody else, and I think it has to do with refreshing the model from the store, but I can't figure out why it would cause this "calling set on a destroyed object" error.
Any help would be greatly appreciated.
Offhand it looks like this route serves both single project param (q is specified) and all projects, which offhand sounds like far from perfect design for ember. Ideally you should have two routes - the projects and project route. That's on the Ember architecture side.
On the functional side, this happens when you object was released by ember yet you try and access it a second time. I suspect this is happening as the Ember.run, runs the unload all in another loop, whereas I don't think that's what's needed. Try to remove the unload all from the ember loop, or most chances you can just run without it at all (as why do you want to remove all the object in the current cache each time you call the route?
this.store.unloadAll('project');
return this.store.findAll('project', {reload: true});
Or just leave it commented out (I think leaving it commented should work for you).

Detect model/URL change for Ember Route

My EmberJS application has a ProjectRoute (/project/:project_id) and a corresponding ProjectController. When viewing a particular project, users can edit its properties, and I'd like the project to automatically be saved when the user stops looking at it.
Currently, what I'm doing is something like this:
Application.ProjectRoute = Ember.Route.extend({
...
exit: function() {
this.get('controller').saveProject();
}
...
});
This works when the user simply closest the project view. However, if the user simply switches to viewing a different project (e.g. goes directly from /project/1 to /project/2), the same route is used (it just uses a different model), and exit is not called.
What I need is a way to detect this transition and call the saveProject function before it happens. Any ideas?
I "solved" it by adding the following to my controller:
Application.ProjectController = Ember.ObjectController.extend({
...
saveOnChange: function() {
var previousProject = this.get('target.projectToSave');
if (previousProject && previousProject.get('isDirty')) {
Application.store.commit();
}
this.set('target.projectToSave', this.get('content'));
}.observes('content')
...
});
This seems to work well. Note that I'm storing the projectToSave property in the route (target) as opposed to the controller, because the controller gets wiped every time the model changes. It feels a little weird/hacky to store this in the route, but the only alternative I could think of was to store it in ApplicationController, which seemed overly broad.

Is there a way to get a callback when Ember.js has finished loading everything?

I am building an Ember.js app and I need to do some additional setup after everything is rendered/loaded.
Is there a way to get such a callback? Thanks!
There are also several functions defined on Views that can be overloaded and which will be called automatically. These include willInsertElement(), didInsertElement(), afterRender(), etc.
In particular I find didInsertElement() a useful time to run code that in a regular object-oriented system would be run in the constructor.
You can use the ready property of Ember.Application.
example from http://awardwinningfjords.com/2011/12/27/emberjs-collections.html:
// Setup a global namespace for our code.
Twitter = Em.Application.create({
// When everything is loaded.
ready: function() {
// Start polling Twitter
setInterval(function() {
Twitter.searchResults.refresh();
}, 2000);
// The default search is empty, let's find some cats.
Twitter.searchResults.set("query", "cats");
// Call the superclass's `ready` method.
this._super();
}
});
LazyBoy's answer is what you want to do, but it will work differently than you think. The phrasing of your question highlights an interesting point about Ember.
In your question you specified that you wanted a callback after the views were rendered. However, for good 'Ember' style, you should use the 'ready' callback which fires after the application is initialized, but before the views are rendered.
The important conceptual point is that after the callback updates the data-model you should then let Ember update the views.
Letting ember update the view is mostly straightforward. There are some edge cases where it's necessary to use 'didFoo' callbacks to avoid state-transition flickers in the view. (E.g., avoid showing "no items found" for 0.2 seconds.)
If that doesn't work for you, you might also investigate the 'onLoad' callback.
You can use jQuery ajax callbacks for this:
$(document).ajaxStart(function(){ console.log("ajax started")})
$(document).ajaxStop(function(){ console.log("ajax stopped")})
This will work for all ajax requests.
I simply put this into the Application Route
actions: {
loading: function(transition, route) {
this.controllerFor('application').set('isLoading', true);
this.router.on('didTransition', this, function(){
this.controllerFor('application').set('isLoading', false);
});
}
}
And then anywhere in my template I can enable and disable loading stuff using {{#if isLoading}} or I can add special jQuery events inside the actual loading action.
Very simple but effective.