Skip to content

bug: IonCheckbox Angular standalone - Cannot redefine property 'checked' in component #28418

Description

@PatrikHorvatic

Prerequisites

Ionic Framework Version

v7.x

Current Behavior

Each time I try to enter the page, an error occoures from IonCheckbox Angular standalone component.
Error text:

core.mjs:10614 ERROR TypeError: Cannot redefine property: checked 
    at Function.defineProperty (<anonymous>)
    at ionic-angular-standalone.mjs:210:16
    at Array.forEach (<anonymous>)
    at proxyInputs (ionic-angular-standalone.mjs:209:12)
    at IonCheckbox.ngOnInit (ionic-angular-standalone.mjs:2114:9)
    at callHookInternal (core.mjs:4024:14)
    at callHook (core.mjs:4051:13)
    at callHooks (core.mjs:4006:17)
    at executeInitAndCheckHooks (core.mjs:3956:9)
    at selectIndexInternal (core.mjs:11780:17)

ion-checkbox-angular-standalone-error

I am still using NgModules and have followed tutorial how to implement standalone components in Ionic Angular project. I am using Ionic standalone components in entire project and they are working properly except IonCheckbox.

Expected Behavior

An error should not have happened.

Steps to Reproduce

1. Create CompleteProfileCompletenesItemComponent with proper inputs:

import { ChangeDetectionStrategy, Component, Input } from '@angular/core';

@Component({
  selector: 'app-complete-profile-completenes-item',
  templateUrl: './complete-profile-completenes-item.component.html',
  styleUrls: ['./complete-profile-completenes-item.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class CompleteProfileCompletenesItemComponent {
  @Input({ required: true }) checked: boolean;
  @Input({ required: true }) title: string;
  @Input({ required: true }) percentage: number;
}
<div class="checkmark-title-container">
  <ion-checkbox aria-label="l" [checked]="checked" [disabled]="true" />
  <div class="inter fontSize14 lineHeight150 mainText ion-padding-start">
    {{title}}
  </div>
</div>
<div class="percentage-container inter fontSize16 lineHeight150"
  [ngClass]="{'mainText': checked, 'secondaryText': !checked}">
  +{{percentage}} %
</div>

2. Generate respective NgModule with proper standalone IonCheckbox component import:

import { NgClass } from '@angular/common';
import { NgModule } from '@angular/core';
import { IonCheckbox } from '@ionic/angular/standalone';
import { CompleteProfileCompletenesItemComponent } from './complete-profile-completenes-item/complete-profile-completenes-item.component';
import { CompleteProfileCompletenesTitleComponent } from './complete-profile-completenes-title/complete-profile-completenes-title.component';

@NgModule({
    declarations: [CompleteProfileCompletenesItemComponent, CompleteProfileCompletenesTitleComponent],
    imports: [NgClass, IonCheckbox],
    exports: [CompleteProfileCompletenesItemComponent, CompleteProfileCompletenesTitleComponent],
})
export class CompleteProfileComponentsModule {}

3. Create page in which CompleteProfileCompletenesItemComponent from step 1 occoures:
TS (for reproduction purposes you can remove ActiveUserService. I have commented lines where Boolean value is determined in ngOnInit method) :

  • ProfileCompletenes type
export type ProfileCompletenes = {
    language: IJezici;
    percentage: number;
    checked: boolean;
};

PAGE:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { logError } from 'src/app/Functions/decorators';
import { IJezici, NAVIGATION_SIDE_MENU_LANGUAGE, NAVIGATION_SIDE_MENU_PROFILE_COMPLETENES_LANGUAGE, SIDE_MENU_PAGES_LANGUAGE, TOAST_MESSAGES } from 'src/app/Language/language';
import { RouterHistoryService } from 'src/app/Services/Other/router-history.service';
import { ActiveUserService } from 'src/app/Services/RegLog/active-user.service';
import { ProfileCompletenes } from 'src/app/Types/types';

@Component({
  selector: 'app-side-menu-complete-profile',
  templateUrl: './side-menu-complete-profile.page.html',
  styleUrls: ['./side-menu-complete-profile.page.scss'],
})
export class SideMenuCompleteProfilePage implements OnInit {

  public zadnjaStranica: string;
  protected LANGUAGE: IJezici = NAVIGATION_SIDE_MENU_LANGUAGE[18];
  protected LANGUAGE_PAGE = SIDE_MENU_PAGES_LANGUAGE.COMPLETE_PROFILE;
  protected TOAST_MESSAGES = TOAST_MESSAGES;
  protected LANGUAGE_TITLE = NAVIGATION_SIDE_MENU_PROFILE_COMPLETENES_LANGUAGE;

  protected profileCompletenesList: Array<ProfileCompletenes>;
  protected calculatedPercentage: number;

  constructor(public activeUser: ActiveUserService,
    private router: Router,
    private routerHisotry: RouterHistoryService) {
    this.zadnjaStranica = this.routerHisotry.vratiZadnjuStranicu();
  }

  @logError
  ngOnInit() {
    let socials = false;
    // Ako se radi o čistom null-u
    if (this.activeUser.profileData.socials === null) {
      socials = false;
    }
    else if (typeof this.activeUser.profileData.socials === 'object') {
      for (const social of Object.keys(this.activeUser.profileData.socials)) {
        if (this.activeUser.profileData.socials[social]) {
          socials = true;
          break;
        }
      }
    }
    else {
      socials = false;
    }

    this.profileCompletenesList = [
      {
        language: this.LANGUAGE_PAGE.FIRST_NAME,
        percentage: 5,
        // checked: Boolean(this.activeUser.userAuthenticationData.first)
        checked: true

      },
      {
        language: this.LANGUAGE_PAGE.LAST_NAME,
        percentage: 5,
        // checked: Boolean(this.activeUser.userAuthenticationData.last)
        checked: true

      },
      {
        language: this.LANGUAGE_PAGE.ABOUT_ME,
        percentage: 10,
        // checked: Boolean(this.activeUser.profileData.description)
        checked: true

      },
      {
        language: this.LANGUAGE_PAGE.BIRTHDAY,
        percentage: 5,
        // checked: Boolean(this.activeUser.profileData.dob)
        checked: true

      },
      {
        language: this.LANGUAGE_PAGE.EXPERIENCE,
        percentage: 10,
        // checked: Boolean(this.activeUser.profileData.experiences && this.activeUser.profileData.experiences.length > 0)
        checked: true

      },
      {
        language: this.LANGUAGE_PAGE.EDUCATION,
        percentage: 10,
        // checked: Boolean(this.activeUser.profileData.educations && this.activeUser.profileData.educations.length > 0)
        checked: true

      },
      {
        language: this.LANGUAGE_PAGE.CERTIFICATION,
        percentage: 10,
        // checked: Boolean(this.activeUser.profileData.licenses && this.activeUser.profileData.licenses.length > 0)        
        checked: true
      },
      {
        language: this.LANGUAGE_PAGE.SKILLS,
        percentage: 10,
        // checked: Boolean(this.activeUser.profileData.skills && this.activeUser.profileData.skills.length > 0)
        checked: true

      },
      {
        language: this.LANGUAGE_PAGE.LANGUAGES,
        percentage: 10,
        // checked: Boolean(this.activeUser.profileData.languages && this.activeUser.profileData.languages.length > 0)
        checked: true

      },
      {
        language: this.LANGUAGE_PAGE.INTERESTS,
        percentage: 5,
        // checked: Boolean(this.activeUser.profileData.interests && this.activeUser.profileData.interests.length > 0)
        checked: true
      },
      {
        language: this.LANGUAGE_PAGE.SOCIAL_NETWORKS,
        percentage: 5,
        // checked: socials
        checked: true

      },
      {
        language: this.LANGUAGE_PAGE.PROFILE_PHOTO,
        percentage: 10,
        // checked: Boolean(this.activeUser.userProfilePicture)
        checked: true

      },
      {
        language: this.LANGUAGE_PAGE.BACKGROUND_PHOTO,
        percentage: 5,
        // checked: Boolean(this.activeUser.userCoverPicture)
        checked: true
      },
    ];
    this.calculatedPercentage = this.calculatePercentage();
  }

  @logError
  goBack() {
    this.routerHisotry.izbaciZadnjuStranicu();
    if (this.zadnjaStranica.startsWith('/company/ads/ad-matches')) {
      const parametri = new URLSearchParams(this.zadnjaStranica.split('?')[1]);

      this.router.navigate(['/company/ads/ad-matches'],
        {
          queryParams: {
            adId: parametri.get('adId'),
            adTitle: parametri.get('adTitle')
          }
        });
    }
    else {
      this.router.navigate([this.zadnjaStranica]);
    }
  }

  @logError
  private calculatePercentage(): number {
    return this.profileCompletenesList.reduce((acc, obj) => obj.checked ? acc + obj.percentage : acc, 0);
  }
}

HTML:

<ion-content [scrollY]="false">
  <app-side-menu-page-header [title]="LANGUAGE_TITLE.TEXT | language" (goBack)="goBack()" />
  <div class="scrollable-content" style="padding: 5px 24px env(safe-area-inset-bottom) 24px">
    <p class="inter mainText fontSize13 lineHeight150">{{LANGUAGE_PAGE.EXPLANATION | language}}</p>
    <app-complete-profile-completenes-title [title]="LANGUAGE_TITLE.TEXT | language" [image]="activeUser.userProfilePicture ? 
    activeUser.userProfilePicture.base64image : 
    '../../../assets/imgs/logo-small.png' " [percentage]="calculatedPercentage" />

    <app-complete-profile-completenes-item *ngFor="let item of profileCompletenesList; let last=last"
      [checked]="item.checked" [title]="item.language | language" [percentage]="item.percentage"
      [style]="'border-bottom:'+ (last ? '0 !important' : '2px solid #f7f7f7') " />
  </div>

</ion-content>

4. Try to enter the page:
this.router.navigate(['/user/side-complete-profile']);
As I try to navigate to this route, an error occoures.

Code Reproduction URL

No response

Ionic Info

Ionic:
Ionic CLI: 7.1.1 (C:\Users\patrik.horvatic\AppData\Roaming\npm\node_modules@ionic\cli)
Ionic Framework: @ionic/angular 7.5.2
@angular-devkit/build-angular: 16.2.8
@angular-devkit/schematics: 16.2.8
@angular/cli : 16.2.8
@ionic/angular-toolkit: 10.0.0

Capacitor:
Capacitor CLI: 5.5.1
@capacitor/android: 5.5.1
@capacitor/core: 5.5.1
@capacitor/ios: 5.5.1

Utility:
cordova-res : 0.15.4
native-run : 1.7.3

System:
NodeJS : v18.12.0 (C:\Program Files\nodejs\node.exe)
npm : 9.6.6
OS : Windows 10

Additional Information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug: externalBugs in non-Ionic software that impact Ionic apps (I.e. WebKit, Angular, Android etc)type: buga confirmed bug report

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions