我写了一篇AngularJS指令,但我对此很新,而且我不知道我是否采用了#34; Angular方式" ...
以下是我的代码:http://plnkr.co/edit/X1tOk4z8f6dCK3mfB7HP?p=preview
HTML:
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<meta charset=utf-8 />
<title>Directive Test</title>
<script src="script.js"></script>
</head>
<body ng-controller="MainCtrl">
<button id="button1" ng-click="dummyClickFoo()" wait-button="foo"><i></i> Foo</button>
<button id="button2" ng-click="dummyClickBar()" wait-button="bar"><i></i> Bar</button>
</body>
</html>
JS:
app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.dummyClickFoo = function() {
$scope.startSpinner('foo');
setTimeout(function() {
$scope.stopSpinner('foo');
}, 3000);
};
$scope.dummyClickBar = function() {
$scope.startSpinner('bar');
setTimeout(function() {
$scope.stopSpinner('bar');
}, 3000);
};
});
app.directive('waitButton', function() {
return {
restrict: 'A',
controller: ['$scope', '$element', function($scope, $element) {
$scope.startSpinner = function(id) {
var el = angular.element(document.querySelector('[wait-button="'+id+'"]'));
el.children('i').text('searching...');
};
$scope.stopSpinner = function(id) {
var el = angular.element(document.querySelector('[wait-button="'+id+'"]'));
el.children('i').empty();
};
}]
};
});
我发现document.querySelector('[wait-button="'+id+'"]')
部分,它有点&#34;讨厌&#34; ...(或不是?);否则我不知道在同一个控制器中不同时间重复使用同一指令的更好方法。
有人可以建议我更好的代码吗?
谢谢。
答案 0 :(得分:2)
我主张将link
函数用于此类事情:
link: function($scope, elem, attrs){ /* do something w. elem */ }
在控制器中访问您的元素并不是非常 angular-ish 。这是link
&amp;的全部观点。指令对象的compile
函数....
......但在极少数情况下这是合理的。控制器中注入的$element
引用了angular.element(document.querySelector('[wait-button="'+id+'"]'))
代码正在执行的操作。此时您只需要使用$element
。但是,我可以推荐一种更有棱角的方法吗?
另一个问题是你如何基本上将指令的意图传达给主控制器并返回指令。您的用例与大多数用例略有不同,因为您具有异步性质。
我做了一个利用隔离范围和回调参数的例子。在大多数现实场景中,您将处理异步回调的承诺。因此,我使用promises中的.finally
逻辑来执行回调,该回调与指令进行通信,无论异步逻辑已经包含了什么。
我的例子中要记住的事情:
link
函数而不是自定义指令控制器时,会有一个模糊的行。$scope
范例。plunker - http://plnkr.co/edit/0AvlCQW5qqkpYKl2WpB3?p=preview
主控制器
.controller 'MainCtrl', class MainCtrl
@$inject = [
'$scope'
'$interval'
]
constructor: ($scope, @$interval)->
@viewData = 'Skynet 2.0'
@isLoading = false
callbackExample: ($callbackFunc)->
@loadRqst()
.finally -> $callbackFunc?()
loadRqst: ->
@isLoading = 1
# this returns a promise which gets processed in the example functions
@$interval =>
console.log @isLoading++
, 250, 10
.finally =>
@isLoading = false
实施ui
<button callback-btn="vc.callbackExample($callbackFunc)">
Callback Example<i> - I'm loading & I'm #1</i>
</button>
<button callback-btn="vc.callbackExample($callbackFunc)">
Callback Example<i> - Look I can load too, I'm #2</i>
</button>
<强> CSS 强>
[callback-btn] i{
display: none;
}
[callback-btn].loading i{
display: initial;
}
.directive 'callbackBtn', ($parse)->
dir =
restrict: 'A'
scope: { callbackBtn: '&' }
link: ($scope, elem, attrs)->
onCallback = ->
console.log 'on callback'
elem.removeClass 'loading'
elem.on 'click', ->
elem.addClass 'loading'
$scope.$apply ->
$scope.callbackBtn({$callbackFunc: onCallback})
答案 1 :(得分:1)
我强烈建议您转换
<button id="button1" ng-click="dummyClickFoo()" wait-button="foo"><i></i> Foo</button>
进入指令,所以你的代码将是
<my-button label="foo"></my-button>
答案 2 :(得分:1)
directive
的整个想法是为了促进关注点的分离。
当你使用指令时,它的所有功能都应由指令本身来处理。
现在,你的MainCtrl
中有一部分指令的逻辑,理想情况下应该在你的指令中。
此外,在您的指令中,还有一个控制器功能。理想情况下,控制器函数应该只处理视图模型之间传递的数据等。
对于DOM manilulations,你正在做的事情,它应该在link
函数中实现。
因此,执行相同操作的angular way
如下所示。
你的Html
<body ng-controller="MainCtrl">
<button id="button1" wait-button="foo"><i></i> Foo</button>
<button id="button2" wait-button="bar"><i></i> Bar</button>
<!-- NOTICE: No ng-click handlers here -->
</body>
您的MainCtrl
app.controller('MainCtrl', function($scope) {
// No code required here. This will be handled in Directive's link function.
});
您的waitButton
指令。
app.directive('waitButton', function() {
return {
restrict: 'A',
controller: ['$scope', '$element', function($scope, $element) {
//Again, it's not controller's job to handle DOM manipulations. So code required here.
}],
link: function($scope, $element){
var waitButtons = angular.element(document.querySelectorAll('[wait-button]'));// NOTE: I've used querySelectorAll instead of querySelector. This will make this function generic.
waitButtons.on('click', function(){
var $this = angular.element(this);
startSpinner($this);
setTimeout(function(){
stopSpinner($this);
},3000);
});
function startSpinner(el) {
el.children('i').text('searching...');
}
function stopSpinner(el) {
el.children('i').empty();
}
}
};
});
答案 3 :(得分:0)
将您的函数移动到指令中。将单击处理程序放在链接函数中。
app.directive('waitButton', function($timeout) {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
var startSpinner = function() {
elem.children('i').text('searching...');
};
var stopSpinner = function() {
elem.children('i').empty();
};
var clickHandler = function() {
startSpinner();
$timeout(stopSpinner,3000);
};
elem.on("click", clickHandler);
}
}
});
还使用AngularJS $timeout
服务。有关详细信息,请参阅AngularJS $timeout service API Reference。