Определить функцию внутри Angular выделенной области действия

Я пишу пользовательскую директиву <pagination>, которая возвращает элементы, отвечающие за изменение текущей страницы и настроек пагинации (например, сколько элементов будет отображаться на странице). Директива имеет изолированную область действия (чтобы сделать ее более пригодной для повторного использования).

Внутри шаблона директивы мне нужно вызывать такие функции, как changePage() или changePaginationSettings(). Единственный способ передать функцию внутри изолированной области видимости, которую я нашел, - это определить функцию в контроллере.

mainController.js

module.controller("mainController", function($scope) {
    $scope.changePage = function() { ... };
});

а затем передать его в директиву в качестве атрибута:

pagination.js

module.directive("pagination", function() {
    return {
        restrict: "E",
        scope: {
           changePage: "="
        },
        templateUrl: "templates/pagination.html"
    }
}

pagination.html

<pagination change-page="changePage">

Это выглядит очень уродливо для меня, потому что это разбивает связанный код на 2 несвязанных файла. То есть changePage() должна быть определена в файле pagination.js, а не в mainController.js.

Я думаю, что-то подобное должно быть возможно:

pagination.js

module.directive("pagination", function() {
    function changePage() { ... };

    return {
        restrict: "E",
        scope: {
           changePage: changePage
        },
        templateUrl: "templates/pagination.html"
    }
}

Но такой код выдает (бессмысленно для меня) ошибку: Error: definition.match is not a function.

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

Я прочитал AngularJS директиву Docs, но они даже не перечислить, какие правовые ценности в scope объекта директивы, только дать некоторые "=", "и" и "@" примеры.

Ответ 1

Единственными допустимыми значениями для определения объекта изолированной области являются строки, начинающиеся с &, @ или =. (Вы также можете следовать этим символам с именем свойства в родительской области, если вы хотите, чтобы имя свойства отличалось в директиве. 1) В этом примере вы хотите использовать символ = поскольку это означает, что Angular должен "привязать changePage к области директивы к changePage в родительской области". Посмотрите этот ответ для более подробной информации.

Вы правы, что это уродство нужно передать этой функции через атрибут директивы, однако это характер наличия изолированного объема. Вы можете подумать о том, что в службе есть changePage и другие связанные методы, так как вы можете вставить это как зависимость.

Изменить

Без области выделения вы можете сделать следующее:

module.directive("pagination", function() {    
    return {
        restrict: "E",
        templateUrl: "templates/pagination.html",
        link: function(scope, elem, attrs) {
            // scope.changePage is available from the directive parent $scope
        }
    }
}

1 Пример: { 'nameInDirective': '=nameOnParent' }

Ответ 2

Как пользователь sdgluck правильно отвечает, вы можете расширить область действия в функции ссылок и, таким образом, сохранить свой код в чистоте и разделить. Следующий образец немного более полный, но он сводится к одному и тому же результату. Он позволяет определить элемент, как показано ниже. Помните, что все атрибуты интерпретируются как объекты, и, если вы хотите передать строковое значение, вы должны поместить дополнительные кавычки вокруг этого значения (или вы получите значение undefined для этого атрибута)

<my-button someattr="'my text'"></my-button>

angular.module('test', []);

angular.module('test').controller('testctrl', function($scope) {
  $scope.someValue = '';
});

angular.module('test').directive('myButton', function() {
  return {
    restrict: 'E',
    template: '<button>{{getText()}}</button>',
    replace: true,
    scope: {
      someattr: '='
    },
    link: function(scope, elements, attrs){
      scope.getText = function(){
        return scope.someattr;
      };
    }
  }
});

Ответ 3

здесь у вас есть пример конфигурации.

главный контроллер

module.controller("mainController", function($scope) {
    $scope.changePage = function() { ... };
});

скажем, это index.html, и вы должны иметь такую ​​директиву

<pagination change-page="changePage()">

и ваша директива должна быть ниже

module.directive("pagination", function() {
    function changePage() { ... };

    return {
        restrict: 'E',
        scope: {
           changePage: '&'
        },
        templateUrl: "templates/pagination.html"
    }
}

и ваш pagination.html

<div ng-click="changePage()"></div> 

это будет привязано к вашей функции главного контроллера changePage.

Ответ 4

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

Ваш HTML:

<my-custom-directive></my-custom-directive>

Ваше определение директивы:

.directive("myCustomDirective", myCustomDirectiveHanlder)

function myCustomDirectiveHandler() {
    return {
        templateUrl: "/app/templates/myCustomDirectiveTemplate.html",
        restrict: 'E',
        link: function (scope, elements, attrs) {
            //your code here
        }
    }
};