Как я могу использовать 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");
      }
    }
  });

6 ответов

Решение

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

<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>

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

scope: {
  current:'=',
  changeNumber: '&'
},

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

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

измени свой 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>

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

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

    };

})

CodePen

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

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

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

CodePen

Другое решение, если вы не можете переместить «ng-click» в шаблон директивы, заключается в том, что вы можете поместить функцию в родительскую область. Так:

Заменять:

      link: function(scope, element, attrs) {      
    scope.hello = function() {
      scope.current++
    };
  }

Для:

      link: function(scope, element, attrs) {      
    scope.$parent.hello = function() {
      scope.current++
    };
  }

Это сделает функцию «привет» доступной из области контроллера.

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

Пояснение: Когда вы используете ng-click на элемент, значение этого (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");
      }
    }
  });
Другие вопросы по тегам