在AngularJS中,我注意到控制器注入了$element
,这是控制器控制的元素的JQuery / JQLite包装器。例如:
<body ng-controller="MainCtrl">
然后,您可以通过注入$element
app.controller('MainCtrl', function($scope, $element) { ...
这可以在this Plunkr工作。
似乎被确认为docs for $compile
中的故意功能我的问题是:
根据各种指南和教程,建议您不要在控制器中访问DOM,为什么这样做呢?
是否有任何非hacky用例?
在某处可用代码中是否有使用此示例?
感谢。
答案 0 :(得分:15)
可扩展和/或与其他指令交互的编写良好的指令将具有控制器。该控制器需要访问DOM,因为它是定义该指令的功能的地方。指令实际上是将控制器/范围绑定到页面上元素的不同方式;向DOM添加功能的首选方法。据我所知,最佳做法是:不要同时使用控制器和链接功能。所以指令控制器需要$element
。
根据各种指南和教程,建议您不应该在控制器中访问DOM,为什么这甚至可能?
一旦你深入研究这些指南是如何工作的,这些指南就会有点误导。
控制器处理定义函数并分配视图使用的变量。将这些函数和变量绑定到视图的正确方法是使用指令。这是我对最佳实践的理解,在过去的一年里,它与大型和不断增长的角度应用程序一起工作。
棘手的是该指令基本上将控制器绑定到DOM。 ng-model
是一个指令,并且有一个可以从其他指令访问的控制器。如果您执行添加自定义验证功能等操作,则需要利用此功能。该指令的该控制器应该操纵DOM。 所以通用控制器实际上是一组超级视图控制器;教程通常会釉面的细节。
是否有任何非hacky用例?
$element
:例如在指令的控制器中使用它。
在某处可用代码中是否有使用此示例?
Angular源代码虽然可能有点密集,但是代码很好并且评论很好。可能需要一点点才能看到正在发生的事情,但通常信息非常丰富。
NgModelController(复杂示例) https://github.com/angular/angular.js/blob/master/src/ng/directive/input.js https://github.com/angular/angular.js/blob/master/src/ng/directive/input.js#L1660
可能是一个简单的例子,但是使用了编译函数,例如eventDirectives(例如ng-click
),
https://github.com/angular/angular.js/blob/master/src/ng/directive/ngEventDirs.js#L3
答案 1 :(得分:6)
无论是否注入$ element,控制器的范围都绑定在该元素上。
angular.element('#element-with-controller').scope();
Angular围绕指令。它是MVC中粘合在一起的东西。 如果你考虑一下,ng-controller本身就是一个指令。
我想当你将一个控制器用于多个指令时,这可以派上用场。
.controller('MyController', function($scope, $element){
$scope.doSomething = function(){
// do something with $element...
}
})
.directive('myDirective1', function(){
return {
controller: 'MyController'
}
})
.directive('myDirective2', function(){
return {
controller: 'MyController'
}
})
每个指令都有一个指定控制器的新实例,但基本上是共享它的属性,依赖关系。
我写了一个表单处理程序控制器,用于注册/登录/联系人等等。
答案 2 :(得分:4)
实际上,因为您在参数列表中将其指定为依赖项,所以会注入$ element。 如果从列表中删除它,则不会注入它。
http://plnkr.co/edit/CPHGM1awvTvpXMcjxMKM?p=preview
如评论所述,有些情况下你需要控制器中的$元素,尽管我现在想不到任何元素。
答案 3 :(得分:4)
将评论作为答案发布,因为评论中的字符限制以及包含部分答案的感觉。
根据各种指南和教程,建议您不要在控制器中访问DOM,为什么这可能呢?
如前所述,人们建议您在代码中采取特定方法并不要求他们限制您。
是否有任何非hacky用例?
在大多数情况下,我无法想到一个好处(回复你的评论)。有一次我使用这种方法是实现youtube iframe API指令。 当有人停止播放器时,必须从DOM中删除该元素。
在某处可用代码中是否有使用此示例?
这是一些代码,虽然它来自很久以前,我删除了一些部分,被认为是hacky?
angular.module('mainApp.youtube').directive('youtubePlayer', function($window,$element logging, ui,) {
return {
restrict: 'A', // only activate on element attribute
scope: true, // New scope to use but rest inherit proto from parent
compile: function(tElement, tAttrs) {
// Load the Youtube js api
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
},
controller: function($scope, $element, $attrs) {
// This is called when the player is loaded from YT
$window.onYouTubeIframeAPIReady = function() {
$scope.player = new YT.Player('player', {
height: '250',
width: '400',
playerVars: {
'autoplay': 0,
'controls': 1,
'autohide': 2
},
//videoId: $scope.live_track.video_id,
events: {
'onReady': $scope.onPlayerReady,
'onStateChange': $scope.onPlayerStateChange,
'onError': $scope.onError
}
});
};
// When the player has been loaded and is ready to play etc
$scope.onPlayerReady = function (event) {
$scope.$apply(function(){
logging.info("Playa is ready");
logging.info($scope.player);
// Lets also broadcast a change state for the others to catch up
player_service.broadcast_change_state({"state": $scope.player.getPlayerState()});
// Should try to just load the track so that the users can press play on the playa
});
};
// When the player has been loaded and is ready to play etc
$scope.onError = function (event) {
$scope.$apply(function(){
logging.info("Playa Encountered and ERROR");
logging.info(event)
});
};
$scope.start_playing = function (jukebox_id){
logging.info('Yes I am starting...');
};
$scope.$on('handleStartPlaying', function(event, jukebox_id) {
console.log('Got the message I ll play');
$scope.start_playing(jukebox_id);
});
$scope.$on('handlePausePlaying', function() {
console.log('Got the message I ll pause');
$scope.player.pauseVideo();
});
$scope.$on('handleResumePlaying', function() {
console.log('Got the message I ll resume');
$scope.player.playVideo();
});
$scope.$on('handleStopPlaying', function() {
console.log('Got the message I ll stop');
$scope.player.stopVideo();
});
$scope.$on('HandleCloseframe', function() {
console.log('Got the message I ll stop');
$scope.player.stopVideo();
//Should destroy obje etc
// Look here
$element.remove(); // blah blah blah
});
},
ink: function(scope, elm, attrs, ctrl) {
}
}
});
随意纠正我或提供更好的方法。那时候这似乎是合法的。至少如果我们不犯错误,我们就不会学习。