This is quite confusing to me. I might not have a solid understanding of how subscription works.
Angular 2 finalized version
Goal: Hide/Show navigation menu based on roles Approach: I use Facebook to authenticate users. After authentication, user roles will be retrieved and used to determine if Admin menu should be displayed. A observable.next call is made with true and the nav bar compoenent subscription will pick up the flag and change the isAdmin to true.(isAdmin is false to begin with) That shall allow the Admin menu to be displayed.
Problem: The true flag is properly picked up by the subscriber and the isAdmin is set to true. However, the Admin menu doesn't show up.
navbar.component.ts
@Component({
selector: 'as-navbar',
templateUrl: 'app/shared/navbar/navbar.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NavbarComponent {
@Input() brand: string;
public isAdmin:boolean;
constructor(private _securityService:SecurityService){
let self = this;
this._securityService.isAdminObservable.subscribe(function (flag) {
this.isAdmin = flag;
console.log('subscribe received on navbar');
}.bind(this));
}
}
navbar.html
<li class="dropdown" *ngIf="isAdmin">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Admin<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a [routerLink]="['/campaigns']">Campaigns</a></li>
<li><a [routerLink]="['/products']">Products</a></li>
<li><a [routerLink]="['/products']">Reports</a></li>
</ul>
</li>
app.component.ts
constructor(private _http: Http, private _jsonp: Jsonp, private _securityService:SecurityService) {
this.appBrand = CONSTANTS.MAIN.APP.BRAND;
let self = this;
setInterval(function(){
self._securityService.setAdminStatus(true);
console.log('set from app component');
}, 5000)
}
security.service.ts
@Injectable()
export class SecurityService{
public isAdmin:Subject<boolean>=new Subject<boolean>();
public isAdminObservable = this.isAdmin.asObservable();
constructor(){}
setAdminStatus(flag){
this.isAdmin.next(flag);
}
}
Is there something wrong with this? Or there are better approach to achieve the goal? Any suggestion will be greatly appreciated! Thanks
UPDATE
With the answer provided by peeskillet, I removed the changeDetection line from the component and it works.
However, when I further work on the code, I move
self._securityService.setAdminStatus(isAdmin);
to another service (Facebook service in this case) and call that service from app component. The subscribe in navbar.compoenent.ts does pick up the change but didn't trigger change detection. I have to manually trigger the detection to make it work.
updated navbar.component.ts
@Component({
selector: 'as-navbar',
templateUrl: 'app/shared/navbar/navbar.html'
})
export class NavbarComponent {
@Input() brand: string;
public isAdmin:boolean=false;
constructor(private _securityService:SecurityService, private cdr: ChangeDetectorRef){
this._securityService.isAdminObservable.subscribe(function (flag) {
this.isAdmin = flag;
this.cdr.detectChanges();
console.log('subscribe received on navbar');
}.bind(this));
}
}
updated app.component.ts
@Component({
selector: 'as-main-app',
templateUrl: 'app/app.html'
})
export class AppComponent {
public appBrand: string;
constructor(private _http: Http,
private _facebookService:FacebookService
) {
this.appBrand = CONSTANTS.MAIN.APP.BRAND;
this._facebookService.GetLoginStatus();
}
}
This is fairly interesting. Apparently, I need to learn more about angular 2 change detection. If anyone knows a good reference, please share with me.
Thank you!!
It's because you're using changeDetection: ChangeDetectionStrategy.OnPush
. What this means is that a change detection for the component will only occur when @Input
s inputs are changed1.
So if you remove the @Component.changeDetection
, it should work.
If your goal is to keep the OnPush
strategy, then one option would be to explicitly force the change detection, using the ChangeDetectorRef
class SomeComponent {
message;
constructor(private service: Service, private cdr: ChangeDetectorRef) {
}
ngOnInit() {
this.service.subscribe(data => {
this.message = data;
this.cdr.detectChanges();
})
}
}
1 - See Also ChangeDetectionStrategy.OnPush and Observable.subscribe in Angular 2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With