ng-include 导致控制器块重新渲染 [英] ng-include causes the controller block to re render

查看:21
本文介绍了ng-include 导致控制器块重新渲染的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将 ng-switch 与下面的 ng-include 一起使用.问题在于 ng-init 和整个控制器块在任何 ng-includes 更改时重新呈现.

在 login_form.html 中,当用户登录时,我在 LoginCtrl 中设置了 isLoggedIn = true.但是,这会导致重新渲染下面的完整 html,从而再次导致 ng-init.

如何避免这种循环?

 

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

以下是登录表单的 HTML -

<input type="text" placeholder="Email" ng-model="userEmail" class="input-small"/><input type="password" placeholder="密码" ng-model="userPassword" class="input-small"/><button type="submit" ng-click="login(userEmail, userPassword)" class="btn">登录</button></表单>

下面是控制器 -

angularApp.controller('LoginCtrl', function($scope, currentUser){$scope.loginStatus = function(){返回 currentUser.isLoggedIn();};/* $scope.$on('login', function(event, args) {$scope.userName = args.name;});$scope.$on('logout', function(event, args) {$scope.isLoggedIn = false;});*/$scope.login = 函数(电子邮件,密码){currentUser.login(email, password);};$scope.logout = function(){currentUser.logout();};});

打击就是服务-

angularApp.factory('currentUser', function($rootScope) {//服务逻辑//...//var allUsers = {"rob@gmail.com": {name: "Robert Patterson", role: "Admin", email: "rob@gmail.com", password: "rob"},steve@gmail.com":{姓名:史蒂夫谢尔顿",角色:用户",电子邮件:steve@gmail.com",密码:史蒂夫"}}var isUserLoggedIn = false;//这里是公共 API返回 {登录:功能(电子邮件,密码){var user = allUsers[email];var storedPass = user.password;if(storedPass === 密码){isUserLoggedIn = true;返回真;}别的{返回假;}},注销:函数(){$rootScope.$broadcast('退出');isUserLoggedIn = false;},isLoggedIn: 函数(){返回 isUserLoggedIn;}};});

解决方案

我相信您的问题是原型继承的工作方式造成的.ng-include 创建自己的子作用域.在子作用域中分配原始值会在该作用域上创建一个新属性,该属性隐藏/隐藏父属性.

我猜在 login_form.html 中,当用户登录时,您会执行以下操作:

正如上面的链接所解释的,您有三种解决方案:

  1. 在父模型中为模型定义一个对象,然后在子模型中引用该对象的属性:parentObj.isLoggedIn
  2. 在 login_form.html 中使用 $parent.isLoggedIn -- 这将引用 $parent 范围中的原语,而不是创建一个新的原语.例如,
    登录
  3. 在父作用域上定义一个函数,并从子作用域调用它——例如,setIsLoggedIn().这将确保设置的是父作用域属性,而不是子作用域属性.

更新:在检查您的 HTML 时,您实际上可能有两个级别的子作用域,因为 ng-switch 和 ng-include 各自创建了自己的作用域.所以,图片需要一个孙子范围,但三个解决方案是相同的......除了#2,你需要使用 $parent.$parent.isLoggedIn - 丑陋.所以我建议选择 1 或 3.

Update2:@murtaza52 在问题中添加了一些代码...从您的控制器中删除 ng-init="isLoggedIn = false"(您的服务正在管理登录状态通过其 isUserLoggedIn 变量)并在控制器中打开 loginStatus():<div ng-switch on="loginStatus()">.

这是一个工作小提琴.

I am trying to use ng-switch with ng-include below. The problem is with ng-init and the whole controller block getting re-rendered on any ng-includes change.

In the login_form.html, when a user logins, I set the isLoggedIn = true, in the LoginCtrl. However this causes the re-rendering of the full html below, which causes the ng-init again.

How do I avoid this cycle?

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

Below is the HTML for the login form -

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

Below is the controller -

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();
  };

});

Blow is the service -

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

解决方案

I believe your problem is a result of the way prototypal inheritance works. ng-include creates its own child scope. Assigning a primitive value in a child scope creates a new property on that scope that shadows/hides the parent property.

I'm guessing that in login_form.html you do something like the following when a user logs in:

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

Before isLoggedIn is set to true, this is what your scopes look like:

After isLoggedIn is set to true, this is what your scopes look like:

Hopefully the pictures make it clear why this is causing you problems.

For more information about why prototypal inheritance works this way with primitives, please see What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

As the above link explains, you have three solutions:

  1. define an object in the parent for your model, then reference a property of that object in the child: parentObj.isLoggedIn
  2. use $parent.isLoggedIn in login_form.html -- this will then reference the primitive in the $parent scope, rather than create a new one. E.g.,
    <a ng-click="$parent.isLoggedIn=true">login</a>
  3. define a function on the parent scope, and call it from the child -- e.g., setIsLoggedIn(). This will ensure the parent scope property is being set, not a child scope property.

Update: in reviewing your HTML, you may actually have two levels of child scopes, since ng-switch and ng-include each create their own scopes. So, the pictures would need a grandchild scope, but the three solutions are the same... except for #2, where you would need to use $parent.$parent.isLoggedIn -- ugly. So I suggest option 1 or 3.

Update2: @murtaza52 added some code to the question... Remove ng-init="isLoggedIn = false" from your controller (your service is managing the login state via its isUserLoggedIn variable) and switch on loginStatus() in your controller: <div ng-switch on="loginStatus()">.

Here is a working fiddle.

这篇关于ng-include 导致控制器块重新渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆