如何在使用ControllerAs时使用$ watch更新字段绑定

时间:2016-10-03 19:36:00

标签: angularjs angularjs-scope

在我的角度应用程序中,我使用ui-router设置了视图:

.state('search',
                {
                    url: '/',
                views: {
                    'navigation': {
                        templateUrl: '/app/views/navbartemplate.html',
                        controller: 'navigationController',
                        controllerAs: 'nav'
                    },
                    'content': {
                        templateUrl: '/app/views/search.html',
                        controller: 'searchController',
                        controllerAs: 'search'

                    }
                }

            })

我正在使用来自Identity Server 3的声明,并使用访问令牌和身份声明将用户信息传递给客户端。由于这是一个角度应用程序,因此使用回调检索声明。它接收访问令牌,然后传递该令牌以获取作为异步回调的身份。这全部使用OIDC令牌管理器进行管理。在导航控制器中,我尝试将用户的值(名字姓氏)映射到导航视图中来自此回调的字段。

    //get user information
    // no id token or expired => redirect to get one
    if (vm.mgr.expired) {
        vm.mgr.redirectForToken();
    } else {
        vm.mgr.oidcClient.loadUserProfile(vm.mgr.access_token)
            .then(function(userInfoValues) {
                dataService.setItem(userInfoValues);

            }).then(function() {
                vm.profile = dataService.getItem();
                checkAdmin(vm.profile.sys_admin);
                vm.message = "Welcome, " + vm.profile.given_name + " " + vm.profile.family_name;
                $log.info(vm.profile.sys_admin);
                $log.info(vm.message);

            });
    }

我可以通过日志看到属性已设置,但由于DOM已经呈现UI中的绑定字段,因此永远不会更新。我知道这是注入控制器$ scope的候选者,然后应用手表。然而,每当我这样做时,我得到角度误差,消化已经存在。我试图将手表嵌入第二个.then承诺内,并将其置于功能之外。嵌套在里面时会被忽略,当放在promise之外时我会得到错误。

该手表之前曾被写为(注意nav是视图中的ControllerAs):

$scope.$watch('nav.message', function(){
 checkAdmin(vm.profile.sys_admin);
                vm.message = "Welcome, " + vm.profile.given_name + " " + vm.profile.family_name;

});

更新:经过一些额外的测试后,我将该功能移出了第二个承诺,看起来更像是这样:

   var loadData = function() {

        checkAdmin(vm.profile.sys_admin);
        vm.message = "Welcome, " + vm.profile.given_name + " " + vm.profile.family_name;
        $log.info(vm.profile.sys_admin);
        $log.info(vm.message);
    }

    //get user information
    // no id token or expired => redirect to get one
    if (vm.mgr.expired) {
        vm.mgr.redirectForToken();
    } else {
        vm.mgr.oidcClient.loadUserProfile(vm.mgr.access_token)
            .then(function(userInfoValues) {
                dataService.setIqItem(userInfoValues);
                vm.profile = dataService.getIqItem();
            }).then(loadData);
    }   

我意识到这些功能做了同样的事情,但我发现点击屏幕上的其他按钮来改变CSS主题(导致页面回发/重新渲染的任何内容)会更新绑定,我会看到它们出现在UI中的值中。这看起来好像它与角度代码完成之前的DOM渲染有关,并且范围没有更新。我将在明天尝试深度观察方法,看看是否可以纠正它。

我仍然很好奇如何在Oidc经理返回用户身份后如何更新消息字段?观看Deepwatch或其他一些方法。我已经看到用户使用超时的SO帖子,但这似乎是错误的或不可靠的。这应该是服务而不是视图控制器中的某些东西吗?任何想法都赞赏。

提前致谢

1 个答案:

答案 0 :(得分:0)

解决这个问题我可以看到错误与摘要周期有关,并且范围无法更新绑定。通过类似的帖子,我看到可能的答案表明使用$timeout我不是这个的粉丝,因为这是一个异步调用,并且使用超时感觉很好,因为它可能不是100%可靠。然后我偶然发现了Ben Nadal的一篇博客文章,他在那里解释了$scope.$evalAsync的用法我不会进入完整的博客,但实质上是:   " $ scope。$ evalAsync()表达式放在"异步队列中#34;在每个$ digest迭代开始时刷新。"

鉴于我更新了我的代码,现在看起来像:

 if (vm.mgr.expired) {
            vm.mgr.redirectForToken();
        } else {
            vm.mgr.oidcClient.loadUserProfile(vm.mgr.access_token)
                .then(function(userInfoValues) {
                    $scope.$evalAsync(function() {
                        dataService.setItem(userInfoValues);
                        vm.profile = dataService.getItem();
                        checkAdmin(vm.profile.sys_admin);
                        vm.message = "Welcome, " + vm.profile.given_name + " " + vm.profile.family_name;
                    });
                });
        }

现在评估已提升,以便更新UI中的绑定。