-
Notifications
You must be signed in to change notification settings - Fork 24.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Invoking ngOnChanges before ngOnInit is counter-intuitive. Why not change this? #7782
Comments
It is by design, check the docs https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#hook-sequence According to the docs
Since you're passing inputs to your component is expected that gets fired. |
Thnx @ericmartinezr ! |
I actually didn't get any relevant answer. I read these docs, and I know that this behavior is by design. This issue is about the fact that this design is probably not optimal. Sorry if it's not very clear from my original message. |
Calling |
@zoechi So why not call However, I think all the logic that mostly deals with bindings (Lb) should be put to |
The ngOnInit / ngOnChanges sequence seem to be based on the case where the component inputs will not change and there will not actually be any ngOnChanges implemented. In this case it's OK to do the "heavy initialization" there as the docs suggest:
But if you want your component to react to changes to it's inputs (surely all components should, isn't that the "contract" behind So you need to move the initialization code (or a call to it) to the ngOnChanges part anyway which makes ngOnInit a little irrelevant and a potential landmine to catch the unwary. I think most people would expect the sequence to be: constructor > init > changes (repeated as they happen). The current ordering feels unintuitive (it's a surprise and doesn't help people "fall into the pit of success"). If you want to respond to changes, you use ngOnChanges only. I think you can argue for having ngOnInit OR ngOnChanges but that using both doesn't make much sense or add anything - so they could be simplified and combined (just have ngOnChanges?). I know it's probably too late for changes now, things have shipped in ng1 so we're probably stuck with it. |
@CaptainCodeman Actually, things haven't been shipped in ng1. @pkozlowski-opensource Please consider reopening this issue. I believe it was closed by mistake. |
Sorry, I thought they had, the component and router are mentioned in the docs, they must be a version ahead? https://docs.angularjs.org/guide/component I think 'issue closed' means "discussion over" - it's by design. |
The component lifecycle hooks are still under development in ng1. In particular, in the latest released version (1.5.3), Okay, if it's by design, what are those design considerations that are behind the current hook sequence? Why is it a bad idea to change it? Or is it probably not so bad? It'd be great to get a substantive answer as these questions are going to be asked again and again due to the counter-intuitiveness of the current design. |
I stand corrected, I thought the router and component stuff was already released for v1.x - so I agree, now is the time to change it if it needs changing.
I was just pointing out that it's been discussed before and shut down as "by design", I wasn't suggesting I thought that it would be a bad idea to change it - I agree with you that it seems counter intuitive and unhelpful. I don't know why some pieces seem open to more major re-design and even re-writes whereas other parts are not. Maybe differences in what people's view of "beta" means (e.g. is the API meant to be stable?) and what the implications of making various changes are. |
+1 for rethinking its design Inputs are coming before view and content init, and even ngOnInit, and if you are using setters on inputs to perform something that is depend of view components you can't do it on component initialization, but can do on next time inputs are changed. This creates a dummy code, like this: export class DatePicker implements AfterViewInit {
isInited = false;
@Input()
set data(data: string) {
if (this.isInited)
this.doSomethingViewRelated(data);
}
ngAfterViewInit() { // or ngOnInit as thorn0 described
this.isInited = true;
this.doSomethingViewRelated(this.data);
}
} |
+1 for rethinking its design, I too think this is counter intuitive... |
If for some reason you want to ignore that first call to ngOnChanges (before ngOnInit was called), you can use the isFirstChange() function:
|
@fikkatra I dont know. It is look like "Why do it simple if we can do it complicated" |
+1 for rethinking this as well. It's very counter intuitive. OnInit should be called when the initial values are set for any @inputs (hence the name Init), then OnChanges for any changes (hence the name Changes). |
+1 for rethinking for the same reason. You can also consider renaming this lifecycle hook to increase intuitiveness. Here are some suggestions:
|
+1 this is very confusing. can be worked around by accessing changes.item.firstChange |
+1 for rethinking it. It's confusing as hell - makes me trip over it each time. |
For one whose have a component with a
This solved my problem |
@lscarneiro nice, would probably use ReplaySubject to catch situations where the ngOnChanges occure before ngOnInit - see: https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/subjects/replaysubject.md |
+1 here for improving this. no necessity to run on changes on init, it's self explanatory. |
or a +1 to add a ngOnAfterConstruction call which should always be in prior of ngOnChanges and ngOnInit - and thus no breaking change. |
just wanted to cast my vote here that this is very counterintuitive. I just now found this thread while trying to figure out what was going on in my code; it SEEMED like ngOnInit was being called after ngOnChanges... "but that's crazy", I thought. "I must be doing something else wrong; init obviously happens before changes". apparently I was wrong... |
... there is certainly a reason why |
@mlc-mlapis the Init is something everyone is expecting as the next event. the issue is that init can be the next event, but once you bind to an input, then ngOnChanges is fired before. it's documented, yet this does not mean it has a good developer experience. I myself really miss an event that occures right after ctor, because in ctors you can't use async/await. and with ngOnChanges / ngOnInit occuring in a deterministic, predicable but non static order there's no way to do some "magic" without adding extra boilerplate code. and if a new tool forces you to write BS (boilerplate) then we should really ask: how modern that tool is. I really like Angular, but whenever I had some issues, I always asked: how solves that Rob Eisenberg? Believe or not:
|
@hidegh ... ah, no, no, I didn't mean that the suggestion is wrong itself ... I just wanted to say that exact formulation, why the actual logic and naming is as it is, can help us to suggest even better names. 😄 |
Has there been a clarification as to why this is the expected behavior? I would have expected the following to work: @Component()
export class SomeFormComponent {
@Input() someObject: object;
@Input() parentForm: FormGroup;
ngOnInit() {
// add controls to parent form
parentForm.registerControl('name', new FormControl(this.someObject.name, [Validators.required]));
}
ngOnChanges(changes) {
// someObject was changed to different object, say in case of parent - detail
const someObjectChanged = changes.someObject;
if (someObjectChanged) {
this.parentForm.get('name').setValue(someObjectChanged.currentValue.name);
}
}
} yet it doesn't because ngOnChanges will fire before ngOnInit. I realize there are workarounds. In this case, for instance, I would have to check 'isFirstChange' in ngOnChanges to make sure that the form exists |
It's a bit strange that I'm using this to detect if it's the first change. Do you think it's correct?
|
@hgoebl according this it is: https://angular.io/api/core/SimpleChange but still, the ngOnInit is not always the 1st call, which is all but unnatural and needs some boilerplate code. |
ngOnChanges gets a SimpleChanges object, which is a collection of SimpleChange objects. SimpleChanges does not have a way to determine if it's the first change or not. More to the point though, there still has been no explanation why the order of lifecycle hooks is the way it is, other than "it's by design" (which is not an explanation) |
I’ve seen many components not implementing I wouldn’t spend more time discussing the design decision. Seems like this won’t change… |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Steps to reproduce and a minimal demo of the problem
http://plnkr.co/edit/kIf8QgrFxtENzvr6V5TZ
Open the console to see the output there.
Current behavior
ngOnChanges
ofMyComponent
is called beforengOnInit
(docs).Expected/desired behavior
I just have doubts about the idea of calling anything on a not fully initialized component. What if in
ngOnChanges
I want to use something that is initialized inngOnInit
('That's where the heavy initialization logic belongs' as the docs say)? Why not change this order?The text was updated successfully, but these errors were encountered: