如何在子指令中计算 Angular 表达式并将其公开在父指令上

How to evaluate Angular expression in child directive and expose it on parent directive?

本文关键字:指令 Angular 计算 表达式      更新时间:2023-09-26

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

该指令在其模板中有一个重复子指令的ng-repeat,例如 person ,它有一个表达式属性personGreeting,应该根据其范围进行计算。

peopleperson都使用隔离作用域。

如何设置这些指令,以便我可以公开people指令上的personGreeting,并在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服务的编译、链接和控制器函数,并让它工作起来,但它变得非常奇怪和混乱,我无法让数据绑定工作,所以感觉像是浪费精力。我觉得这应该很简单,但似乎并非如此。

有没有一种优雅的方法可以做到这一点?

候语如何取决于用户本身?有没有办法创建一个知道如何产生定制问候语的服务?

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

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

好的,

我设法使用与工作相同的概念将一个简单的留言簿应用程序放在一起:http://plnkr.co/edit/R7s6xE?p=info

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();
        });
      }
    };
  });
<!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>

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