Context
A business component A rely on a business service which say either:
true: all collapsable components should be open by default.
false: all collapsable component should be closed by default.
A pass this knowledge (a calculation, not a stored value) through a one-way property binding to multiple technical children components B, which define the template for a collapsable component (their content is the projection of a specific business component).
When A and B are first rendered, the bindings are resolved and B receive the knowledge: the collapsable components know if they should display their content or hide it. Nonetheless, they are still providing a button to display or hide the content if the user wants to.
Note: a collapsable component does not inject the service itself to access the knowledge directly, because it is a business service and it is a technical component.
Problem
After an action in A, I want to "re-resolve" the property binding with B, so I want A to pass the service knowledge to B again and thus override any action of the user (ex: if he opened a collapsable component which is closed by default, I want it to be restored to its default state, so closed).
The simplest solution would be to re-render the component (destroy/create), but I don't want that because :
1) I don't want the user to see a blink caused by the destruction/rendering of the component.
2) There is no good reason beyond this issue to re-render the component.
Code
@Component({
selector: 'business-parent',
template: '
<generic-collapsable-component [opened]="businessHelper.conditionA">
// A business-child component
</generic-collapsable-component>
// More generic-collapsable-component
'
})
export class BusinessParentComponent {
constructor(private businessHelper: BusinessHelper) {
}
onBusinessAction() {
// Here I do some business stuff...
// And I want to force the binding [opened] to re-execute its default value, so I want GenericCollapsableComponent.opened = businessHelper.conditionA, and not what I currently have, which is the value of the last GenericCollapsableComponent.switch() I called.
}
}
@Component({
selector: 'generic-collapsable-component',
template: '
<button (click)="switch()">Switch to show or hide content</button>
<div [ngClass]="{'is-hidden': !isOpen()}"
<ng-content></ng-content>
</div>
'
})
export class GenericCollapsableComponent {
@Input() opened: boolean; // Is intialized by the parent component but can be modified by the inner switch() method called in the template.
constructor() {
}
switch(): void {
this.opened = !this.opened;
}
isOpen(): boolean {
return this.opened;
};
}
Solutions
- Re-render the component: NO.
- Bind a function () => boolean to set the initial value and use an other private boolean value to respond to the user actions: this is what I did and it works, but it is not ideal.