angular 2 subscribe value change not reflecting on html
S

1

7

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

Stylus answered 7/10, 2016 at 22:55 Comment(0)
L
11

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

Lashundalasker answered 8/10, 2016 at 3:35 Comment(4)
This is awesome! Thanks for the answer. I removed changeDetection: ChangeDetectionStrategy.OnPush and the code works! Interesting thing is. I moved the logic into another service.(Facebook service) When Facebook returns user info, I then pick up the roles from database and then next() the flag. The subscribe picked it up but the change was not detected. I still have to manually trigger changeDetection to have it work. I wonder why. I have updated the code.Stylus
Yea, I'm not sure.Lashundalasker
In regards to your comment at the bottom of your post, here's a great referenceLashundalasker
Under Angular 9 in a subscribe() block I also had to use the detectChanges() method call to have the change detection triggered and the view refreshed.Becky

© 2022 - 2024 — McMap. All rights reserved.