The Dead Man
The Dead Man

Reputation: 5576

ERROR TypeError: Cannot read property of undefined

I have app in Angular 6 , user can follow, like, dislike etc . I am trying to save the data to the server via a post method.

When the user clicks eg follow I get the following error:

UserProfileComponent.html:27 ERROR TypeError: Cannot read property 'followers' of undefined
    at UserProfileComponent.push../src/app/user-profile/user-profile.component.ts.UserProfileComponent.followButtonClick (user-profile.component.ts:46)
    at Object.eval [as handleEvent] (UserProfileComponent.html:27)
    at handleEvent (core.js:19324)
    at callWithDebugContext (core.js:20418)
    at Object.debugHandleEvent [as handleEvent] (core.js:20121)
    at dispatchEvent (core.js:16773)
    at core.js:17220
    at HTMLButtonElement.<anonymous> (platform-browser.js:988)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)
    at Object.onInvokeTask (core.js:13842)

Here is json file in server:

{
  "statuses": [{
    "id": 1,
    "statusId": 2,
    "likes": 121,
    "following": 723,
    "followers": 4433
  }]
}

Here is service I have :

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import {Status } from '../model/statuses.model';
import { Comment } from '../model/comments.model';

@Injectable({
  providedIn: 'root'
})
export class UserService {
  status: Status[];
  constructor(private http: HttpClient) { }
  statusUrl = 'http://localhost:3000/statuses';
  commentsUrl = 'http://localhost:3000/comments';

  getStatuses() {
    return this.http.get<Status[]>(this.statusUrl);
  }

  addStatus(status: Status) {
   return this.http.patch(this.statusUrl, status);
  }

  addComments(comment: Comment) {
    return this.http.post(this.commentsUrl, comment);
  }

}

Here is component ts

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { UserService } from '../service/user.service';
import { Status } from '../model/statuses.model';
import { Comment } from '../model/comments.model';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-user-profile',
  templateUrl: './user-profile.component.html',
  styleUrls: ['./user-profile.component.scss']
})
export class UserProfileComponent implements OnInit {
  status: Status[];
  comment: Comment[];
  numberOflikes = 121;
  numberOffollowing = 723;
  numberOffollowers = 4433;

  constructor(
    private formBuilder: FormBuilder,
    private http: HttpClient,
    private userService: UserService
  ) {}

  addForm: FormGroup;

  ngOnInit() {
    this.addForm = this.formBuilder.group({
      id: [],
      name: ['', Validators.required],
      city: ['', Validators.required],
      description: ['', Validators.required],
    });

    this.userService.getStatuses()
      .subscribe(data => {
        this.status = data;
        console.log(data);
      });
  }

  addComments() {
    this.userService.addComments(this.addForm.value)
      .subscribe(data => {
        this.comment.push(this.addForm.value);
      });
  }

  followButtonClick(statusId) {
    this.status[statusId].followers++;
    this.persistStatus(this.status[statusId]);
  }

  persistStatus(status) {
    this.userService.addStatus(status);
  }

}

Here is html

Harvey Specter

New York USA
      </div>
      <ul class="profile_card-bottom" *ngFor="let stat of status">
        <li class="likes">
          <span class="assets-count">{{stat.followers}}</span>
          <span class="assets-title">Likes</span>
        </li>
        </ul>
</div>

Here is model for status

export class Status {
    id: number;
    statusId: number;
    like: number;
    following: number;
    followers: number;
}

What am I doing wrong in my code?

Upvotes: 0

Views: 7577

Answers (4)

Artyom Amiryan
Artyom Amiryan

Reputation: 2966

as I see you did not pass argument to your followButtonClick() method in html, so move your button in your *ngFor loop and pass stat.id as mentioned @selemmn

<h1>
 Harvey Specter
 <span class="heart reaction">
  <i class="fa fa-heart heart" aria-hidden="true"(click)="followButtonClick(stat.id)"></i>
 </span>
</h1>

and also change your followButtonClick() method to this

followButtonClick(statusId) { 
 const statusToUpdate = this.status.filter(status => status.id === statusId)[0]; 
 statusToUpdate.followers++; 
 this.persistStatus(statusToUpdate); 
}

so as you didn't pass argument your statusId is undefined in followButtonClick() so it tries to get this.status[undefined].followers++; and throws error that can't find property followers of undefined

Upvotes: 1

SeleM
SeleM

Reputation: 9678

You pass nothing as a parameter in the HTML part then based on the same function but with a parameter you proceed in the TS part.

Change this line to :

<button class="btn-follow" (click)="followButtonClick(stat.id)">Follow</button>

PS: Assuming it's named id of course.

Upvotes: 1

arkoak
arkoak

Reputation: 2497

The problem seems that your userService is sending empty data, this empty data then loads into the status array. This should not happen.

You can either handle it in the userService (preferrably , which should b the code hosted at http://localhost:3000/statuses ) If you have no control on server side, you can fix their mistake when calling this.userService.getStatuses() to check if the data is valid object and not an empty one.

Upvotes: 0

SiddAjmera
SiddAjmera

Reputation: 39482

Even though this.status is an array, there's no gurantee that the index of a status and it's statusId will be the same. So you might be getting an index that doesn't exist in your status array and hence the undefined error

Try changing the implememtation of followButtonClick(statusId) like this:

followButtonClick(statusId) {
  const statusToUpdate = this.status.filter(status => status.statusId === statusId)[0];
  statusToUpdate.followers++;
  this.persistStatus(statusToUpdate);
}

Upvotes: 0

Related Questions