Хобрук: Ваш путь к мастерству в программировании

Как оценить выражение Angular в дочерней директиве и выставить его в родительской директиве?

У меня есть директива, представляющая группу объектов, назовем ее people.

Эта директива имеет ng-repeat в своем шаблоне, который повторяет дочернюю директиву, например. person, у которого есть атрибут выражения personGreeting, который должен оценивать его область действия.

И people, и person используют изолированную область.

Как я могу настроить эти директивы так, чтобы я мог выставить 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, и вроде бы все заработало, но все стало очень странно и беспорядочно, и я не мог заставить работать привязку данных. , так что это было похоже на напрасные усилия. Я чувствую, что это должно быть просто, но это не так.

Есть ли элегантный способ сделать это?


  • AngularJS может показаться немного сложным для непосвященных; повесить там! Это интересный фрагмент иерархических директив, который может быть полезен при решении вашей проблемы. Одна вещь, которую я сразу же заметил, — это отсутствие опции «требовать» для ваших «дочерних» директив (например, требовать: «^people» лично и т. д.). Я думаю, что ссылка, которую я дал вам, иллюстрирует это довольно хорошо. 06.12.2014
  • Хорошее видео, но я не уверен, что требование people в person принесет пользу в этой ситуации. Я думаю, что это решает только противоположную проблему, а также, похоже, не помогает с привязкой данных. 06.12.2014

Ответы:


1

Как приветствие зависит от самого пользователя? Есть ли способ создать службу, которая знает, как создавать индивидуальные приветствия?

Если нет, то как насчет прокси-объекта? https://www.youtube.com/watch?v=AIO2Om7B83s&feature=youtu.be&t=15m1s Я обнаружил его вчера, и, с моей точки зрения, он подходит сюда. Вы должны создать прокси-объект для каждого гостя, внедрить его в директиву guest и на этапе связывания поместить проанализированное (сделанное с помощью angular) приветствие в этот введенный прокси-объект.

Кроме того, я думаю, что то, что вы делаете, можно сделать гораздо проще, чем устанавливать атрибут извне и анализировать его.

06.12.2014
  • Приветствие — это упрощение гораздо более сложной директивы в моем реальном приложении, где мне нужно иметь возможность форматировать сообщения всплывающей подсказки/всплывающего окна, вложенные в несколько директив глубоко из внешнего контроллера/шаблона. Вы знаете, где я могу прочитать больше об идее прокси-объекта? На видео это довольно быстро замазали. Кроме того, если вы могли бы, взгляните на приложение гостевой книги в моем ответе и разветвите / измените его так, как, по вашему мнению, должно быть. Спасибо за ссылку на видео, оно определенно стоит просмотра. 06.12.2014
  • к сожалению, у меня больше нет ничего о шаблоне прокси в angular (просто github.com/mgechev /angularjs-in-patterns#proxy, но это не слишком актуально для нашего случая). Я думаю, было бы полезно, если бы вы воспроизвели свое приложение с таким же уровнем глубины, но в упрощенном виде, чтобы мы могли найти для вас лучший дизайн. 06.12.2014

  • 2

    Хорошо, мне удалось собрать простое приложение для гостевой книги, используя ту же концепцию, которая работает: 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, но, может быть, это неизбежно?

    06.12.2014
  • Каков вариант использования $watch здесь? Существуют ли внешние элементы, изменяющие имена экземпляров модели? 06.12.2014
  • Кроме того, требуется ли, чтобы часть ng-repeat была в шаблоне директивы? 06.12.2014
  • Не уверен, нужен ли мне $watch или нет, но в этом примере он используется для приветствия пользователя, когда он вводит свое имя в поле. А что до ng-repeat, то как бы еще повторить гостей? Я не хочу, чтобы потребитель задавал логику повторения. 07.12.2014
  • Я думаю, это разница в стиле. Я думаю, что это излишне усложняет вашу директиву, но я вижу вашу точку зрения в том, что вы не хотите, чтобы потребитель указывал логику повторения. Учитывая ваши требования и после вчерашней игры с вашим плунжером, я думаю, что у вас есть очень надежное решение. Я бы принял ваш собственный ответ в качестве ответа на этот вопрос. :) 07.12.2014
  • Новые материалы

    Основы принципов S.O.L.I.D, Javascript, Git и NoSQL
    каковы принципы S.O.L.I.D? Принципы SOLID призваны помочь разработчикам создавать надежные, удобные в сопровождении приложения. мы видим пять ключевых принципов. Принципы SOLID были разработаны..

    Как настроить Selenium в проекте Angular
    Угловой | Селен Как настроить Selenium в проекте Angular Держите свое приложение Angular и тесты Selenium в одной рабочей области и запускайте их с помощью Mocha. В этой статье мы..

    Аргументы прогрессивного улучшения почти всегда упускают суть
    В наши дни в кругах веб-разработчиков много болтают о Progressive Enhancement — PE, но на самом деле почти все аргументы с обеих сторон упускают самую фундаментальную причину, по которой PE..

    Введение в Джанго Фреймворк
    Схема «работать умно, а не усердно» В этой и последующих статьях я познакомлю вас с тем, что такое фреймворк Django и как создать свое первое приложение с помощью простых и понятных шагов, а..

    Настольный ПК как «одно кольцо, чтобы править всеми» домашних компьютеров
    Вид после 9 месяцев использования С настольных компьютеров все началось, но в какой-то момент они стали «серверами», и мы все перешли на ноутбуки. В прошлом году я столкнулся с идеей настольных..

    Расширенные методы безопасности для VueJS: реализация аутентификации без пароля
    Руководство, которое поможет вам создавать безопасные приложения в долгосрочной перспективе Безопасность приложений часто упускается из виду в процессе разработки, потому что основная..

    стройный-i18следующий
    Представляем стройную оболочку для i18next. Эта библиотека, основанная на i18next, заключает экземпляр i18next в хранилище svelte и отслеживает события i18next, такие как languageChanged,..