MarWinProg
MarWinProg

Reputation: 23

Angular - ERROR TypeError: Cannot read property

I am trying to get data(JSON) from the server and display on the web only after I click on the button. After the first click, I get an error:

core.js:4352 ERROR TypeError: Cannot read property 'imie' of undefined
    at HttpTestComponent.get (http-test.component.ts:28)
    at HttpTestComponent_Template_button_click_6_listener (http-test.component.html:6)
    at executeListenerWithErrorHandling (core.js:15214)
    at wrapListenerIn_markDirtyAndPreventDefault (core.js:15249)
    at HTMLButtonElement.<anonymous> (platform-browser.js:582)
    at ZoneDelegate.invokeTask (zone-evergreen.js:399)
    at Object.onInvokeTask (core.js:27474)
    at ZoneDelegate.invokeTask (zone-evergreen.js:398)
    at Zone.runTask (zone-evergreen.js:167)
    at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:480)

After the Second click it's works. Where is the problem?

service file

export class LoginService {
      private url = 'http://localhost:8080/test';
      constructor(private http:HttpClient) {
      }
          getTest(): Observable<IPerson>{
    
        return this.http.get<IPerson>(this.url);
        
      }
    }

component file

export class HttpTestComponent implements OnInit{

  private record:IPerson;
  name: string="aaaa";
  surname: string="bbbb";
  constructor(private loginService: LoginService) { }

  get(){
       this.loginService.getTest().subscribe((data:IPerson)=>this.record = data);
        this.name = this.record.imie;
        this.surname = this.record.nazwisko;
  }
  ngOnInit(): void {
  }

}

IPerson class

export class IPerson implements Person{

  _imie: string;
  _nazwisko: string;

  get imie(): string {
    return this._imie;
  }

  get nazwisko(): string {
    return this._nazwisko;
  }
}

template

<p>http-test works!</p>

<h1>{{name}}</h1>
<h1>{{surname}}</h1>

<button class="btn-large" (click)="get()">Dane</button>

Upvotes: 0

Views: 950

Answers (2)

choz
choz

Reputation: 17858

The issue is in this line;

this.loginService.getTest().subscribe((data:IPerson)=>this.record = data);

Now, .subscribe is a method of Observable type, and quoting here;

Observables are declarative—that is, you define a function for publishing values, but it is not executed until a consumer subscribes to it. The subscribed consumer then receives notifications until the function completes, or until they unsubscribe.

Based on your code, it seems that your Observable is to perform http GET request on user. Now, moving to the next line;

this.name = this.record.imie;

This is the code that throws the error, because when this line gets executed this.record is still undefined since you assign this.record in the observable callback.

One of the approach is to wrap the code after observable runs your callback;

this.loginService.getTest().subscribe((data:IPerson) => 
    this.record = data;
    this.name = this.record.imie;
    this.surname = this.record.nazwisko;
);

Other approach is to encapsulate your function with async/await, based on your code - perhaps it would be like (Following code is not tested);

// In your service
getTest() : Promise<any> {
   const response = this.http.get(this.url).toPromise();
   return response.json(); // Not sure if this is needed.
}

// Component
async getUser() {
   const record = await this.loginService.getTest();
   this.name = record.imie;
   this.surname = record.nazwisko;
}

Upvotes: 1

Timothy
Timothy

Reputation: 3593

This is because getTest() is async, you need to fetch props inside subscriber, otherwise record is undefined

get(){
 this.loginService.getTest().subscribe((data:IPerson)=> {
  this.record = data;
  this.name = this.record.imie;
  this.surname = this.record.nazwisko;
 });
}

Upvotes: 1

Related Questions