Peter Boomsma
Peter Boomsma

Reputation: 9806

TypeError: Cannot read property 'comments' of undefined using Angular

I'm following this tutorial When I try to post a comment on a post I get a TypeError: Cannot read property 'comments' of undefined error in my console.

the mainCtrl,

.controller('mainCtrl', ['$scope', 'posts',
  function($scope, posts){
    $scope.posts = posts.posts;

  $scope.addPost = function(){
    if(!$scope.title || $scope.title === '') { alert("Field can't left blank"); return; }

    $scope.posts.push({
      title: $scope.title,
      upvotes: 0,
      comments: [
        {author: 'Joe', body: 'Cool post!', upvotes: 0},
        {author: 'Bob', body: 'Great idea but everything is wrong!', upvotes: 0}
      ]
    });
  };
  }
])

and the postCtrl,

.controller('PostsCtrl', ['$scope', '$stateParams', 'posts',
  function($scope, $stateParams, posts){
    $scope.post = posts.posts[$stateParams.id];

    $scope.addComment = function(){
      if($scope.body === '') { return; }
      $scope.post.comments.push({
        body: $scope.body,
        author: 'user',
        upvotes: 0
      });
      $scope.body = '';
    };

  }
])

Both controllers are in mainCtrl.js.

And here are my home.html and post.html partials which are being included through router-ui.

%script{:id => "/home.html", :type => "text/ng-template"}
  %h1
    Flappernews

  %a{:href => "#/posts/{{$index}}"} Comments

%script{:id => "/posts.html", :type => "text/ng-template"}
  %h2
    Below here should be comments
  %span
    {{ post.comments }}
  %div{"ng-repeat" => "comment in post.comments | orderBy:'-upvotes'"}
    {{comment.upvotes}} - by {{comment.author}}
    %span{:style => "font-size:20px; margin-left:10px;"}
      {{comment.body}}

  %form{"ng-submit" => "addComment()"}
    %h3 Add a new comment
    .form-group
      %input.form-control{"ng-model" => "body", :placeholder => "Comment", :type => "text"}
    %button.btn.btn-primary{:type => "submit"} Post

When I visit the homepage I get redirected to localhost:3000/#/home I can then enter a title and post it. When I click on the comments link I get redirected to http://localhost:3000/#/posts/ and when I try to post a comment I get the

TypeError: Cannot read property 'comments' of undefined at Scope.$scope.addComment error.

Upvotes: 6

Views: 6459

Answers (4)

Zainul Abdin
Zainul Abdin

Reputation: 835

You have defined two separate controllers, don't need to do that. If you look at that tutorial again you will see that addPost and addComment functions are inside single controller like this

   .controller('PostsCtrl', [
    '$scope',
    '$stateParams',
    'posts',
    function($scope, $stateParams, posts){

    // Fetch post object from state parameter.
    $scope.post = posts.posts[$stateParams.id];

    // Add Post.
    $scope.posts.push({
      title: $scope.title,
      link: $scope.link,
      upvotes: 0,
      comments: [
        {author: 'Joe', body: 'Cool post!', upvotes: 0},
        {author: 'Bob', body: 'Great idea but everything is wrong!', upvotes: 0}
      ]
    });

    // Add comment.
    $scope.addComment = function(){
      if($scope.body === '') { return; }
      $scope.post.comments.push({
        body: $scope.body,
        author: 'user',
        upvotes: 0
      });
      $scope.body = '';
    };

    }]);

add post and comment works on single Post object where comments property is pre defined.

Upvotes: 1

gafi
gafi

Reputation: 12749

Since I cannot debug the code so I'll try to list all possible reasons and you can confirm which is true for your case

  1. Make sure the new post is pushed to the posts service correctly.

Place a breakpoint after the $scope.posts.push and log posts.posts to make sure the new object is added to the array

  1. Make sure the PostsCtrl has the same posts.posts array with the new post added.

  2. Make sure $stateParams.id is actually a valid index for the posts.posts array

I hope this helps. If not, make a comment with the results.

Upvotes: 0

Vidyadhar
Vidyadhar

Reputation: 1118

In your 'mainCrtl', you are not saving/adding new post data to your 'posts' object but added to '$scope.posts' so its reflecting in your page with comment link (let's say your newly created post id is 'x' ).

And when you are clicking on comments link, and trying to check the data which is not added before to your 'posts' object ie.., posts[x] is undefined (you have not added id 'x' data in maincrtl).

Hope I have Answered your question.

Upvotes: 0

Mohan Singh
Mohan Singh

Reputation: 883

I am sure there is reference link issue. $scope.posts = posts.posts; only should be used to access the posts object. CURD operation should be performed on service directly.

$scope.posts would get automatically changed because there is a reference link between $scope.posts and posts.

Please make below change. Hope it should work.

    $scope.addPost = function () {
      if (!$scope.title || $scope.title === '') {
          alert("Field can't left blank");
          return;
      }

      posts.posts.push({
          title: $scope.title,
          upvotes: 0,
          comments: [{
              author: 'Joe',
              body: 'Cool post!',
              upvotes: 0
          }, {
              author: 'Bob',
              body: 'Great idea but everything is wrong!',
              upvotes: 0
          }]
      });
  };

now you are able to share data between different controllers. Same should be done while adding comment.

Important part :

you can not get post like posts.posts[$stateParams.id]; This will match the index of array and return the object.

angular.forEach(posts.posts, function (post) {
    if (post.id === parseInt($stateParams.id)) {
        $scope.post = post;
        return;
    }

})

Hope this will help you.

Upvotes: 0

Related Questions