Neamesis
Neamesis

Reputation: 744

PrimeNG + Angular 4 : toggle button set in component isn't updated on the screen

I'm a beginner working on an app built with JHipster and using Angular 4.3. I'm using PrimeNG too.

I'm trying to use <p-toggleButton> (here is the documentation), but my problem is that I update my value in my component.ts, but the html doesn't matter.

The use case is that with some conditions, users can't put the button into ON or OFF. So I've got to check the conditions and assign the toggle button according to the result.

My code looks like this :

HTML

   <p-toggleButton [(ngModel)]="checked"
                   [value]="checked" // Tried [(ngValue)], (ngValue) too but doesn't work
                   (ngModelChange)="lockChanged()"
                   onLabel="ON" offLabel="OFF"
                   [style]="{'width':'150px'}">
   </p-toggleButton>

TS

export class Component implements OnInit {
    checked: boolean;
    lockScreen: Lock;
    lockItem: LockItem = [...];

    constructor(
        private lockService: LockService
    ) { }

    ngOnInit() {
        this.findLock();
    }

    lockChanged() {
        this.lockService.find(this.lockItem).subscribe((res) =>  this.lockScreen = res);
        if (this.checked) {
            if (this.lockScreen.lockItem === undefined) {
                let lock = new Lock();
                this.lockService.create(lock).subscribe((res) => console.log(res));
                this.checked = true;
            } else {
                // TODO error Message

            }
        } else {
            if (this.lockScreen.lockItem !== undefined) { 
                this.checked = true;
                console.log(this.checked); // is true
            }
        }
    }

    private findLock() {
        this.lockService.find(this.lockItem).subscribe((res) => {
            res.lockItem ? (this.checked = true, this.lockScreen = res) : (this.checked = false, this.lockScreen = res);
        });
    }
}

But even if I set the checked value to true or false, the html code doesn't matter. I've tried [(ngValue)], (ngValue) and [value] in the html... Does anyone have an idea ?

EDIT : Answers to comments + Solution

@Arash : I've tried (change), my function in my TS isn't called. I've no choice but using (ngModelChange)

@Skorunka František : If I put a disabled property, I can't use my toggle button because of the disabled status. So I can't use this.

@Shah : Yes, it doesn't have a property value, I've just tried solutions like when I use other components.

@Bharat Gupta : You partially solved my problem, thank you !

Here is the code that works :

HTML

   <p-toggleButton [(ngModel)]="locked"
                   (onChange)="lockChanged()"
                   onLabel="ON"
                   offLabel="OFF"
                   [style]="{'width':'150px'}">
   </p-toggleButton>

TS

                this._ngZone.run(() => {
                    setTimeout(()=>{
                        this.locked = false;
                    },0);
                });

Upvotes: 1

Views: 6331

Answers (1)

Bharat Gupta
Bharat Gupta

Reputation: 2696

Quoting @Gunter from this answer:

Angular runs the code of your components within its zone where most async APIs (addEventListener, setTimeout, ...) are patched so the zone can notify Angular when such an async callback has happend. This is when Angular runs change detection.

If you initialized AssetService outside Angular or AssetService by other means executes code outside Angulars zone, then Angular doesn't get notified about happened async callbacks and doesn't run change detection.

So you might need to execute your changes within zone.run(). First inject NgZone into your component. And then lockChanged needs to change like below:

lockChanged() {
    this.lockService.find(this.lockItem).subscribe((res) =>  this.lockScreen = res);
    if (this.checked) {
        if (this.lockScreen.lockItem === undefined) {
            let lock = new Lock();
            this.lockService.create(lock).subscribe((res) => console.log(res));
            this.zone.run(() => { this.checked = true });
        } else {
            // TODO error Message
        }
    } else {
        if (this.lockScreen.lockItem !== undefined) { 
            this.zone.run(() => { 
              this.checked = true;
              console.log(this.checked); 
            });
        }
    }
}

Similar changes would be needed to be done for findLock function.

Upvotes: 2

Related Questions