1

I'm new to Angular, so apologies in advance for what I predict is a simple question. I'm trying to create a comments system for articles. I have two angular controllers, one to load the comments when the page is loaded, and another to submit a new comment to the server. These work fine, but in the success() method I'd like to update the displayed comments to show the new comment. However, my code at present doesn't work and no method I've tried seems to fix it. Could I get some help please?!

I know this is probably to do with different $scope variables, but none of the documentation I've read seems to make this clear.

article.js

// create app
var articleApp = angular.module('articleApp', ['btford.markdown', 'ngSanitize']);
// create controller
articleApp.controller('DisplayCommentsCtrl', function ($scope, $http) {
    $scope.loadComments =   function () {
        $http.get(Routing.generate('article_comments', { id: window.articleId })).success(function (data) {
            $scope.comments = data.comments;
        });
    };
    $scope.loadComments();
});

articleApp.controller('SubmitCommentCtrl', function ($scope, $http, $route) {
    $scope.loadComments = function () {
        $http.get(Routing.generate('article_comments', { id: window.articleId })).success(function (data) {
            $scope.comments = data.comments;
        });
    };
    $scope.loadComments();

    $scope.formData = {
        'comment':{
            'save'      :   'Save',
            'comment'   :   '',
            '_token'    :   $('#comment__token').val()
        }
    };
    $scope.processForm = function ($route) {
        $http({
            method  :   'POST',
            url     :   Routing.generate('article_new_comment', { id: window.articleId }),
            data    :   $.param($scope.formData),
            headers :   {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        })
        .success(function (data, $route) {
            $route.reload();
        });
    };
});

article.html.twig

<div class="col-md-12">     
    <div class="commentFormContainer" ng-controller="SubmitCommentCtrl">
        {% verbatim %}
        <p>{{ formData.comment.comment }} / {{ formData.comment._token }}</p>
        {% endverbatim %}
        <!--{{ form_start(commentForm, { 'attr': { 'id': 'commentForm', 'ng-submit':'processForm()' }}) }} -->
        <form name="comment" id="commentForm" ng-submit="processForm()">
            {{ form_errors(commentForm) }}
            {{ form_row(commentForm.comment, { 'attr': { 'ng-model': 'formData.comment.comment' } }) }}
            {{ form_widget(commentForm._token) }}
            {{ form_end(commentForm) }}
    </div>

    {% verbatim %}
    <div class="articleCommentContainer"  ng-controller="DisplayCommentsCtrl">
        <div ng-repeat="comment in comments | orderBy: '-time'">
            <div class="articleCommentComment" ng-bind-html="comment.commentHTML">              
            </div>
            <div class="articleCommentDetails">
                <p>[{{ comment.creator }} @ {{ comment.time|date:'EEE d MMM, h.mm a' }}]</p>
            </div>
        </div>
    </div>
    {% endverbatim %}
</div>
4
  • 2
    in that case you need to pass new comment data from SubmitCommentCtrl to DisplayCommentsCtrl, you can achieve this using angular broadcast event. stackoverflow.com/questions/14502006/… Commented Jun 25, 2015 at 13:44
  • Take a look at here Commented Jun 25, 2015 at 13:56
  • Try $window.location.reload(); or Use broadcast or emit from submit controller and on from Display Controller Commented Jun 25, 2015 at 14:12
  • Thanks for the help all! I've added an answer describing how I got to the solution below. Dom :-) Commented Jun 26, 2015 at 17:47

1 Answer 1

1

Thanks to everyone who commented to help me out. I fixed this using event broadcasting - although not quite the solution I'd envisaged initially it works quite nicely. I've put the code below to explain.

In a nutshell...

Whereas previously I was trying to either reload one controller, DisplayCommentsCtrl, from another controller, SubmitCommentCtrl, or use a method which I'd defined in one controller in a different controller, I now use the angular event dispatcher in the $http.success() of SubmitCommentCtrl to trigger an event which I'm watching for in DisplayCommentsCtrl. I supply all the information needed to display the comment (which is returned as the data argument in the $http.success() as the argument for this event.

The method described above cuts out the problem of scope. My two controllers have totally different scopes, and so methods I'd defined in one couldn't be run in the other, and changing the value of a scope variable in one didn't affect the other. My SubmitCommentCtrl is now injected with $rootScope, from where I can use the method $rootScope.$broadcast(strEventName, mixedData) to broadcast to all child scopes. In DisplayCommentsCtrl I'm listening for this method using $scope.$on(strEventName, function (event, mixedData) { // do something }).

Hope this answer helps. For more information on scopes in angular, see here: https://docs.angularjs.org/guide/scope.

article.js

// create app
var articleApp                          =   angular.module('articleApp', ['btford.markdown', 'ngSanitize', 'ngAnimate']);

// controller to display comments
articleApp.controller('DisplayCommentsCtrl', function ($scope, $http) {
  // load comments method
  $scope.loadComments                   =   function () {
    $http.get(Routing.generate('article_comments', { id: window.articleId })).success(function (data) {
      $scope.comments                   =   data.comments;
    });
  };
  $scope.loadComments();

  // in case there's a new comment
  $scope.$on('newComment', function (event, newComment) {
    $scope.comments.push(newComment);
  });

});

// controller to submit a new comment
articleApp.controller('SubmitCommentCtrl', function ($scope, $rootScope, $http) {
  $scope.loadComments                   =   function () {
    $http.get(Routing.generate('article_comments', { id: window.articleId })).success(function (data) {
      $scope.comments                   =   data.comments;
    });
  };
  $scope.loadComments();

  $scope.formData                       =   {
    'comment':{
      'save'        :   'Save',
      'comment' :   '',
      '_token'  :   $('#comment__token').val()
    }
  };
  $scope.processForm                    =   function ($route) {
    $http({
      method    :   'POST',
      url       :   Routing.generate('article_new_comment', { id: window.articleId }),
      data  :   $.param($scope.formData),
      headers   :   {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
      })
    .success(function (data) {
      // add the new comment below the form
      $rootScope.$broadcast('newComment', data);
      // empty the form
      $scope.formData.comment.comment   =   '';
    });
  };
});
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.