如何评估child指令中的Angular表达式并在父指令中公开它?

时间:2014-12-06 08:48:53

标签: javascript angularjs angularjs-directive angularjs-ng-repeat

我有一个代表一组对象的指令,我们称之为people

该指令在其模板中有一个ng-repeat,它重复一个子指令,例如: person,其表达式属性personGreeting应评估其范围。

peopleperson都使用隔离范围。

如何设置这些指令,以便我可以在personGreeting指令上公开people并在person指令的范围内进行评估?

以下是一个例子:

angular.module('app', [])
  .controller('ctrl', function($scope) {
    $scope.myPeople = [{
      id: 1,
      name: 'Bob'
    }, {
      id: 2,
      name: 'Steve'
    }, {
      id: 3,
      name: 'Joe',
    }]
  })
  .directive('people', function() {
    return {
      scope: {
        peopleList: '=',
        eachPersonGreeting: '&'
      },
      template: '<ul><person ng-repeat="currentPerson in peopleList" person-greeting="eachPersonGreeting(currentPerson)"></person></ul>'
    }
  })
  .directive('person', function() {
    return {
      scope: {
        personDetails: '=',
        personGreeting: '&'
      },
      template: '<li>{{personGreeting(personDetails)}}</li>'
    }
  })
  .directive('people2', function() {
    return {
      scope: {
        peopleList: '=',
        eachPersonGreeting: '@'
      },
      template: '<ul><person-2 ng-repeat="currentPerson in peopleList" person-greeting="{{eachPersonGreeting}}"></person-2></ul>'
    }
  })
  .directive('person2', function() {
    return {
      scope: {
        personDetails: '=',
        personGreeting: '@'
      },
      template: '<li>{{personGreeting}}</li>'
    }
  })
<!DOCTYPE html>
<html ng-app="app">

<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>
</head>

<body ng-controller="ctrl">
  <h4>Here we are just using an in-line expression with ng-repeat, which works as you'd expect:</h4>
  <ul>
    <li ng-repeat="currentPerson in myPeople">Hello, {{currentPerson.name}}!</li>
  </ul>

  <h4>But what if we have custom directives, `people`, and `person`, and we want to let consumers of our `people` directive specify how each `person` should be greeted without making them override our directive's template, and also have data binding still work?</h4>

  <h4>Unfortunately, this doesn't seem to work:</h4>

  <people people-list="myPeople" each-person-greeting="'Welcome, ' + personDetails.name + '!'"></people>

  <h4>Neither does this:</h4>

  <people-2 people-list="myPeople" each-person-greeting="Welcome, {{personDetails.name}}!"></people-2>
</body>


</html>

我也开始深入研究这两个指令的编译,链接和控制器函数,以及$ interpolate服务,并使它有点工作,但它真的很奇怪和混乱,我无法得到数据绑定工作,所以感觉就像浪费了精力。我觉得这应该很简单,但似乎不是。

有优雅的方法吗?

2 个答案:

答案 0 :(得分:1)

好吧,我设法使用相同的概念组合了一个简单的留言簿应用程序:http://plnkr.co/edit/R7s6xE?p=info

&#13;
&#13;
angular.module('guestbookApp', [])
  .controller('guestbookCtrl', function($scope) {
    $scope.latestGuests = [{
      id: 1,
      name: 'Bob'
    }, {
      id: 2,
      name: 'Steve'
    }, {
      id: 3,
      name: 'Joe',
    }];
    $scope.newGuest = {
      name: ''
    };
    $scope.addGuest = function() {
      $scope.latestGuests.push(angular.extend(angular.copy($scope.newGuest), {
        id: $scope.latestGuests.length + 1
      }));
      $scope.newGuest.name = '';
    };
  })
  .directive('guestList', function($parse) {
    return {
      scope: {
        guests: '='
      },
      template: '<ul><li guest ng-repeat="currentGuest in guests | limitTo: -5" guest-details="currentGuest"></li></ul>',
      controller: function($scope, $element, $attrs) {
        this.greeting = function(scope) {
          return $parse($attrs.greeting)(scope);
        };
      }
    };
  })
  .directive('guest', function($parse) {
    return {
      scope: {
        guestDetails: '='
      },
      template: '{{greeting}}',
      require: '?^guestList',
      link: function(scope, element, attrs, controller) {
        var updateGreeting;
        if (controller) {
          updateGreeting = function() {
            scope.greeting = controller.greeting(scope);
          };
        } else if (attrs.greeting) {
          updateGreeting = function() {
            scope.greeting = $parse(attrs.greeting)(scope);
          };
        }
        scope.$watch('guestDetails.name', function() {
          updateGreeting();
        });
      }
    };
  });
&#13;
<!DOCTYPE html>
<html ng-app="guestbookApp">

<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.js"></script>
</head>

<body ng-controller="guestbookCtrl">

  <h4>Latest guests:</h4>

  <guest-list guests="latestGuests" greeting="'Welcome, ' + guestDetails.name + '!'"></guest-list>
  
  <h4>Type your name below to sign the guestbook:</h4>
  <input type="text" ng-model="newGuest.name" />
  <button ng-click="addGuest()" ng-disabled="!newGuest.name">Sign</button>
  <div ng-if="newGuest.name">
    <p guest guest-details="newGuest" greeting="'Hello, ' + guestDetails.name + '! Click \'Sign\' to sign the guestbook!'"></p>
  </div>
</body>

</html>
&#13;
&#13;
&#13;

如果有人对如何改进有任何建议,请告诉我们!我仍然对使用$parse$watch感到有些讨厌,但也许这是不可避免的?

答案 1 :(得分:1)

问候语如何取决于用户自己? 有没有办法创建一个知道如何生成自定义问候语的服务?

如果没有,那么Proxy对象呢? https://www.youtube.com/watch?v=AIO2Om7B83s&feature=youtu.be&t=15m1s 我昨天发现它,从我的角度来看,它似乎适合这里。您应该为每个guest虚拟机创建代理对象,将其注入guest指令,并在链接阶段将解析(由angular完成)问候语放入注入的代理对象中。

此外,我认为你所做的事情可以通过比从外部设置属性并解析它更简单的方式完成。