How to use compile function in AngularJS directive

2019-07-08 11:09发布

问题:

Could someone, please, show me what I need to do to render in a directive new elements stored in an array in a service. In the example below, an alert from the service shows that each new element is added to the elements array, but how to make the directive show these new elements on the page?

I tried to read everything about compile function in a directive, but could not understand how to make my example work.

Here is a jsfiddle. All I need is to render new messages inside the directive after they are added to the message array in the service.

The Chat service is injected into directive as a chat variable, and in the directive template I want to repeat every message from the service:

'<ul>' +
     '<li ng-repeat="message in chat.messages">' +
          '<strong>{{message.name}}</strong> {{message.text}}' +
      '</li>' +
'</ul>'

Sample code is on jsfiddle and below:

HTML:

<div ng-app="myApp">
<my-simple-chat title="AngularJS Chat"></my-simple-chat>
</div>

JavaScript:

angular.module('myApp', [])
.factory('Chat', function () {
    var messages = [];
    function sendMessage(name, text) {
        messages.push(
            {
                name: name,
                text: text
            });
        alert("Sending message from factory: " + name + ", " + text + " : " + messages.length);       
    };

    return {
        messages: messages,
        sendMessage: sendMessage
    };

})
.directive('mySimpleChat', ['Chat', function (chat) {

    var tmpl = '<div><h2>{{title}}</h2>' +
                    '<input type="text" ng-model="name" placeholder="Type your name"/>' +
                    '<hr />' +
                    '<form ng-submit="sendMessage()">' +
                        '<input type="text" ng-model="text" required placeholder="Type a new message..."/>' +
                        '<input type="submit" id="submit" value="Send"/>' +
                    '</form>' +
                        '<ul>' +
                            '<li ng-repeat="message in chat.messages">' +
                                '<strong>{{message.name}}</strong> {{message.text}}' +
                            '</li>' +
                        '</ul>' +
                '<div>';

    return {
        restrict: 'E',
        replace: true,
        scope: { title: '@title' },
        template: tmpl,

        controller: ['$scope', '$element', '$attrs', '$transclude',
          function ($scope, $element, $attrs, $transclude) {
              $scope.name = 'MyName';
              $scope.text = '';

              $scope.sendMessage = function () {
                  chat.sendMessage($scope.name, $scope.text);
                  $scope.text = '';

              };

          }],

    };
}]);

回答1:

You are using ngRepeat on chat.messages but never assigning chat to be part of $scope.

    controller: ['$scope', '$element', '$attrs', '$transclude',
      function ($scope, $element, $attrs, $transclude) {
          $scope.name = 'MyName';
          $scope.text = '';
          $scope.chat = chat;  //<--this so you can use ngRepeat
          $scope.sendMessage = function () {
              chat.sendMessage($scope.name, $scope.text);
              $scope.text = '';

          };

      }],

updated fiddle.



回答2:

Looks like writing a question on SO is 90% way to its answer... All I needed to do was to add a link function to the directive:

link: function ($scope, element, attributes) {
    $scope.messages = chat.messages;
}

and remove chat. from ng.repeat:

'<ul>' +
     '<li ng-repeat="message in messages">' +
          '<strong>{{message.name}}</strong> {{message.text}}' +
      '</li>' +
'</ul>'

I am not sure that this is the right way to do the task, but it just works. In docs I have read that I have to use compile function if I use ng-repeat in a template, so I am still confused somewhat.

An updated jsfiddle.



回答3:

You can create a bridge like this:

<li ng-repeat="message in messages()">

$scope.messages = function () {
    return chat.messages;
}