Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angular 2 subscribe value change not reflecting on html

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!!

like image 860
Chuck Avatar asked Oct 07 '16 22:10

Chuck


1 Answers

It's because you're using changeDetection: ChangeDetectionStrategy.OnPush. What this means is that a change detection for the component will only occur when @Inputs 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

like image 180
Paul Samsotha Avatar answered Oct 17 '22 00:10

Paul Samsotha