2015-08-17 156 views
9

我正在編寫一個自定義的<pagination>指令,它將返回負責更改當前頁面和分頁設置(例如每頁顯示多少項)的元素。該指令具有隔離範圍(使其更加可重用)。在Angular指令的隔離範圍內定義函數

在指令模板中,我需要調用諸如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 Directive Docs但他們甚至沒有列出什麼是一個指令scope對象合法值,只給一些「=」,「&」和「@」的例子。

回答

11

獨立作用域對象定義的唯一合法值是以&,@=開頭的字符串。 (如果你希望屬性名稱在指令中有所不同,你也可以在父範圍內使用這些符號的屬性名稱)在這種情況下,你想使用=符號,因爲這表示Angular應該「將指令範圍上的changePage綁定到父範圍上的changePage「。請參閱this answer瞭解更多詳情。

你說得對,通過指令中的一個屬性來傳遞這個函數是醜陋的,但這是具有隔離範圍的本質。您可能會考慮在服務中使用changePage和其他相關方法,因爲您可以將其注入爲依賴項。

編輯

沒有一個分離的範圍,你可以做到以下幾點:

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

例子:{ 'nameInDirective': '=nameOnParent' }

+0

因此,無法在指令本身內定義新的範圍值,對嗎?順便說一句,我不明白如何允許這會違反*隔離範圍*概念。使用服務的解決方案似乎比定義控制器內的值要好得多。感謝您提出建議。 –

+0

你可以使用指令的'$ scope'做任何你喜歡的事情,唯一的區別就是該指令繼承了你自己定義的屬性,而不是其他的。像在控制器中一樣訪問一個指令的'$ scope',例如:'link:function(scope,elem,attrs){...}' – sdgluck

+0

我在我之前的評論中以錯誤的方式提出了這個問題。我的意思是:「所以沒有辦法在指令中定義一些新的值 - 指令中可用的唯一值是通過屬性**和**傳遞給它的值明確地綁定到隔離範圍我。」 –

0

在這裏你有一個簡單的配置。

主控制器

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

和您的分頁。 html

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

這將綁定到您的主控制器的changePage函數。

+0

這與我提供的代碼幾乎相同。還有什麼是最重要的,你仍然在控制器中定義'changePage()'函數,這是我想避免的,我的問題的原因 - 我問過有沒有一種方法來定義'changePage()'在指令內而不是在控制器內。 –

+0

ok..anyway當你需要它的時候你會錯過隔離範圍,因爲你不能從父範圍傳遞參數到你的指令 – bews99

+0

我不想從父範圍傳遞任何東西。我想要的是在指令的隔離範圍內定義一個新值(在我的情況下是一個函數)。 –

2

正如用戶sdgluck正確回答,您可以在鏈接函數中擴展指令範圍,從而保持您的代碼清潔和分離。下面的例子更完整一些,但歸結爲相同的結果。它允許你定義一個元素如下。 要知道,所有的屬性都解釋爲對象,並且,如果你想傳遞一個字符串值,你必須把多餘的引號圍繞價值(否則你會得到該屬性未定義的值)

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