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>
helmbert
  • 35,797
  • 13
  • 82
  • 95
Dom Weldon
  • 1,728
  • 1
  • 12
  • 24
  • 2
    in that case you need to pass new comment data from SubmitCommentCtrl to DisplayCommentsCtrl, you can achieve this using angular broadcast event. http://stackoverflow.com/questions/14502006/working-with-scope-emit-and-on – Gopinath Shiva Jun 25 '15 at 13:44
  • [Take a look at here](http://stackoverflow.com/questions/12008908/how-can-i-pass-variables-between-controllers) – ODelibalta Jun 25 '15 at 13:56
  • Try $window.location.reload(); or Use broadcast or emit from submit controller and on from Display Controller – Kumar Garapati Jun 25 '15 at 14:12
  • Thanks for the help all! I've added an answer describing how I got to the solution below. Dom :-) – Dom Weldon Jun 26 '15 at 17:47

1 Answers1

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   =   '';
    });
  };
});
Dom Weldon
  • 1,728
  • 1
  • 12
  • 24