Magor Menessy
Magor Menessy

Reputation: 413

Ionic 3 - After data load ngModel undefined

I'm a bit of a beginner in angular 4... tried to search for this many times in the past few months, but got no result, even though it seems the most simple thing.

It's an ionic app. User logs in, the whole user object is saved to localStorage. Have tried several plugins, but went with simple:

window.localStorage.setItem('User', JSON.stringify(user));

user object structure:

export class User {
constructor(
    public token?: string,
    public user_email?: string,
    public email?: string,
    public first_name?: string,
    public last_name?: string,
    public user_roles?: {
        ID?: number,
        caps?: {
            administrator?: boolean,
        },
        roles?: object,
    },
    public id?: number,
    public device_feedback?: boolean,
    public role?: string,
    public username?: string,
    public billing?: Address,
    public shipping?: Address
) {}
}

export class Address {
    first_name?: string;
    last_name?: string;
    company?: string;
    address_1?: string;
    address_2?: string;
    city?: string;
    state?: string;
    postcode?: string;
    country?: string;
    email?: string;
    phone?: number   
}

settings.ts: (I have added ngOnInit and this.platform.ready(){} because thought data is not ready or something...)

export class Settings implements OnInit{
 [other vars]

 user: User;

 constructor(public storage: Storage, private platform: Platform) { }

ngOnInit() {
    // this.storage.ready().then(() => {
    // this.storage.get("User").then((data) => {
    this.platform.ready().then(() => {
        let data = window.localStorage.getItem('User');
        if (data) {
            this.user = JSON.parse(data);
            this.email = this.user.user_email;
            console.log('user', this.user);
            console.log('this.user.user_email', this.user.user_email);

        }
    });
}

Settings.html

<ion-content>
<ion-list padding>
    <ion-list-header>
        Title
    </ion-list-header>
    <ion-item>
        <ion-label color="primary" fixed>Email</ion-label>
        <ion-input class="in" type="email" [(ngModel)]="user.user_email" disabled="true"></ion-input>
    </ion-item>

The user_email is displayed in the console.log, referenced as this.user.user_email and same property gives an error in the HTML... how is this possible? Same in the browser or the device: http://prntscr.com/i8rfhg I have also tried with user: any, but got the same result...

How? Why? What am I missing?

Here's the ionic info:

@ionic/cli-utils  : 1.19.1
ionic (Ionic CLI) : 3.19.1

global packages:

cordova (Cordova CLI) : 7.1.0

local packages:

@ionic/app-scripts : 1.3.0
Cordova Platforms  : none
Ionic Framework    : ionic-angular 3.0.1

System:

Android SDK Tools : 25.2.5
Node              : v6.11.0
npm               : 5.6.0

Thanks a lot!

Upvotes: 2

Views: 1526

Answers (4)

Ange-Marie
Ange-Marie

Reputation: 1

I use export interface and class.

export interface UserCaps
        administrator: boolean;
}

export interface UserRole {
        ID: null;
        caps: UserCaps;
        roles: any;
}

export interface Address {
    first_name?: string;
    last_name?: string;
    company?: string;
    address_1?: string;
    address_2?: string;
    city?: string;
    state?: string;
    postcode?: string;
    country?: string;
    email?: string;
    phone?: number   
}

export interface User {public token: string;
    user_email: string;
    email: string;
    first_name: string;
    last_name: string;
    user_roles : UserRole;
    id: number;
    device_feedback: boolean;
    role: string;
    username: string;
    billing: Address;
    shipping: Address;
}

export class User {}

And i init my user with new Class()

user = new User();

Upvotes: 0

Martin Parenteau
Martin Parenteau

Reputation: 73721

In ngOnInit, the callback for this.platform.ready() is executed asynchronously. Before that, user is undefined and [(ngModel)]="user.user_email" causes an error.

You can prevent that error with the safe navigation operator. Since it works only for one-way data binding, you should split [(ngModel)] in its two parts, [ngModel] and (ngModelChange). In addition to that change, you can keep the input element disabled until user is initialized, to prevent entering data that will be lost anyway.

[ngModel]="user?.user_email" (ngModelChange)="setUserEmail($event)" [disabled]="!user"

with the component method:

setUserEmail(value: string): void {
  if (this.user) {
    this.user.user_email = value;
  }
}

The code is illustrated in this stackblitz, where the user object is initialized after a few seconds.

Upvotes: 1

thurgi
thurgi

Reputation: 36

you don't have instance of User in this.user.

export class User {
    public token: string;
    public user_email: string;
    public email: string;
    public first_name: string;
    public last_name: string;
    public user_roles : Object = {
        ID: null,
        caps: {
            administrator: false,
        },
        roles: {},
    };
    public id: number;
    public device_feedback: boolean;
    public role: string;
    public username: string;
    public billing: Address;
    public shipping: Address;

    public set(data:any){
        if(!data){
            return;
        }
        this.token = data.token;
        this.user_email = data.user_email;
        this.email = data.email;
        this.first_name = data.first_name;
        this.last_name = data.last_name;
        this.id = data.id;
        this.device_feedback = data.device_feedback;
        this.role = data.role;
        this.username = data.username;
        this.billing = data.billing;
        this.shipping = data.shipping;

        this.user_roles = data.user_roles;

    } }

and

export class Settings implements OnInit{  [other vars]

 user: User = new User(); constructor(public storage: Storage, private platform: Platform) { }

ngOnInit() {
    // this.storage.ready().then(() => {
    // this.storage.get("User").then((data) => {
    this.platform.ready().then(() => {
        this.user.set(window.localStorage.getItem('User'));

    });
}

Upvotes: 1

Uğur Din&#231;
Uğur Din&#231;

Reputation: 2455

You are trying to access the property user_email of your user object while it's null / before it's initialized.

Try:

user: User = {}; // initial value

Or:

<ion-list padding *ngIf="user">
    <ion-list-header>
        Title
    </ion-list-header>
    <ion-item>
        <ion-label color="primary" fixed>Email</ion-label>
        <ion-input class="in" type="email" [(ngModel)]="user.user_email" disabled="true"></ion-input>
    </ion-item>

Upvotes: 1

Related Questions