I have the following case:
Component @permissions this component has a button that triggers a simple promise and set a value on my other component @MenuComponent
export class Permissions {
constructor(private _menu: MenuComponent, private _api: ApiService) {}
btnAction(){
this._api.getDataID(item.project_name, 'usersbyID', userID).then((data: any) => {
this._menu.checkPerm(JSON.parse(data.permissions).description);
});
}
}
its not important what is returned but it is a simple JSON.
In my other component @MenuComponent
@Component({
// ..another configuration non relevant
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MenuComponent implements OnInit {
menus = []
menuPermisson: any;
menuObservable = new Subject();
constructor(private _cdRef: ChangeDetectorRef) {
this.menuObservable.subscribe(value => {
this.menuPermisson = value;
this.reloadAll();
});
}
reloadAll() {
this.menus.push('someValue');
this._cdRef.markForCheck();
}
checkPerm(data) {
this.menuObservable.next(data);
}
}
So the concept is after the promise sends some value to my subject I need to push someValue to the menu until this point it's ok all data get there, but I need to re-render the view so the "someValue" shows on the view. but it does nothing, when I change the this._cdRef.markForCheck()
to this._cdRef.detectChanges()
and put it on a tryCatch it returns Attempt to use a destroyed view: detectChanges
. I can't find a way to render the menu with someValue.
This both components are at the same level on the ChangeDetection Tree
My solution for this case was a suggestion from Maciej Treder, he said:
'The best solution for your problem would be to use Component <-> Service <-> Component
communication: https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service'
So I've created a service that listen to the changes made by @PermissionModule
and send a change event to the @MenuComponent
from that I was able to push vales into the menus
array and render the view, without .tick()
or .detectChanges()
ServiceComponent
@Injectable()
export class SharedServiceMenu {
// Observable string sources
private emitChangeSource = new Subject<any>();
// Observable string streams
changeEmitted$ = this.emitChangeSource.asObservable();
// Service message commands
emitChange(change: any) {
this.emitChangeSource.next(change);
}
constructor() { }
}
Where do I want to emmit the event:
// ...irrelevant code
constructor(private: _shared: SharedServiceMenu){}
this._shared.emitChange(data);
And where I want to listen the change emmited
// ... IrrelevantCode
constructor(private _shared: SharedServicesMenu){}
this._shared.changeEmitted$.subscribe((data) => {
//Do what ever you want with data emmited here
}, (err) => {
console.log(err);
}, () => {
console.log('Complete!');
});