AngularJS:控制器更新ng-model后视图不显示值问题
问题分析与解决方案
这个问题我之前在项目里也碰到过,其实核心原因是控制器被重复实例化了,咱们一步步拆解来看:
为什么输入框是空的?
你在View1和View2里都用了ctrl1控制器,当用ui-router的$state.go切换视图时,ui-router会为View2创建一个全新的ctrl1实例。这意味着:
- View1里的
$scope.selectedList和View2里的$scope.selectedList是两个完全独立的对象 - 你在View1的
goToForm里修改的是第一个控制器实例的selectedList,控制台打印的也是这个实例里的数值 - 而View2的控制器实例初始化时,
selectedList.name还是默认的空字符串,所以输入框自然显示为空
解决办法
这里有几种靠谱的方案,按推荐程度排序:
1. 使用Angular服务(最推荐)
Angular的服务是单例模式,所有控制器都共享同一个服务实例,完美解决跨视图数据共享的问题。
首先创建一个共享数据的服务:
angular.module('yourApp').service('DataShareService', function() { // 这里存需要共享的数据 this.selectedList = { name: "" }; });
然后修改你的ctrl1,让它绑定到服务里的对象:
angular.module('yourApp').controller('ctrl1', function($scope, $state, DataShareService) { // 把作用域的变量指向服务里的对象,两个控制器实例会共用同一个引用 $scope.selectedList = DataShareService.selectedList; $scope.goToForm = function(e) { $scope.selectedList.name = e.name; $state.go('view2'); console.log(e); }; });
这样不管切换到哪个视图,selectedList都是指向服务里的同一个对象,数据自然会同步。
2. 用ui-router的resolve传参
如果只是一次性传递数据,也可以用ui-router的resolve配置,在路由跳转前把数据准备好,传递给目标视图的控制器。
先修改路由配置:
$stateProvider.state('view2', { url: '/view2?name', // 定义路由参数 templateUrl: 'view2.html', controller: 'ctrl1', resolve: { // 这里可以处理数据,然后传递给控制器 selectedName: function($stateParams) { return $stateParams.name; } } });
然后修改goToForm方法,跳转时带上参数:
$scope.goToForm = function(e) { // 传递参数到view2的路由 $state.go('view2', { name: e.name }); console.log(e); };
最后修改ctrl1,接收resolve的数据:
angular.module('yourApp').controller('ctrl1', function($scope, $state, selectedName) { // 如果有传递过来的参数就用,否则用默认值 $scope.selectedList = { name: selectedName || "" }; });
3. 使用$rootScope(不推荐,应急用)
虽然可以用全局的$rootScope来共享数据,但容易造成全局变量污染,维护起来麻烦,只适合临时测试:
// 在View1的ctrl1里 $scope.goToForm = function(e) { $rootScope.selectedList = { name: e.name }; $state.go('view2'); }; // 在View2的ctrl1里 $scope.selectedList = $rootScope.selectedList;
总结
本质问题就是同一个控制器被实例化了两次,作用域不共享。最符合Angular设计理念的方案是用服务来管理共享数据,既能保证数据一致性,也方便后续维护。
内容的提问来源于stack exchange,提问作者user3761308
相关产品推荐
相关产品推荐

