Angularjs 如何在Angular controller外部删除Cordova特定事件?
假设我有一个控制器,可以处理视图更改:Angularjs 如何在Angular controller外部删除Cordova特定事件?,angularjs,cordova,angularjs-scope,angularjs-controller,angularjs-controlleras,Angularjs,Cordova,Angularjs Scope,Angularjs Controller,Angularjs Controlleras,假设我有一个控制器,可以处理视图更改: function Controller($scope){ var viewModel = this; viewModel.goBack= function(){ viewModel.visible = visibleLinks.pop(); //get last visible link viewModel.swipeDirection = 'left';// for view change animati
function Controller($scope){
var viewModel = this;
viewModel.goBack= function(){
viewModel.visible = visibleLinks.pop(); //get last visible link
viewModel.swipeDirection = 'left';// for view change animation
}
}
但我不仅想用
中的HTML按钮来处理它,还想用设备上的后退按钮来处理它。因此,我必须为deviceready
事件添加事件监听器,并显式调用$scope.$apply()
,以便在AngularJS上下文之外调用它,如下所示:
document.addEventListener("deviceready", function(){
document.addEventListener("backbutton", function(){
viewModel.goBack();
$scope.$apply();
}, false);
}, false);
}
但我还想遵循(相对:)新的
controllerAs
语法,因为这是现在推荐的,例如Todd的座右铭:当不使用$emit
或$on
时,它允许从控制器中删除$scope
。但我不能这样做,如果我必须调用$apply()
,因为当用户单击设备后退按钮时,我的上下文不是角度上下文。我想创建一个服务
,它可以作为cordova的包装外观,并将$scope
注入该服务,但正如我在这里读到的:这是不可能的。我看到了这一点:接受的解决方案还包含$apply()
,这使得$scope
不可移动。有谁知道在Angular controller之外删除Cordova特定事件的解决方案,以便在不需要明确说明时从控制器中删除$scope
?提前谢谢。在我的例子中,我只是在$rootScope
上通过角度触发来转发Cordova事件。基本上,任何应用程序控制器都将接收此自定义事件。在初始化任何控制器之前,侦听器都会连接到配置阶段的run
块中。以下是一个例子:
angular
.module('app', [])
.run(function ($rootScope, $document) {
$document.on('backbutton', function (e) {
// block original system back button behavior for the entire application
e.preventDefault();
e.stopPropagation();
// forward the event
$rootScope.$broadcast('SYSTEM_BACKBUTTON', e);
});
})
.controller('AppCtrl', function ($scope) {
$scope.$on('SYSTEM_BACKBUTTON', function () {
// do stuff
viewModel.goBack();
});
});
显然,在$scope.$处理程序中,您不必调用$scope.$apply()
此解决方案的优点是:
- 在事件广播到所有控制器之前,您可以修改事件或对整个应用程序执行其他操作李>
- 每次实例化控制器时使用
$document.on()
时,事件处理程序将保留在内存中,除非手动从该事件中取消sibscribe;使用$scope.$on
自动关心它李>
- 如果系统分派Cordova事件的方式发生变化,您必须在一个地方进行更改
缺点:
- 在继承已在初始化阶段附加了事件处理程序的控制器时,如果希望在子级中包含自己的处理程序,则必须小心
在哪里放置侦听器和转发器取决于您,这在很大程度上取决于您的应用程序结构。如果你的应用程序允许,你甚至可以在run
块中保留backbutton
事件的所有逻辑,并在控制器中删除它。另一种组织方法是指定一个附加到$rootScope
的全局回调,例如,如果控制器中的“后退”按钮具有不同的行为,则可以在控制器内重写该回调,以避免干扰事件
不过,我不确定是否有devicerady
事件,它从一开始就触发一次。在我的例子中,我首先等待触发deviceready
事件,然后手动引导AngularJS应用程序,以提供应用程序的顺序加载并防止任何冲突:
document.addEventListener('deviceready', function onDeviceReady() {
angular.element(document).ready(function () {
angular.bootstrap(document.body, ['app']);
});
}, false);
从我的观点来看,应用程序的逻辑和引导方式应该彼此分离。这就是为什么我将backbutton
的侦听器移动到run
块。我看不出为什么要从控制器中删除$scope。遵循最佳实践并在不需要时删除它是可以的,但正如您所说,您仍然需要$emit、$on、$watch。。您可以在列表中添加$apply()
我在这里建议的另一种解决方案是实现一个helper函数来处理这个问题。我们可以将它放在一个服务中,并使用$rootScope服务,它是可注入的
app.factory('utilService', function ($rootScope) {
return {
justApply: function () {
$rootScope.$apply();
},
createNgAware: function (fnCallback) {
return function () {
fnCallback.apply(this, arguments);
$rootScope.$apply();
};
}
};
});
// use it
app.controller('SampleCtrl', function(utilService) {
var backBtnHandler1 = function () {
viewModel.goBack();
utilService.justApply(); // instead of $scope.$apply();
}
// or
var backBtnHandler2 = utilService.createNgAware(function(){
viewModel.goBack();
});
document.addEventListener("backbutton", backBtnHandler2, false);
});