1. ホーム
  2. jquery

[解決済み] AngularJS: 部分ビューが表示される前に $viewContentLoaded が起動される

2022-02-18 07:49:50

質問

部分ビューのために、通常なら $(document).ready(function() {...}) 例えば、venetリスナーを要素にバインドします。AngularJSと"root"ビューにロードされた部分ビューでは、これが機能しないことは分かっています。

したがって、私は、コントローラにリスナーを追加しました。 $viewContentLoaded イベントが発生します。リスナーの関数が呼び出されるので、イベントは発生しますが、まるで部分ビューがレンダリングされる前であるかのように私には思えます。リスナーの関数にブレークポイントを設定し、firebugでデバッグしても、要素は表示されませんし、関数内のjquery選択で部分ビューの要素が見つかるわけでもありません。

コントローラはこんな感じです。

angular.module('docinvoiceClientAngularjsApp')
  .controller('LoginController', function ($scope, $rootScope) {

$scope.$on('$viewContentLoaded', function(event) {
  console.log("content loaded");
  console.log($("#loginForm"));   // breakpoint here 
});

[...]

もしこれが一般的なバグであれば、stackoverflowにもっと多くの投稿があるはずなので、私は何か間違ったことをしているのだと思います。

を使っているので ui-router ui-view ルーティングファイルの抜粋をお見せします。

angular
  .module('docinvoiceClientAngularjsApp', [
    'ui.router',
    'ngAnimate',
    'ngCookies',
    'ngResource',
    'ngMessages',
    'ngRoute',
    'ngSanitize',
    'ngTouch'
  ])
 .config(function ($routeProvider, $stateProvider) {
    $stateProvider
    .state('login', {
        url: '/',
        templateUrl: 'components/login/loginView.html',
        controller: 'LoginController'
    })
    .run(['$state', function ($state) {
        $state.transitionTo('login');
    }])

 [...]

よろしくお願いします。ありがとうございます。

UPDATE 1: 以下のようなユースケースで、エラーを剥がしました。loginView.htmlは以下のような感じです。

<div id="loginContainer" style="width: 300px">
  <form id="loginForm" ng-submit="login(credentials)" ng-if="session.token == undefined">

[...]

を削除すると、すぐに ng-if をdivタグから削除すると、期待通りに動作します。このイベントは DOM がレンダリングされた後に発生するため、jQuery は要素を見つけます。もし ng-if がdivタグに付いている場合は、最初に説明したような動作になります。

アップデイト2。 約束した通り、動作するデモを追加しました。 ng-if ディレクティブを使用します。どなたか正しい方向を教えていただけませんか?ログインフォームにこだわらず、何らかの式に基づいてビューの特定の部分を削除し、部分的なビューが準備された後にJavaScriptを実行したい場合など、他にも多くのユースケースがあります。

動作するデモはこちらでご覧いただけます。 デモ

解決するには?

これはangularのダイジェストサイクルに関連しており、angularがフードの下でどのように動作するか、データバインディングなどに関するものです。これを説明する素晴らしいチュートリアルがあります。

あなたの問題を解決するには、$timeoutを使用します。これは、ng-ifがすでにパースされている場合、次のサイクルでコードを実行します。

app.controller('LoginController', function ($scope, $timeout) {
    $scope.$on('$viewContentLoaded', function(event) {
      $timeout(function() {
        $scope.formData.value = document.getElementById("loginForm").id;
      },0);
    });
});

修正したデモはこちら http://codepen.io/anon/pen/JoYPdv

しかし、DOM操作にはディレクティブを使用することを強くお勧めします。 以下はその例です。 AngularJSで簡単なドメイン操作 - ボタンをクリックし、input要素にフォーカスを設定する