Ionic 2: Inconsistency detected in the expression after it was verified

After going through this response, this solution and this advice (as well as numerous others), I still find myself struggling to comprehend how to resolve this issue in my current approach.

The task at hand involves creating an event countdown timer that displays the two largest remaining time intervals, such as 1 year, 2 months, 4 days, 12 hours, 10 minutes, and 25 seconds.

Despite having multiple events on the screen all calling the same function, I keep encountering the error message:

Error Expression has changed after it was checked
. This tends to occur when the seconds are actively counting down, and occasionally when there is a change in minutes during the countdown.

Below is a snippet of my HTML structure:

<ion-header>
    <ion-navbar>
        <ion-title>
            <h2>{{theTime}}</h2>
        </ion-title>
    </ion-navbar>
</ion-header>

<ion-content padding-top padding-bottom>
    <ion-fab right bottom>
        <button ion-fab color="primary" (click)='goToEventUpsert()'>
            <ion-icon name="add"></ion-icon>
        </button>
    </ion-fab>
    <ion-card class="event" *ngFor="let event of events | OrderBy : 'dateTimeEpoch'" id="id-{{event.id}}">
        <div class="event__container">
            <div class="event__container__countdown" color="light" [innerHTML]="timeUntil(event.dateTime)"></div>
        <div class="event__container__details">
            ...
        </div>
    </ion-card>
</ion-content>

Accompanied with the TypeScript implementation:

export class HomePage {
    constructor(...) {
        this.getCurrentTime();
        setInterval(() => this.getCurrentTime(), 100);
    }

    getCurrentTime() {
        this.theTime = moment().format("h:mm a");
    }

    timeUntil(date) {
        var dur = moment.duration( moment(date).diff(moment()) );
        let yearsRemain = dur.years();
        let monthsRemain = dur.months();
        let daysRemain = dur.days();
        let hoursRemain = dur.hours();
        let minutesRemain = dur.minutes();
        let secondsRemain = dur.seconds();

        var dateArray = [
            yearsRemain,
            monthsRemain,
            daysRemain,
            hoursRemain,
            minutesRemain,
            secondsRemain
        ]

        for(var i = 0; i < dateArray.length; i++) {
            if(dateArray[i] > 0){
                var firstDur = dateArray[i] + this.typeOfTime(i, dateArray[i]);
                var secondDur = dateArray[i+1] !== 0 ? dateArray[i+1] + this.typeOfTime(i+1, dateArray[i+1]) : dateArray[i+2] + this.typeOfTime(i+2, dateArray[i+2]);
                return firstDur +  secondDur;
            } else if(dateArray[i] < 0) {
                return (dateArray[i] * (-1)) + this.typeOfTime(i, (dateArray[i] * (-1))) + " ago";
            } else {
                i++
            }
        }
    }

    typeOfTime(type, num) {
        var display;
        var plur = num === 1 ? "" : "s";
        switch(type) {
            case 0:
                display = "Year" + plur;
                break;
            case 1:
                display = "Month" + plur;
                break;
            case 2:
                display = "Day" + plur;
                break;
            case 3:
                display = "Hour" + plur;
                break;
            case 4:
                display = "Minute" + plur;
                break;
            case 5:
                display = "Second" + plur;
                break;
        }
        return display;
    }
}

Despite reviewing various answers, the concept still eludes me. Could someone provide further insights or guidance regarding this matter?

Answer №1

When dealing with Angular in development mode, it performs a double check on the variables' state. Consider switching to a production build to observe the differences, and be sure to address any code that is frequently changing to resolve this issue. It appears that the problem lies within your timeUntil function.

To switch to production mode, you can utilize the --prod flag, such as ionic run android --prod, which will incorporate enableProdMode().

Alternatively, you could manually add enableProdMode() to your main.ts file before the bootstrap call.

This approach should rectify the issue, although it may not be the most optimal solution.

Answer №2

After some trial and error, I managed to solve the problem at hand, although I'm still not entirely certain about the reason behind it.

In the section above, my approach involved using Angular to display a return value utilizing [innerHTML]. Strangely enough (the part that remains unclear), the data binding was unable to process a "return" value and instead required a simple variable input. Thus, I revised it from:

<div class="event__container__countdown" color="light" [innerHTML]="timeUntil(event.dateTime)"></div>

where the function timeUntil() employed a return statement as follows: return firstDur + secondDur;

to

<div class="event__container__countdown" color="light">
    {{timePrimary}} {{timePrimaryType}} {{timeSecondary}} {{timeSecondaryType}}
</div>

Here, I called my timeUntil() function within a setTimeout to ensure continuous execution, updating the variables accordingly.

timePrimary: number;
timePrimaryType: string;
timeSecondary: number;
timeSecondaryType: string;

constructor() {
    this.timeUntil(this.timeUntilValue);
    setInterval(_ => this.timeUntil(this.timeUntilValue));
}
timeUntil(date) {

    //...Variable declarations remain unchanged...

    for(var i = 0; i < dateArray.length; i++) {
        if(dateArray[i] > 0){
            this.timePrimary = dateArray[i];
            this.timePrimaryType = this.typeOfTime(i, dateArray[i]);
            this.timeSecondary = dateArray[i+1] !== 0 ? dateArray[i+1] : dateArray[i+2];
            this.timeSecondaryType = dateArray[i+1] !== 0 ? this.typeOfTime(i+1, dateArray[i+1]) : this.typeOfTime(i+2, dateArray[i+2]);
            break;
        } else if(dateArray[i] < 0) {
            this.timePrimary = dateArray[i] * (-1);
            this.timePrimaryType = this.typeOfTime(i, (dateArray[i] * (-1))) + " ago";
            break;
        } else {
            i++
        }
    }
}

Hence, in this scenario, assigning a value to a variable proved more effective than simply returning the value.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Support the Cause with Paypal Contributions on Angular/Bootstrap Website!

I'm currently in the process of developing a website using Angular and Bootstrap for a non-profit organization that will facilitate donations through Paypal. On the platform, users will have the option to select their donation frequency (Weekly, Mont ...

Updating the input value in a React application

With a list and an edit button, upon clicking the edit button, a new modal opens. How can I auto-populate the selected username email? The server-side response is {this.test.name}, where I provide him with the input value to auto-populate. However, when ...

Error Alert: The function split cannot be applied to params[item]

ERROR! The console is outputting a message stating that TypeError: params[item].split is not a function. I would greatly appreciate any assistance in resolving this issue. Understanding where I went wrong in tackling this problem would be the most benefici ...

What is the best way to implement nested iterations in Jade?

ul li a(href='') menu1 li a(href='') menu2 ul li a(href='') sub-menu2 li a(href='') menu3 ul li a(href=&apos ...

Issues arise when attempting to include the src attribute within the template tag in a Vuejs and Laravel project

After starting a project with Vuejs and Laravel using Laravel Mix, I encountered an issue. When attempting to split my component into separate files and load them in the .vue file as follows: <template src="./comp.html"></template> &l ...

Concealing tables with Jquery during PostBack in ASP.net

There have been some discussions about this, but I'm struggling to connect all the pieces. My question is related to dynamic tables for which I've created CSS classes. I use checkboxes and jQuery to hide different tables... However, after a postb ...

Multi-dimensional array: Include an extra array if the desired value is not located

I am currently working on a project that involves using Google tables to create a report based on data retrieved from my MYSQL Database. The issue I'm encountering is that there are 5 header values: ['Call Disposition', 'Answered' ...

Using Javascript regex to validate strings without any backslashes present in the text

Having an issue with a JavaScript regex that needs to comment out all <script> tags inside a <script> tag except the first one with the id "ignorescript". Here is a sample string to work with: <script id="ignorescript"> var test = & ...

The function $.post(...) is failing to detect the JSON content in the

I am attempting to send a POST request to the server using the following code: var body = { PatientAgeFilter: { CompareOperator: parseInt(self.patientAge()), MoreThanVal: { AgeSpecifier: 0, AgeValue: parseInt(se ...

How to Conceal Axis Label in an HTML5 Canvas Line Chart

Is there a way to hide the x-axis label from a line chart without hiding the y-axis label as well? I tried using scaleFontSize: 0,, but that ended up hiding both axis labels. I only want to hide the x-axis label. var lineOptions = { ///Boo ...

Try utilizing a distinct value for searching compared to the one that is shown in Material UI's Autocomplete feature for React in JavaScript

I'm currently utilizing the <AutoComplete /> component offered by Material UI. It prescribes the following organization for the options const options = [ { label: 'The Godfather', id: 1 }, { label: 'Pulp Fiction', id: 2 } ...

Displaying the Yii form directly on the page upon loading, rather than enclosed within a jQuery dialog box

After studying this yii wiki page, I encountered an issue where the form is supposed to appear within a jQuery dialog box, but it opens immediately when the page loads instead. Upon further investigation, I discovered that removing the success callback fr ...

Error thrown due to uncaught type mismatch in jQuery AJAX request

I am currently working on transferring Rails-generated json data into Google Maps markers on a map. However, I am still in the learning process of jQuery/JavaScript and trying to grasp the concepts. Unfortunately, I encountered a confusing error message i ...

Is it possible to enable typescript to build in watch mode with eslint integrated?

Can this be achieved without relying on webpack or other bundlers? Alternatively, is the only solution to have two separate consoles - one for building and another for linting? ...

Retrieving child class prototype from superclass

In my current project, I am working on implementing a base class method that shares the same logic across all child classes. However, I need this method to utilize specific variables from each child class. function A() {} A.prototype.foo = 'bar' ...

Is there a way to incorporate a dropdown feature into a search bar using Ant Design?

I'm currently working on a project that requires me to incorporate two drop-down menus inside the search box. Despite following the guidelines provided in the documentation (https://ant.design/components/input), I encountered a problem when trying to ...

Tips for hiding navigation items on mobile screens

I've been learning how to create a hamburger menu for mobile devices. Within a navigation structure, I have three components: Logo, nav-items, and hamburger menu. Utilizing flexbox, I arranged them side by side and initially hid the hamburger menu on ...

Trouble with the combining of values

Here is a function I have created: function GetCompleteAddress() { $('#<%=txtAddress.ClientID %>').val($('#<%=txtWhere.ClientID %>').val() + ', ' + $('#<%=txtCity.ClientID %>').val() + &apo ...

The sequence of event handler executions in JavaScript

When multiple event handlers are attached to the same event on the same elements, how does the system determine the order in which they are executed? Although I came across this thread that focuses on click events, another discussion at this page points o ...

Managing redundant asynchronous data in AngularJS

Imagine this scenario: In your AngularJS application, a user is spamming input which triggers numerous asynchronous data calls on the backend. This results in constant changes to the displayed data as each fetch request completes. Ideally, we want the fina ...