6

以下のng-includeでng-switchを使用しようとしています。問題は、ng-initと、ng-includesの変更でコントローラーブロック全体が再レンダリングされることです。

login_form.htmlで、ユーザーがログインするときに、LoginCtrlでisLoggedIn=trueを設定しました。ただし、これにより、以下の完全なhtmlが再レンダリングされ、ng-initが再度発生します。

このサイクルを回避するにはどうすればよいですか?

      <div ng-controller="LoginCtrl" ng-init="isLoggedIn = false" class="span4 pull-right">
        <div ng-switch on="isLoggedIn"> 
          <div ng-switch-when="false" ng-include src="'login_form.html'"></div>
          <div ng-switch-when="true" ng-include src="'profile_links.html'"></div>
        </div>
      </div>

以下はログインフォームのHTMLです-

<form class="form-inline">
  <input type="text" placeholder="Email" ng-model="userEmail" class="input-small"/>
  <input type="password" placeholder="Password" ng-model="userPassword" class="input-small"/>
  <button type="submit" ng-click="login(userEmail, userPassword)" class="btn">Sign In</button>
</form>

以下はコントローラーです-

angularApp.controller('LoginCtrl', function($scope, currentUser){

  $scope.loginStatus = function(){
    return currentUser.isLoggedIn();
  };

/*  $scope.$on('login', function(event, args) {
    $scope.userName = args.name;
  }); 

  $scope.$on('logout', function(event, args) {
    $scope.isLoggedIn = false;
  });*/

  $scope.login = function(email, password){
    currentUser.login(email, password);
  };

  $scope.logout = function(){
    currentUser.logout();
  };

});

打撃はサービスです-

angularApp.factory('currentUser', function($rootScope) {
  // Service logic
  // ...
  // 
    var allUsers = {"rob@gmail.com": {name: "Robert Patterson", role: "Admin", email: "rob@gmail.com", password: "rob"},
            "steve@gmail.com":{name: "Steve Sheldon", role: "User", email: "steve@gmail.com", password: "steve"}}

  var isUserLoggedIn = false;

  // Public API here
  return {
    login: function(email, password){
      var user = allUsers[email];
      var storedPass = user.password;

      if(storedPass === password){
        isUserLoggedIn = true;
        return true;
      }
      else
      {
        return false;
      }
    },
    logout: function(){
      $rootScope.$broadcast('logout');
      isUserLoggedIn = false;
    },

    isLoggedIn: function(){
      return isUserLoggedIn;
    }
 };
});
4

3 に答える 3

38

あなたの問題は、プロトタイプの継承が機能する方法の結果だと思います。ng-includeは、独自の子スコープを作成します。子スコープにプリミティブ値を割り当てると、そのスコープに親プロパティをシャドウ/非表示にする新しいプロパティが作成されます。

login_form.htmlでは、ユーザーがログインしたときに次のようなことをしていると思います。

<a ng-click="isLoggedIn=true">login</a>

isLoggedInがtrueに設定される前は、スコープは次のようになります。

割り当て前

isLoggedInをtrueに設定すると、スコープは次のようになります。

割り当て後

うまくいけば、写真がこれがあなたに問題を引き起こしている理由を明らかにします。

プロトタイプの継承がプリミティブでこのように機能する理由の詳細については、AngularJSのスコープのプロトタイプ/プロトタイプの継承のニュアンスは何ですか?を参照してください。

上記のリンクで説明されているように、3つの解決策があります。

  1. モデルの親でオブジェクトを定義してから、子でそのオブジェクトのプロパティを参照します:parentObj.isLoggedIn
  2. login_form.htmlで$parent.isLoggedInを使用します。これにより、新しいスコープを作成するのではなく、$parentスコープのプリミティブが参照されます。例えば、
    <a ng-click="$parent.isLoggedIn=true">login</a>
  3. 親スコープで関数を定義し、子から呼び出します(例:setIsLoggedIn())。これにより、子スコーププロパティではなく、親スコーププロパティが設定されます。

更新:HTMLのレビューでは、ng-switchとng-includeがそれぞれ独自のスコープを作成するため、実際には2つのレベルの子スコープがある場合があります。したがって、写真には孫スコープが必要ですが、3つのソリューションは同じです... $parent。$parent.isLoggedIn-醜いを使用する必要がある#2を除いて。したがって、オプション1または3をお勧めします。

Update2:@ murtaza52が質問にコードを追加しました...ng-init="isLoggedIn = false"コントローラーから削除し(サービスはその変数を介してログイン状態を管理していますisUserLoggedIn)、コントローラーでloginStatus()をオンにします<div ng-switch on="loginStatus()">

これが実用的なフィドルです。

于 2012-12-31T17:20:32.797 に答える
3

実例があります。秘訣は、評価されるスコープ変数がプリミティブ型ではなくオブジェクトでなければならないことです。$scope.$watch()プリミティブ型を適切に監視していないようです(これはバグです)。jsFiddleには、2つの子コントローラーを持つ親コントローラーがありますが、1つの(親)コントローラーのみでも機能します。

HTML:

<div ng-controller="LoginCheckCtrl">
        <div ng-switch on="user.login"> 
          <div ng-switch-when="false" ng-include="'login'"></div>
          <div ng-switch-when="true" ng-include="'logout'"></div>
        </div>
</div>

コントローラ:

function LoginCheckCtrl($scope) {
    $scope.user = {
        login: false
    };
}

注:これは、1つのコントローラーでのみ機能します。

function LoginCheckCtrl($scope) {
    $scope.user = {
        login: false
    };
    $scope.login = function() {
        console.log($scope.user.login ? 'logged in' : 'not logged in');
        $scope.user.login = true;
    };
    $scope.logout = function() {
        console.log($scope.user.login ? 'logged in' : 'not logged in');
        $scope.user.login = false;
    };
}
于 2012-12-31T11:44:38.557 に答える
0

コントローラの再初期化後も存続する必要がある状態を親スコープに保存できます。$rootScopeにisLoggedInを配置するのも不思議ではないと思います。

また、コントローラー内で初期化することもできますが、この場合はよりクリーンになります(ただし、問題は解決しません)。

于 2012-12-31T12:17:30.640 に答える