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
    }
}

<body>しかし、たとえば、内部の HTML ボタンだけでなく、デバイスの [戻る] ボタンでも処理したいと考えています。したがって、次のように、イベントのイベント リスナーを追加し、AngularJS コンテキストの外部で呼び出されることをdeviceready明示的に呼び出す必要があります。$scope.$apply()

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

しかし、私は (比較的 :)) 新しい構文にも従いたいと思っていcontrollerAsます。これは、Todd Motto: Opinionated AngularJS styleguide for teamによって現在推奨されて$scopeいるため$emitです$on$apply()しかし、ユーザーがデバイスの戻るボタンをクリックしたときに、コンテキストがAngularコンテキストではないため、呼び出す必要がある場合はできません。Serviceコードバのラッパー ファサードを作成し、このサービスに注入することを考えました$scopeが、ここで読んだように、 $scope を angular サービス function()に注入することはできません。私はこれを見ました: Angular JS & Phonegap 戻るボタン イベントと受け入れられたソリューションには$apply()$scope取り外し不可。$scope明示的に必要ないときにコントローラから削除するために、Angular コントローラの外部にある Cordova 固有のイベントを削除する解決策を知っている人はいますか? 前もって感謝します。

4

2 に答える 2

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);
});
于 2015-09-07T18:55:50.817 に答える
1

私の場合、Angular$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すると、自動的に気になります。
  • システムが Cordova イベントをディスパッチする方法が変更された場合、1 か所で変更する必要があります。

短所:

  • 初期化フェーズで既にイベント ハンドラーがアタッチされているコントローラーを継承する場合、および子に独自のハンドラーが必要な場合は注意が必要です。

リスナーとフォワーダーを配置する場所はユーザー次第であり、アプリケーションの構造に大きく依存します。backbuttonアプリで許可されている場合は、イベントのすべてのロジックをrunブロックに保持し、コントローラーでそれを取り除くこともできます。$rootScopeそれを整理する別の方法は、たとえば、コントローラ内でオーバーライドできる単一のグローバル コールバックをアタッチして指定することです。コントローラの戻るボタンの動作が異なる場合は、イベントを台無しにしないでください。

devicereadyイベントについてはよくわかりませんが、最初に1回発生します。私の場合、最初にdevicereadyイベントが発生するのを待ってから、AngularJS アプリケーションを手動でブートストラップして、アプリのシーケンシャル ロードを提供し、競合を回避していました。

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

私の観点からは、アプリのロジックと、それをブートストラップする方法を互いに分離する必要があります。backbuttonそのため、リスナーをrunブロックに移動しました。

于 2015-09-07T10:59:34.267 に答える