3

I'm trying to do a two-way binding between a 'user' variable and a form in the html template :

export class UsersComponent implements OnInit {

  user: User = {
    firstname: '',
    lastname: '',
    age: 0,
    adress: {
      street: '',
      city: '',
      state: ''
    }
  };
  ...

example from the form: (I don't want to paste a lot of code)

 ...
 <div class="form-group">
        <label for="street">Street Adress</label>
        <input
          type="text"
          class="form-control"
          [(ngModel)]="user.adress.street"
          name="street"
        />
 </div>
 ...

when I bind user.firstname, user.lastname or user.age it works: example :

          [(ngModel)]="user.age" //works

but when I try user.adress.street, user.adress.city, or user.adress.state id does not compile example :

          [(ngModel)]="user.adress.street" //does not work

but when I go to the interface User and I click save: the compilation works

export interface User{

    firstname: string;
    lastname: string;
    age?: number;

    adress?: {
        street?: string,
        city?: string,
        state?: string
    }

    active?: boolean;
    registered?: any;
    hide?: boolean;
}

and when I edit the ts or the html file and I save: it gives me a compilation error :

Failed to compile.

src/app/components/users/users.component.html:39:36 - error TS2532: Object is possibly 'undefined'.

39           [(ngModel)]="user.adress.street"
                                      ~~~~~~

  src/app/components/users/users.component.ts:7:16
    7   templateUrl: './users.component.html',
                     ~~~~~~~~~~~~~~~~~~~~~~~~
    Error occurs in the template of component UsersComponent.

I tried using

user?.adress?.street

but it didn't work

4 Answers4

2

Another solution is to check the content of object using *ngIf="user.adress.street", in this case, angular will wait for this object to be filled.

<div class="form-group">
  <label for="street">Street Adress</label>
  <input
          type="text"
          class="form-control"
          *ngIf="user.adress.street"
          [(ngModel)]="user.adress.street"
          name="street"
        />
</div>

If your object has many fields, it could be hard to do it in all objects on HTML. I this case you could create a div with *ngIf and put the content inside.

<div *ngIf="user.adress.street"> 
    ...
    <div class="form-group">
      <label for="street">Street Adress</label>
      <input
              type="text"
              class="form-control"
              [(ngModel)]="user.adress.street"
              name="street"
            />
    </div>
</div>

I hope it can help you

Marcus Menezes
  • 170
  • 2
  • 11
0

Angular binding mostly works on predefined types (string, number, any) or types that we are declaring explicitly such as interface. Now in code mentioned above class level variable is not declared properly either it must be a type of "any" or any interface. Please use the link mentioned below for verification.

Demo

-1

In your component.ts:

  user = new User("", "", 0, {
    street: "Test",
    city: "",
    state: ""
  });

After that create a class like this one:

export class User {
  firstname: string;
  lastname: string;
  age?: number;

  adress: {
    street?: string;
    city?: string;
    state?: string;
  };

  active?: boolean;
  registered?: any;
  hide?: boolean;
  constructor(firstname, lastname, age, adress) {
    this.firstname = firstname;
    this.lastname = lastname;
    this.age = age;
    this.adress = adress;
  }
}

At the end your Html template should be:

<div class="form-group">
  <label for="street">Street Adress</label>
  <input
          type="text"
          class="form-control"
          [(ngModel)]="user.adress.street"
          name="street"
        />
</div>

stackblitz link

-3

I fixed it, with a turnaround :

instead of using user.adress.street

I created a variable ' adress ' in the component

and in the template I used adress.street