4

想象我有一個控制器,該控制器處理,例如,查看變化:如何刪除角控制器外的科爾多瓦特定事件?

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按鈕裏面<body>,也與後退的設備按鈕。所以,我必須添加事件偵聽器deviceready事件,同時也顯式調用$scope.$apply()爲了事實上,它被稱爲AngularJS背景之外,像這樣:

document.addEventListener("deviceready", function(){ 
     document.addEventListener("backbutton", function(){ 
      viewModel.goBack(); 
      $scope.$apply(); 
     }, false); 
    }, false); 
} 

但我也想跟進(相對:) )新的controllerAs語法,因此現在推薦,例如通過託德格言:Opinionated AngularJS styleguide for teams,它允許從$emit$on不使用時,從控制器中刪除$scope。但我無法做到這一點,我不得不打電話$apply()導致我的上下文不是當用戶點擊設備後退按鈕時的Angular上下文。我想創建一個Service這可能是科爾多瓦包裝外觀和注入$scope這項服務,但正如我在這裏讀:Injecting $scope into an angular service function()這是不可能的。我看到這個:Angular JS & Phonegap back button event並且接受的解決方案還包含$apply()這使得$scope不可移動。任何人都知道一個解決方案來刪除角控制器外的科爾多瓦特定事件,以便在控制器不需要顯式時從控制器中刪除$scope?先謝謝你。

回答

2

我沒有看到爲什麼要從控制器中刪除$ scope的原因。如果不需要,可以遵循最佳實踐並將其刪除,但正如您所說的,您仍然需要$ emit,$ on,$ watch ..並且您可以在列表中將$ apply()添加到肯定的列表中。

我可以在這裏建議作爲一種替代解決方案是實現一個輔助函數來處理這個問題。我們可以將它放在一個服務中,並使用可注入的$ 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); 
}); 
1

在我的情況下,我簡單地轉發科爾多瓦事件與角$broadcast幫助發射它在$rootScope。基本上任何應用程序控制器都會收到這個自定義事件。在任何控制器被初始化之前,監聽器都附加在配置階段 - 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.$on處理

很明顯,你不必叫$scope.$apply()。該解決方案的

優點是:

  • 你就可以修改事件或者做別的事情了整個應用程序之前,該事件將被廣播到所有的控制器;
  • 當您在每次控制器實例化時使用$document.on()時,事件處理程序將保留在內存中,除非您手動取消訂閱此事件;使用$scope.$on會自動關心它;
  • 如果系統調度科爾多瓦事件變化的方式,你必須改變它在一個地方

缺點:

  • 你得繼承這已經控制器時要小心一個事件處理程序附加在初始化階段,如果你想讓你自己的處理程序在一個孩子。

放置聽衆的位置和轉發者的位置取決於您,它高度依賴於您的應用程序結構。如果您的應用程序允許您甚至可以將backbutton事件的所有邏輯保留在run塊中,並在控制器中清除它。另一種組織方式是指定一個全局回調函數,例如$rootScope,如果它們對後退按鈕有不同的行爲,而不是混淆事件,則可以在控制器內重寫。

雖然我不確定deviceready事件,但它一開始就會激發一次。在我的情況下,我首先等待deviceready事件觸發,然後手動自舉AngularJS應用程序提供應用程序的順序負荷並防止任何衝突:

document.addEventListener('deviceready', function onDeviceReady() { 
    angular.element(document).ready(function() { 
     angular.bootstrap(document.body, ['app']); 
    }); 
}, false); 

從我的觀點來看,應用程序的邏輯以及你如何引導它應該彼此分開。這就是爲什麼我已將backbutton的聽衆移動到run區塊。