Boaris
Boaris

Reputation: 5226

Angular HttpClient subscribe cannot read property 'name' of undefined

I have the following component and service:
Component

@Component({
  selector: 'app-root',
  template: '{{user.name}}',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {

  user: User;

  constructor(private userService: UserService) {
    this.userService.get().subscribe(user => {
      this.user = user;
    });
  }

}

Service

@Injectable()
export class UserService {
  constructor(private http: HttpClient) {
  }

  get(): Observable<User> {
    return this.http.get<User>('http://www.mocky.io/v2/5cc0af9a310000440a0364b6');
  }
}

User

export class User {
  constructor(
    public name: string
  ) {
  }
}

As you can see, I'm just trying to print the user's name. It works, but before it prints the value I receive Cannot read property 'name' of undefined error several times.
I know the reason — I load the user asynchronously, but how to deal with it?
I found the safe operator:

{{user?.name}}

And it works. But in my real project this approach will not work everywhere.
I also tried to use ngIf:

<div *ngIf="user">
  {{user.name}}
</div>

But this will break another part of my app.
Is there a way to render a component after an HTTP call, so that I don't have to use Safe Operator or ngIf? If not, then what approach do you use? How do you deal with this problem?

Upvotes: 1

Views: 328

Answers (4)

NhutLe
NhutLe

Reputation: 95

You don't need create a DTO for this case:

  get(): any{
return this.http.get<User>('http://www.mocky.io/v2/5cc0af9a310000440a0364b6');

}

Upvotes: 0

Saksham
Saksham

Reputation: 9380

If you mean to say that by introducing another extra div in your template will break the CSS, you can use ng-container element and have *ngIf in that as

<ng-container *ngIf="user">{{user}}</ng-container>

According to the definition

The Angular is a grouping element that doesn't interfere with styles or layout because Angular doesn't put it in the DOM.

Upvotes: 0

Ali Adravi
Ali Adravi

Reputation: 22723

Your code looks correct, change your user class to interface:

export interface User {
  name: string;
}

Or if you want to use the class, change it to:

export class User {
  name: string;
}

You current code:

export class User {
  constructor( public name: string) {
  }
}

Means property will be created only when the constructor will be called, and that will only be called when you will try to create the object by using new:

user = new User();

Upvotes: 0

Hien Nguyen
Hien Nguyen

Reputation: 18975

You can prevent it by create default User object

export class AppComponent {

  user = new User('');

}

Upvotes: 0

Related Questions