Suppose I have components Parent
and Child
. Child
can be used either as a standalone component, or within a Parent
component. However, I want Child
to have different behavior based upon where it lives.
Suppose Child
has an optional @Input [isHappy]
, which is either true
or false
. However , whenever a Child
component is hosted by a Parent
component, suppose isHappy
must always be true.
AFAICT there are two ways of doing this:
1) User must just know to always specify [isHappy]="true"
whenever a Child
is hosted by a Parent
.
<parent>
<child [isHappy]="true"></child>
</parent>
2) Parent
manually sets this.child.isHappy = true
within its ngOnInit
lifecycle hook.
Which approach is preferred? In my opinion, approach #2 makes more sense, users don't have to know to set [isHappy]="true"
when a Child
is hosted by a Parent
. On the other hand, I'm aware that it's frowned upon in Angular for components to programmatically change one another, especially if all components are OnPush
(please correct me if I'm wrong here).
I want Child to have different behavior based upon where it lives.
How about letting Child
component know where it lives with ElementRef
:
export class ChildComponent {
hasParent: boolean;
constructor (
private elRef: ElementRef
) {}
ngOnInit() {
const el = this.elRef.nativeElement.parentElement as HTMLElement
this.hasParent = el.localName === 'app-parent'
}
}
stackblitz: https://stackblitz.com/edit/angular-kagdsu
In my opinion 2nd way would work, but that could add couple of things into your solution
parent
component don't have child
component? To solve it by better way, I'd suggest you to use Host
decorator, that will ask for Parent
component dependency from Child
component. If that exists the make isHappy
property to be true
@Component({...})
export class Child {
@Input() isHappy: boolean = false;
constructor(@Optional() @Host() private parent: Parent) {}
ngOnInit() {
// Do only if parent exists
if (this.parent) {
this.parent.isHappy = true
}
}
}
I understand even the way suggested above has tight coupling between the Parent
component. We should think of removing that dependency from the inner child component.
Yes, we can do that by little hackish way, where we would be checking current component's immediate parent component name like below. For achieving the same you had to add ViewContainerRef
dependency to get hold of parent/host component.
constructor(private viewContainer: ViewContainerRef) {}
ngOnInit() {
if(this.viewContainer[ '_data' ].componentView.parent.component.constructor.name === 'Parent') {
this.parent.isHappy = true
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.