【问题标题】:$scope value doesn't get updated in other controller$scope 值不会在其他控制器中更新
【发布时间】:2016-02-24 23:00:20
【问题描述】:

我在更新视图中的值时遇到问题。让我向您展示我的代码,并稍微解释一下发生了什么。我知道代码有点乱,因为我现在尝试了很多代码组合。

我有这个 accCtrl 控制器

controllers.accCtrl = function($scope, sessionFactory){
    sessionFactory.isLoggedIn().then(function(data){
        console.log(data.logged_in);
        $scope.loggedIn = data.logged_in;
    });
    $scope.logOut = function(){
        sessionFactory.logOutUser().then(function(data){
            $scope.loggedIn = data.logged_in;
        });
    }
}

控制台注销是false,这个变量$scope.loggedIn通过显示或隐藏登录、注册、我的个人资料和注销按钮来控制我的html

<div ng-controller="accCtrl">
    {{loggedIn}}
        <ul>
        <li ng-hide="loggedIn">
            <a href="#/login">
                <b>Login</b>
            </a>
        </li>
        <li ng-hide="loggedIn">
            <a href="#/register" >
                <b>Register</b>
            </a>
        </li>
        <li ng-show="loggedIn" >
            <a href="#/my_profile">
                <b >My profile</b>
            </a>
        </li>
        <li ng-show="loggedIn"> 
            <a ng-click="logOut()">
                <b>Log out</b>
            </a>
        </li>
    </ul>
</div>

现在用户尝试登录,所以他点击登录按钮,并显示登录表单。这个登录功能写在loginCtrl

    controllers.loginCtrl = function($scope, $http, $location, $timeout, sessionFactory){
    $scope.loginUser = function () {
        $http({
            method: 'POST',
            url: $location.protocol() + '://' + $location.host() + '/server/api/users/login',
            headers: {'Content-Type': 'application/x-www-form-urlencoded'},
            data : $.param({
                username : $scope.username,
                password : $scope.password
            })
        }).success(function(data){
                sessionFactory.isLoggedIn().then(function(data){
                    $scope.loggedIn = data.logged_in;
                });
                window.location.href="/#/home";
        });
    };
}

成功登录后,他或她被重定向到主页,但问题是帐户控制器中的$scope.loggedIn变量没有更新即使loginCtrl中的console.log(data.logged_in)设置为true

如果用户按下注销按钮,一切都会再次正常,因为我正在调用 accCtrl 中的函数。所以唯一的问题是用户登录时,因为他在另一个控制器中这样做。

这也是我的 sessionFactory,以防你不想看到我如何检查用户是否已登录

app.factory('sessionFactory', ['$http', '$location', function($http, $location){
    var factory = {};

    factory.logOutUser = function(){
        return $http({
            method: 'GET',
            url: $location.protocol() + '://' + $location.host() + '/server/api/users/logout'
        }).then(function successCallback(response){
            return response.data;
        },function errorCallback(response) {
            console.log('error logging out: ' + response);
        });
    }
    factory.isLoggedIn = function(){
        return $http({
            method: 'GET',
            url: $location.protocol() + '://' + $location.host() + '/server/api/users/isLoggedIn'
        }).then(function successCallback(response){
            console.log(response.data);
            return response.data;
        },function errorCallback(response) {
            console.log('Checking login failed: ' + response);
        });
    }

    return factory;
}]);

我的 app.js

var app = angular.module('app', ['ngRoute', 'ngAnimate', 'ui.sortable', 'ngFileUpload'])
app.config(function($routeProvider){
    $routeProvider.
    when('/', {controller:'homeCtrl', templateUrl:'app/templates/home.html'}).
    when('/home', {controller:'homeCtrl', templateUrl:'app/templates/home.html'}).
    when('/contact', {controller:'contactCtrl', templateUrl:'app/templates/contact.html'}).
    when('/about_us', {controller:'aboutUsCtrl', templateUrl:'app/templates/aboutUs.html'}).
    when('/cookies', {controller:'cookiesCtrl', templateUrl:'app/templates/cookies.html'}).
    when('/faqs', {controller:'faqsCtrl', templateUrl:'app/templates/faqs.html'}).
    when('/register', {controller:'registerCtrl', templateUrl:'app/templates/register.html'}).
    when('/login', {controller:'loginCtrl', templateUrl:'app/templates/login.html'}).
    when('/my_profile', {controller:'myProfileCtrl', templateUrl:'app/templates/myProfile.html'}).
    when('/trade/:param1', {controller:'tradeCtrl', templateUrl:'app/templates/trade.html'}).
    when('/user/:param1', {controller:'userCtrl', templateUrl:'app/templates/user.html'}).
    when('/swap/:param1', {controller:'subCategoriesCtrl', templateUrl:'app/templates/subCategories.html'}).
    when('/swap/:param1/:param2', {controller:'products', templateUrl:'app/templates/products.html'}).
    when('/swap/:param1/:param2/:param3', {controller:'product', templateUrl:'app/templates/product.html'}).
    otherwise({ redirectTo: '/home'});
  });

我可能需要实现一些手表或类似的功能,但我真的不知道怎么做,如果你能帮助我,我将不胜感激。

图片说明

显示登录和注册按钮

用户点击登录按钮并成功登录,但按钮没有刷新,因为在loginCtrl中发生了动作,但按钮在accCtrl中

在浏览器中按 f5 后,accCtrl 中的按钮会正确更新。

TLTR

一旦用户登录loginCtrl,我必须更新accCtrl 中的$scope.loggedIn

如果您需要任何其他信息,请告诉我

【问题讨论】:

    标签: javascript angularjs


    【解决方案1】:

    出现问题是因为angularjs中的控制器只初始化了一次,除非你设置为重新初始化。尝试在accCtrl 中提醒某些内容,即使您多次导航到该页面,它也只会提醒一次。点击ctrl+f5 有效,因为它重新初始化了您的控制器。您可以简单地使用$window.location.reload() 重新初始化控制器。 $window.location.reload() 所做的是它不仅会重新加载您的控制器,还会重新加载您的服务。由于您使用的是ngRoute,所以我能想到的重新初始化您的控制器的方法就是使用$window.location.reload();

    .success(function(data){
                    sessionFactory.isLoggedIn().then(function(data){
                        $scope.loggedIn = data.logged_in;
                    });
                    window.location.reload(); //the only workaround i could find with ngroute as for now.
                    window.location.href="/#/home";
            });
    

    但是使用ui.Router$stateProvider 为您提供了仅重新初始化控制器的选项,如下所示。

    .state('home', {
        url: '/home',
        templateUrl: 'templates/home.html',
        controller: 'accCtrl',
        reload: true //will reload controller when state is being access
    });
    
    $state.transitionTo($state.current, {}, { reload: true, inherit: true, notify: true });
    

    $state.go('.', null, { reload: true });
    

    将解决重新初始化控制器的问题,这似乎是您现在的问题。

    【讨论】:

    • 谢谢回答,但我还没有使用任何状态提供。我还添加了我的 app.js。您能否创建示例我的代码应该是什么样子。当 loginCtrl 中发生某些事情时,我需要更新我的 accCtrl...
    • 当您的 home.html 页面被访问时,您是否尝试过重新初始化 accCtrl?类似于使用 $location.reload()。
    • 所以如果我做对了。一旦用户登录,我必须在登录控制器上创建 $route.reload(),所以 accCtrl 得到更新。但首先我必须为主页制作 .state?
    • 如果你为主页设置状态然后使用 $state.transitionTo("home", {}, {inherit: false, reload: true, notify: true});将代替使用 window.location.href="/#/home";。正如我所说的,问题是你的控制器只初始化了一次。
    • 我认为我使用指令也可以解决问题,让我解决一下。
    【解决方案2】:

    好的,您在 $scope.loggedIn 变量方面犯了 2 个错误。

    1) 你很困惑,因为控制台为 $scope.loggedIn 记录了一个 false 和一个 true 值;发生这种情况是因为 Promise 是异步的,并且在您要求 session 登录后代码会继续运行。

    sessionFactory.isLoggedIn().then(function(data){
        console.log(data);                     (2)
        $scope.loggedIn = data.logged_in;
        console.log($scope.loggedIn);          (3)
    });
    console.log($scope.loggedIn);              (1) <-- executes first before promise resolves
    window.location.href="/#/home";
    

    所以执行日志中的最后一个但在执行日志中的第一个自然会产生 false,只要在 promise 开始执行之前用户没有被登录。承诺解决后,它会产生数据并且是真实的。更多关于 herehere 的承诺。

    2) 您正在使用 ajax 请求更改角度变量,并且当您在角度框架之外对范围进行更改时需要通知角度。 One mechanism angular has for that 正在使用 $rootScope.$apply() 或 $scope.$apply() 显式调用摘要循环。我建议你在你的服务上做这项工作。如果你想在控制器中使用它,应该这样做:

    $http({
        method: 'POST',
        url: $location.protocol() + '://' + $location.host() + '/server/api/users/login',
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
        data : $.param({
            username : $scope.username,
            password : $scope.password
        })
    }).success(function(data){
        ...
        $rootScope.$apply();
    });
    

    【讨论】:

    • 关于第 1 点:是的,我刚从 php 转到 js,我必须说,一切都颠倒了。我将阅读有关承诺的内容。关于第 2 点。$scope.$apply() 对我不起作用
    • 抱歉,我的错误,$http 调用已经结束了 $apply 调用...您应该在loggedIn 变量上使用$watch 来解决登录问题。我稍后会编辑我的答案...
    • $http 是一个角度服务,应该不需要$scope.$apply,我很惊讶没有抛出异常。 $apply 仅用于当事情发生在角度范围之外时,例如在 jQuery 事件处理程序中。另外.success.error 已弃用,请使用.then.catch
    • 如果我尝试 $apply,当然会抛出异常。我仍然需要解决这个问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多