我正在尝试创建一条指令,该指令允许将元素定义为可点击或不可点击,并且将被定义为:
<page is-clickable="true"> transcluded elements... </page>
我希望生成的HTML是:
<page is-clickable="true" ng-click="onHandleClick()"> transcluded elements... </page>
我的指令实现如下所示:
app.directive('page', function() { return { restrict: 'E', template: '<div ng-transclude></div>', transclude: true, link: function(scope, element, attrs) { var isClickable = angular.isDefined(attrs.isClickable) && scope.$eval(attrs.isClickable) === true ? true : false; if (isClickable) { attrs.$set('ngClick', 'onHandleClick()'); } scope.onHandleClick = function() { console.log('onHandleClick'); }; } }; });
我可以看到,添加新属性后,Angular不了解ng- click,因此不会触发。我尝试$compile在设置属性后添加一个,但它会导致无限的链接/编译循环。
ng- click
$compile
我知道我可以只检查onHandleClick()函数中的isClickable值是否为true,但是我很好奇如何动态添加ng- click事件来执行此操作,因为我可能需要使用多个其他ng-*指令来执行此操作,而我不想这样做添加不必要的开销。有任何想法吗?
onHandleClick()
isClickable
true
ng-*
阅读了Angular文档后,我发现了这一点:
您可以将template指定为表示模板的字符串,或者指定为使用两个参数tElement和tAttrs(在下面的编译函数api中进行描述)并返回表示模板的字符串值的函数。
因此,我的新指令如下所示:(我相信这是处理此类问题的适当“角度”方式)
app.directive('page', function() { return { restrict: 'E', replace: true, template: function(tElement, tAttrs) { var isClickable = angular.isDefined(tAttrs.isClickable) && eval(tAttrs.isClickable) === true ? true : false; var clickAttr = isClickable ? 'ng-click="onHandleClick()"' : ''; return '<div ' + clickAttr + ' ng-transclude></div>'; }, transclude: true, link: function(scope, element, attrs) { scope.onHandleClick = function() { console.log('onHandleClick'); }; } }; });
注意新的模板功能。现在,我正在编译该函数之前的模板。
添加replace: true该函数可消除重新编译指令时的无限循环问题。然后在链接函数中,我只是在添加新属性后重新编译元素。不过要注意一件事,因为我ng- transclude在元素上有一条指令,所以我需要删除该指令,以便它不会尝试在第二次编译中包含任何内容,因为没有要包含的内容。
replace: true
ng- transclude
这是我的指令现在的样子:
app.directive('page', function() { return { restrict: 'E', replace: true, template: '<div ng-transclude></div>', transclude: true, link: function(scope, element, attrs) { var isClickable = angular.isDefined(attrs.isClickable) && scope.$eval(attrs.isClickable) === true ? true : false; if (isClickable) { attrs.$set('ngClick', 'onHandleClick()'); element.removeAttr('ng-transclude'); $compile(element)(scope); } scope.onHandleClick = function() { console.log('onHandleClick'); }; } }; });
我认为第二次重新编译模板并不是理想的选择,因此我觉得在第一次编译模板之前仍然有一种方法可以这样做。