改进 AngularJS 指令代码 [英] Improve AngularJS directive code
问题描述
我写了一个 AngularJS 指令,但我对它很陌生,我不知道我是否以Angular 方式"完成...
I wrote an AngularJS directive, but I'm pretty new about it, and I don't know if I done in the "Angular way"...
这是我的 plunker 代码:http://plnkr.co/edit/X1tOk4z8f6dCK3mfB7HP?p=预览
Here is my plunker with the code: 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+'"]')
部分,它有点讨厌"...(或不?);否则我不知道在同一个控制器中不同时间重用同一个指令的更好方法.有人可以建议我更好的代码吗?
I find that the document.querySelector('[wait-button="'+id+'"]')
part, it's a bit "nasty"... (or not?); otherwise I don't know a better way to re-use the same directive different times in the same controller.
Can someone suggest me a better code?
谢谢.
推荐答案
访问指令中的元素
我提倡使用 link
函数来处理这种类型的事情:
accessing the element in the directive
I'd advocate using the link
function for this type of thing:
link: function($scope, elem, attrs){ /* do something w. elem */ }
在控制器中访问您的元素并不是很angular-ish.这就是 link
& 的全部意义所在.compile
指令对象的函数....
It's not very angular-ish to be accessing your element in the controller. That's the whole point of the link
& compile
functions of the directive object....
...但在极少数情况下这是合理的.在您的控制器中注入的 $element
引用了您的 angular.element(document.querySelector('[wait-button="'+id+'"]'))
代码正在做.此时您只需要使用 $element
即可.但我可以推荐一种更有角度的方法吗?
... but in rare cases this is justified. The injected $element
in your controller references the same thing your angular.element(document.querySelector('[wait-button="'+id+'"]'))
code is doing. You only need to use $element
at this point. But may I recommend a more angular approach altogether?
另一个问题是您基本上如何将您的意图从指令传达给主控制器并返回给指令.您的用例与大多数用例略有不同,因为您具有异步性质.
The other issue is how you're basically communicating your intent from the directive to the main controller and back to the directive. Your use case is a little different than most in that you have an async nature.
我制作了一个利用隔离作用域和回调参数的示例.在大多数实际场景中,您将处理异步回调的承诺.因此,我使用了 Promise 中的 .finally
逻辑来执行回调,该回调与指令进行通信,无论异步逻辑已经结束.
I have made an example that leverages an isolate scope and callback parameters. In most real-world scenarios you'll be dealing with promises for async callbacks. As such, I used the .finally
logic from the promises to execute the callback that communicates back to the directive that whatever async logic has wrapped up.
在我的例子中要记住的事情:
Things to keep in mind in my examples:
- 我使用了咖啡脚本,因为我用这种方式编写代码
- 我使用 CSS/DOM 来驱动指令的加载状态应该出现,而不是尝试以编程方式执行.在我的书中,程序化 DOM 操作非常反对 NG.指令为您提供了足够的信息来以声明方式执行此类操作.
- 我没有使用指令控制器,因为除非您打算为指令使用模板,否则您真的不需要自定义控制器.使用
link
函数与自定义指令控制器的区别是模糊的. - 哦...我使用了 *controller as• 语法,因为如果您阅读有关 NG 发展方向的任何信息,它们将远离整个
$scope
范式.
- I used coffeescript because I code sanely that way
- I used CSS/DOM to drive how the loading state of the directive should appear rather than trying to do it programmatically. Programmatic DOM manipulation is very much anti-NG in my book. Directives provide you with enough to do things like this declaratively.
- I didn't use the directive controller because unless you're going to use a template for your directive, you really don't need a custom controller. There is a fuzzy line of when you go with a
link
function versus a custom directive controller. - Oh... and I used the *controller as• syntax because if you read anything about where NG is going, they are moving away from the whole
$scope
paradigm.
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
实现用户界面
<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})
这篇关于改进 AngularJS 指令代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!