Как я могу использовать ng-click для директивы с областью изоляции?

#angularjs #angularjs-directive #angularjs-ng-click

#angularjs #angularjs-директива #angularjs-ng-click

Вопрос:

Я могу заставить ng-click работать, когда область действия наследуется в директиве, но не при изоляции. UPDATE: The point is that I want the click function to be defined as part of the directive... moving the function definition into a different scope is not what I want.

Вот рабочий пример с унаследованной областью действия: https://codepen.io/anon/pen/PGBQvj

Вот неработающий пример с изолированной областью действия; https://codepen.io/anon/pen/jrpkjp

(Щелкните числа, они увеличиваются в первом примере, но не во втором)

Некоторый код…

HTML

 <div ng-app="myApp" ng-controller="baseController">
  <my-directive ng-click="hello()" current="current"></my-directive>
</div>
 

Директива с унаследованной областью действия:

 angular.module('myApp', [])
    .controller('baseController', function($scope) {
    $scope.current = 1;
  })
    .directive('myDirective', function() {
    return {
      link: function(scope, element, attrs) {      
        scope.hello = function() {
          scope.current  
        };
      },
      replace: true,
      scope: true,
      template: '<div><child>      <strong>{{ current }}</strong></child></div>'
    }
    })
  .directive('child', function() {
    return {
      link: function(scope, element, attrs) {
        console.log("horeee");
      }
    }
  });
 

Та же директива, но с изолированной областью действия:

 angular.module('myApp', [])
    .controller('baseController', function($scope) {
    $scope.current = 1;
  })
    .directive('myDirective', function() {
    return {
      link: function(scope, element, attrs) {      
        scope.hello = function() {
          scope.current  
        };
      },
      replace: true,
      scope: {
        current:'='
      },
      template: '<div><child>      <strong>{{ current }}</strong></child></div>'
    }
    })
  .directive('child', function() {
    return {
      link: function(scope, element, attrs) {
        console.log("horeee");
      }
    }
  });
 

Ответ №1:

Проблема в том, что вы пытаетесь вызвать функцию, которая не определена. Если вы хотите, чтобы логика была определена внутри изолированной директивы, нет необходимости передавать ссылку на функцию.

 <my-directive current="current"></my-directive>
 

Вы не можете пройти ng-click="hello()" здесь. Это область действия контроллера, поэтому hello() она не определена.

Вместо этого переместите ng-click событие в шаблон директивы

 template: '<div ng-click="hello()">
 

Один дополнительный момент:
Вы используете link() функцию директивы. Это зарезервировано для манипулирования DOM. Вместо этого определите hello() внутри controller функции.

 controller: function ($scope) {
  $scope.hello = function() {
      $scope.current  
  }
},
 

Я думаю, что здесь есть более серьезная архитектурная проблема. Цель изолированной директивы или компонента — инкапсулировать внутреннюю логику для себя. Он не должен манипулировать внешним состоянием. В этом примере вы увеличиваете число. Что, если в другой части вашего приложения вы хотите уменьшить число? Копирование директивы с логикой уменьшения приведет к большому дублированию кода.

Вместо этого вы должны определить функциональность увеличения или уменьшения в контроллере и передать ее в директиву.

 <my-directive change-number="increment()" current="current"></my-directive>
 

Затем используйте amp; синтаксис, чтобы привязать ссылку на функцию к директиве:

 scope: {
  current:'=',
  changeNumber: 'amp;'
},
 

и звоните changeNumber из шаблона. Это очень облегчает повторное использование кода.

Ответ №2:

Добавьте функцию приветствия к контроллеру. Пусть он обновит значение current и передаст его в изолированную область действия директивы

  .controller('baseController', function($scope) {
    $scope.current = 1;
    $scope.hello = function() {         
      $scope.current  ;

    };
 

})

Кодовое соединение

Ответ №3:

вам нужно передать объект из контроллера в директиву

измените свой js на

 angular.module('myApp', [])
.controller('baseController', function($scope) {
$scope.current = {};
$scope.current.val=1;
})
.directive('myDirective', function() {
return {
  link: function(scope, element, attrs) {      scope.internalcurrent= scope.current || {};
                                         //scope.internalcurrent.val=1;
    scope.internalcurrent.hello = function() {
      scope.internalcurrent.val  

    };
  },
  replace: true,
  scope: {
    current:'='
  },
  template: '<div><child>      <strong>{{ internalcurrent.val }}</strong></child></div>'
}
})
.directive('child', function() {
return {
  link: function(scope, element, attrs) {
    console.log("horeee");
  }
}
});
 

и ваш html для

 <div ng-app="myApp" ng-controller="baseController">
<my-directive ng-click="hello()" current="current"></my-directive>
</div>
 

Ответ №4:

Если вы хотите, чтобы функция click была определена в директиве, вам нужно прикрепить обработчик к шаблону следующим образом:

 template: '<div ng-click="hello()"><child><strong>{{current}}</strong></child></div>'
 

Когда вы присоединяете обработчик к объявлению директивы, как в вашем сломанном примере, вы в основном сообщаете ng-click, что хотите вызвать функцию в текущей области видимости (области контроллера). Может показаться, что это не так, потому что в вашем рабочем примере ваша функция была определена из myDirective, но на самом деле она была привязана к области действия, которая в данном случае (рабочий пример) была областью действия контроллера.

CodePen

Ответ №5:

С изолированной директивой вы можете использовать ng-click="$parent.hello()" вместо ng-click="hello()" . Приятно опубликовать перья в вашем вопросе.

Объяснение: когда вы используете ng-click для элемента, значение it ( hello() ) будет оцениваться относительно его внешней области, то есть области контроллера в вашем примере. Когда вы создаете директиву, которая использует неизолированную область, область контроллера передается link функции и hello определяется в области контроллера.

// Редактировать код:

 angular.module('myApp', [])
    .controller('baseController', function($scope) {
    $scope.current = 1;
    $scope.hello = () => $scope.current   ;
  })
    .directive('myDirective', function() {
    return {
      link: function(scope, element, attrs) {      
      },
      replace: true,
      scope: {
        current:'='
      },
      template: '<div><child>      <strong>{{ current }}</strong></child></div>'
    }
    })
  .directive('child', function() {
    return {
      link: function(scope, element, attrs) {
        console.log("horeee");
      }
    }
  });
 

Комментарии:

1. Извините, я неправильно понял ваш вопрос. Определите hello() область действия вашего контроллера, и он должен work.@geoidesic

2. Это тоже не работает. Пожалуйста, попробуйте, прежде чем предлагать 🙂 tx.

3. Если я вас неправильно понял, функция hello() уже определена в области действия контроллера.

4. Когда вы используете директиву с изолированной областью действия, она влияет только на оценку внутри элемента. @geoidesic

5. Ваше решение работает, но на самом деле оно мне не полезно. Я не хочу перемещать свою функцию из контроллера директив.