0

Might be a beginners question but I'm really stuck here. Just trying to toggle the class of an element I added to my HTML like this:

<ion-card [ngClass]="{
   'inactive': step2Inactive,
   'button-card': true
}">

It should always have the button-card class and a toggleable inactive class.

In my TS file in initialize the param at the top of the class like this above the constructor:

protected step2Inactive: boolean = true;

Then at runtime I try to change it like this, but nothing happens:

this.step2Inactive = false;

The last part is wrapped in some functions and Timeouts, could I be losing the focus of "this"? Sorry this might be a very basic thing to ask but I couldn't find any solution to this :/

I am using Ionic 4 and Angular 8.1.2

Full Class:

    import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
    import { HTTP } from '@ionic-native/http/ngx';
    import { NFC } from '@ionic-native/nfc/ngx';
    import { Vibration } from '@ionic-native/vibration/ngx';
    import { Platform, AlertController, IonRadioGroup, NavController, ToastController, IonCard } from '@ionic/angular';

    @Component({
        selector: 'app-repair',
        templateUrl: './repair.page.html',
        styleUrls: ['./repair.page.scss'],
    })
    export class RepairPage implements OnInit {

        protected stepsHidden: boolean = false;
        protected step2Inactive: boolean = true;
        protected step3Inactive: boolean = true;
        protected spinnerHidden: boolean = true;
        protected resultContainerHidden: boolean = true;

        constructor(
            private http: HTTP,
            private platform: Platform,
            private nfc: NFC,
            private vibration: Vibration,
            private alertController: AlertController,
            private navCtrl: NavController,
            private tstCtrl: ToastController,
        ) {}

        ngOnInit() {
        }

        ionViewDidEnter() {
            this.slides.lockSwipeToNext(true);
            this.slideParams[0] = 'rfid';
            this.slideParams[1] = 'guarantee';
            this.startRFID();
        }
        startRFID() {
            let listener = this.nfc.addNdefListener(() => {
                console.log('connected ndef listener')
            }, (err) => {
                console.log('error attaching ndef listener', err);
            }).subscribe((event) => {
                this.spinnerHidden = false;
                this.resultContainerHidden = true;
                setTimeout(() => {
                    this.step2Inactive = false;
                }, 1000);
                setTimeout(() => {              
                    this.step3Inactive = false;
                }, 2000);
                setTimeout(() => {
                    this.spinnerHidden = true;
                    this.stepsHidden = true;
                    this.resultContainerHidden = true;
                }, 3000);
            })
        }
    }

Full HTML File:

<ion-header>
</ion-header>
<ion-content>
    <ion-slides #slides [options]="slideOpts">
        <ion-slide class="slide-2">
            <ion-row>
                <ion-col size="12">
                    <h3 *ngIf="this.slideParams[1] == 'guarantee'">Garantie</h3>
                    <h3 *ngIf="this.slideParams[1] == 'costs'">Kostenpflichtig</h3>
                    <h3 *ngIf="this.slideParams[0] == 'rfid'">RFID Scan</h3>
                    <h3 *ngIf="this.slideParams[0] == 'qr'">QR Code Scan</h3>
                </ion-col>
            </ion-row>
            <div *ngIf="this.slideParams[0] == 'rfid'" [ngClass]="{'hidden': this.stepsHidden}">
                <ion-card class="button-card">
                    <ion-row>
                        <ion-col size="1">
                            <h3>1</h3>
                        </ion-col>
                        <ion-col class="ion-align-self-center" size="10">
                            <ion-text color="#606368">RFID zum scannen berühren</ion-text>
                        </ion-col>
                    </ion-row>
                </ion-card>
                <ion-card [ngClass]="{
                    'inactive': step2Inactive,
                    'button-card': true
                }">
                    <ion-row>
                        <ion-col size="1">
                            <h3>2</h3>
                        </ion-col>
                        <ion-col class="ion-align-self-center" size="10">
                            <ion-text color="#606368">Artikelnummer erkannt</ion-text>
                        </ion-col>
                    </ion-row>
                </ion-card>
                <ion-card [ngClass]="{
                    'inactive': this.step3Inactive,
                    'button-card': true
                }">
                    <ion-row>
                        <ion-col size="1">
                            <h3>3</h3>
                        </ion-col>
                        <ion-col class="ion-align-self-center" size="10">
                            <ion-text color="#606368">Daten werden geladen</ion-text>
                        </ion-col>
                    </ion-row>
                </ion-card>
            </div>
            <ion-row #spinner [ngClass]="{
                'hidden': spinnerHidden
            }" *ngIf="this.slideParams[0] == 'rfid'">
                <ion-col>
                    <ion-spinner color="danger" class="ion-align-self-center"></ion-spinner>
                </ion-col>
            </ion-row>
            <ion-card #result_container [ngClass]="{
                'hidden': resultContainerHidden,
                'ion-padding-horizontal': true
            }" (click)="openCard()">
            </ion-card>
        </ion-slide>
    </ion-slides>
</ion-content>
<ion-footer>
    <footer-nav-bar></footer-nav-bar>
</ion-footer>
MincedMeatMole
  • 469
  • 6
  • 14
  • I think we'll need to see some more code. At the moment, there are a lot of bits and pieces and I don't think we can help just based on that. For instance 1. In what context are you changing this variable? 2. Are your .css classes correct? 3. Is all this happening in a single component? etc.. – Nicholas K Jan 27 '20 at 09:41
  • I added the full Codeblock for the .ts file. This is all happening in a single page. Adding the full HTML as well. Just removed some unnecessary parts like content of ion-header and first few slides to keep it all a bit smaller – MincedMeatMole Jan 27 '20 at 09:46
  • Well, thats not exactly what I meant. You'll need to create a [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). For more information, see [How to Ask](https://stackoverflow.com/help/how-to-ask) and take the [tour](https://stackoverflow.com/tour). – Nicholas K Jan 27 '20 at 09:48
  • Ok broke it down to as little code as possible while still keeping the logic. Hope this helps. Basically everything important happens in the startRFID() Function. That function runs as expected, just doesn't update any classes – MincedMeatMole Jan 27 '20 at 09:54
  • Looks like this line `setTimeout(() => { this.step2Inactive = false; }, 1000);` sets the variable to false. Where are you setting it to true again? – Nicholas K Jan 27 '20 at 09:57
  • Currently it's not getting reset. Only at the top when I init the variable it's set to true by default: protected step2Inactive: boolean = true; – MincedMeatMole Jan 27 '20 at 09:59
  • Hmm.. so it's true to default but then your subscription code executes and you set it to false. You need to reset it to true in order for it to work again. – Nicholas K Jan 27 '20 at 10:01
  • Just tried that at the start of the subscriber, directly below the subscribe. Still no effect > The class isn't even toggled once. Not even on the first run – MincedMeatMole Jan 27 '20 at 10:03
  • `.subscribe()` is an asynchronous call, so it won't work as you expect it to. I feel you should read up more on how they work. Also, if you are trying to simply toggle a button why are you using all these subscriptions and setTimeOut's? – Nicholas K Jan 27 '20 at 10:08
  • Running the functions outside the subscribe seems to do the trick. The Timeouts are to simulate a loading process. (I know that's bad for UX but it's all I got for now, trust me). Will refactor the code to work outside the subscribe. I first had some old school js Functions with document.querySelector in there, that worked. So changing that broke it all. Makes sense now – MincedMeatMole Jan 27 '20 at 10:15
  • Great. Glad I could help. – Nicholas K Jan 27 '20 at 10:18
  • Does this answer your question? [Angular 6 View is not updated after changing a variable within subscribe](https://stackoverflow.com/questions/50519200/angular-6-view-is-not-updated-after-changing-a-variable-within-subscribe) – MincedMeatMole Jan 29 '20 at 14:01

1 Answers1

0

Posting a solution if anyone ever stumbles across this: Basically I was trying to change the variable outside of the "angular zone" after the subscribe. Thus the change did not affect the DOM.

Full explanation and code can be found here: Angular 6 View is not updated after changing a variable within subscribe

MincedMeatMole
  • 469
  • 6
  • 14