[ディレクティブで] ng-click を使用して、コントローラーのスコープで selectResult 関数を呼び出したいと思います...
- 関数 (またはプロパティ) を isolate スコープに渡すには、ディレクティブ タグで属性を使用します。
...しかし、結果オブジェクトをディレクティブ [スコープ] から取得します。
- ディレクティブ タグのコンテンツがディレクティブのスコープにアクセスできるようにする場合は、transclude を使用しないでください。指定
transclude: true
すると、ディレクティブ タグのコンテンツがディレクティブのスコープにアクセスできないように angular に指示されます。これは、希望するものとは逆です。
#1 を達成するには、ユーザーに次のようにテンプレートを指定させることができます。
<div ng-controller="MainCtrl">
<search external-func='selectResult'>
<div class="someStyle" ng-click="selectResult(result)">{{result.Name}}</div>
</search>
</div>
<search>
ユーザーはタグに追加の属性を追加する必要があることに注意してください。それでも、その html は、javascript が要素に対してどのような操作を行うかについて、html が開発者にヒントを与えるべきであるという angular の哲学にうまく適合する可能性があります。
次に、isolate スコープを次のように指定します。
scope: {
selectResult: '=externalFunc'
},
#2 を達成transclude: true
するには、ディレクティブで指定しないでください。
var app = angular.module('myApp',[]);
app.controller('MainCtrl', ['$scope', function($scope) {
$scope.selectResult = function(result) {
console.log("In MainCtrl: " + result.Name);
};
}]);
app.controller('DirectiveCtrl', ['$scope', function($scope) {
$scope.results = [
{Name: "Mr. Result"},
{Name: "Mrs. Result"}
]
}]);
app.directive('search', function() {
return {
restrict: 'E',
scope: {
selectResult: '=externalFunc'
},
template: function(element, attrs) {
// ^ ^
// | |
// directive tag --+ +-- directive tag's attributes
var inner_div = element.children();
inner_div.attr('ng-repeat', 'result in results')
//console.log("Inside template func: " + element.html());
return element.html(); //Must return a string. The return value replaces the innerHTML of the directive tag.
},
controller: 'DirectiveCtrl'
}
}]);
ユーザーにテンプレートをより詳細に指定させると、html は javascript が何をするかのより良い記録を提供する可能性があります。
<search external-func='selectResult'>
<div class="someStyle"
ng-click="selectResult(result)"
ng-repeat="result in results">{{result.Name}}
</div>
</search>
しかし、ミニマリストの html を主張する場合:
<search>
<div class="someStyle" ng-click="selectResult(result)">{{result.Name}}</div>
</search>
...次に、(上記のように) ng-repeat 属性を動的に追加できます。また、外部関数を isolate スコープに動的にマップすることもできます。
var app = angular.module('myApp',[]);
app.controller('MainCtrl', ['$scope', function($scope) {
$scope.selectDog = function(result) {
console.log("In MainCtrl: you clicked " + result.Name);
};
$scope.greet = function(result) {
console.log('MainCtrl: ' + result.Name);
};
}]);
app.controller('DirectiveCtrl', ['$scope', function($scope) {
$scope.results = [
{Name: "Mr. Result"},
{Name: "Mrs. Result"}
]
}]);
app.directive('search', function() {
return {
restrict: 'E',
scope: {
externalFunc: '&externalFunc' //Cannot write => externalFunc: '&'
}, //because the attribute name is
//'external-func', which means
//the left hand side would have to be external-func.
template: function(element, attrs) {
//Retrieve function specified by ng-click:
var inner_div = element.children();
var ng_click_val = inner_div.attr('ng-click'); //==>"selectResult(result)"
//Add the outer_scope<==>inner_scope mapping to the directive tag:
//element.attr('external', ng_click_val); //=> No worky! Angular does not create the mapping.
//But this works:
attrs.$set('externalFunc', ng_click_val) //=> external-func="selectResult(result)"
//attrs.$set('external-func', ng_click_val); //=> No worky!
//Change ng-click val to use the correct call format:
var func_args = ng_click_val.substring(ng_click_val.indexOf('(')); //=> (result)
func_args = func_args.replace(/[\(]([^\)]*)[\)]/, "({$1: $1})"); //=> ({result: result})
inner_div.attr('ng-click', 'externalFunc' + func_args); //=> ng-click="externalFunc({result: result})"
//Dynamically add an ng-repeat attribute:
inner_div.attr('ng-repeat', 'result in results')
console.log("Template: " + element[0].outerHTML);
return element.html();
},
controller: 'DirectiveCtrl'
}
})
複数の引数を指定して外部関数を呼び出したい場合は、次のようにすることができます。
var app = angular.module('myApp',[]);
app.controller('MainCtrl', ['$scope', function($scope) {
$scope.selectResult = function(result, index) {
console.log("In MainCtrl: you clicked "
+ result.Name
+ " "
+ index);
};
}]);
app.controller('DirectiveCtrl', ['$scope', function($scope) {
$scope.results = [
{Name: "Mr. Result"},
{Name: "Mrs. Result"}
]
}]);
app.directive('search', function() {
return {
restrict: 'E',
scope: {
external: '='
},
template: function(element, attrs) {
//Extract function name specified by ng-click:
var inner_div = element.children();
var ng_click_val = inner_div.attr('ng-click'); //=>"selectResult(result, $index)"
var external_func_name = ng_click_val.substring(0, ng_click_val.indexOf('(') ); //=> selectResult
external_func_name = external_func_name.trim();
//Add the outer_scope<==>inner_scope mapping to the directive tag:
//element.attr('externalFunc', ng_click_val); => No worky!
attrs.$set('external', external_func_name); //=> external="selectResult"
//Change name of ng-click function to 'external':
ng_click_val = ng_click_val.replace(/[^(]+/, 'external');
inner_div.attr('ng-click', ng_click_val);
//Dynamically add ng-repeat to div:
inner_div.attr('ng-repeat', 'result in results');
console.log("Template: " + element[0].outerHTML);
return element.html();
},
controller: 'DirectiveCtrl'
}
});