如何在 angularjs ui-router 中的状态之间共享 $scope 数据?

Posted

技术标签:

【中文标题】如何在 angularjs ui-router 中的状态之间共享 $scope 数据?【英文标题】:How do I share $scope data between states in angularjs ui-router? 【发布时间】:2015-02-26 02:18:49 【问题描述】:

如果不使用服务或在父控制器中构建观察者,如何让子状态访问主控制器的$scope

  .state("main", 
      controller:'mainController',
      url:"/main",
      templateUrl: "main_init.html"
  )  
  .state("main.1", 
      controller:'mainController',
      parent: 'main',
      url:"/1",
      templateUrl: 'form_1.html'
  )  
  .state("main.2", 
      controller:'mainController',
      parent: 'main',
      url: "/2",
      templateUrl: 'form_2.html'
  )  

我无法在子状态下访问 mainController 范围——或者更确切地说,我正在获取该范围的另一个实例——这不是我想要的。我觉得我错过了一些简单的东西。 状态对象中有一个共享数据配置选项,但我不确定这是否应该用于类似的事情。

【问题讨论】:

孩子可以访问父母。你能在 plunkr 中复制你的问题吗? 这是一个很好的例子,但是我如何让它使用控制器作为语法而不是 $scope? 我想知道;我正在尝试做同样的事情,但担心我可能不得不将$scope 注入控制器,即使我使用controller as 语法(并且不在控制器的代码中使用$scope - 只需将其提供给ui-路由器)。 【参考方案1】:

我created working plunker,展示如何使用$scope和UI-Router。

状态定义不变:

$stateProvider
    // States
 .state("main", 
      controller:'mainController',
      url:"/main",
      templateUrl: "main_init.html"
  )  
  .state("main.1", 
      controller:'mainController',
      parent: 'main',
      url:"/1",
      templateUrl: 'form_1.html'
  )  
  .state("main.2", 
      controller:'mainController',
      parent: 'main',
      url: "/2",
      templateUrl: 'form_2.html'
  )  

但是每个状态可以有不同的控制器。为什么?因为每个 state 的每个 view 都获得了已定义 controllernew instance。因此,虽然我们有如下图所示的 mainController,但我们可以肯定,如果我们导航到状态 'main.2',它将被实例化两次。

controller('mainController', function ($scope) 
  $scope.Model = $scope.Model || Name : "xxx";
)

但是我们可以看到here,我们检查$scope.Model 是否已经存在...如果不存在(父状态),我们使用新实例对其进行实例化强> Name : "xxx"

好吧,我的意思是:只有父状态会初始化$scope.Model。所有其他人都会得到已经填满的。如何?好吧,这就是答案:

Scope Inheritance by View Hierarchy Only

请记住,如果您的状态视图是嵌套的,则范围属性只会沿状态链继承。范围属性的继承与您的状态的嵌套无关,而与您的视图(模板)的嵌套有关。

您完全有可能拥有嵌套状态,其模板在您的站点内的各种非嵌套位置填充 ui-views。在这种情况下,您不能期望在子状态的视图中访问父状态视图的范围变量。

因此,如文档中所述。因为我们的子视图嵌套在父视图中,所以作用域是继承的。

Understanding Scopes

在 AngularJS 中,子作用域通常从其父作用域原型继承。 ...

有一个“。”在您的模型中将确保原型继承发挥作用。

// So, use
<input type="text" ng-model="someObj.prop1"> 
// rather than
<input type="text" ng-model="prop1">.

就是这样。我们从UI-Router 视图和角度范围获得继承,并且因为我们巧妙地使用了引用类型(Model),即在'.' 点定义ng-model - 我们可以共享数据现在

注意:有点 '.'在 ng-model="Model.PropertyName 中只是意味着,有一个 reference 对象 Model 具有一些属性:PropertyName

查看working example here

【讨论】:

这是非常有用的。感谢您花时间以有序的方式解释这一点——这种蒸馏水平不会被忽视。我根据您的建议重建了 stateProvider.state 对象和我的模板,一切都按照我希望的方式工作:范围沿链继承——在构建视图时没有考虑这个基本原则,我觉得很傻——再次感谢你我希望所有关于 SO 的答案都像这样深思熟虑。 Radim,非常感谢您对 SO 的帮助! @Radim Kohler 我的登录状态有问题。你能帮我解决我的问题吗:***.com/questions/34690439/… 谁知道我是否删除了 "|| ;"在 mainController 内部它不起作用? @Radim Kohler 有什么办法可以帮助我解决这个问题***.com/questions/58126482/…【参考方案2】:

您可以通过$rootScope 获得整个范围。如果您只需要范围的一部分,ui-router 具有custom data 功能。

以下是如何创建多步骤表单。我需要路线包含有关其流程中步骤的信息。

首先,我有一些带有 UI-router 的路由:

  // Sign UP routes
  .state('sign-up', 
    abstract: true,
    url: '/sign-up',
    controller: 'SignupController',
    templateUrl: 'sign-up/index.html',
  )
  .state('sign-up.start', 
    url: '-start',
    templateUrl: 'sign-up/sign-up.start.html',
    data:  step: 0, title: 'Welcome to Mars!', ,
  )
  .state('sign-up.expertise', 
    url: '-expertise',
    templateUrl: 'sign-up/sign-up.expertise.html',
    data:  step: 1, title: 'Your Expertise',
  )

注意:

每个路由中的data 元素。 abstract 状态有SignupController。这是这个多步骤表单的唯一控制器。 abstract 不是必需的,但对于这个用例来说是有意义的。

SignupController.js

angular.module('app').controller('SignupController', function($scope, $state) 
  $scope.state = $state;
);

这里我们获取ui-router的$state并把它放在$scope

这里是主模板'sign-up/index.html',:

<h2>state.current.data.title</h2>

<div>This is a multi-step-progress control state.current.data.step</div>

<form id="signUpForm" name="signUpForm" novalidate>
  <div ui-view></div>
</form>

子模板可以是任何他们喜欢的。

【讨论】:

这为我节省了一些时间。感谢分享 如果你想简化视图模板中的$state,你可以这样做:$scope.state = $state.current.data;和视图中:state.title【参考方案3】:

这个想法是你在父->子继承中使用范围:

 .state("main", 
      controller:'mainController',
      abstract: true,
      url:"/main",
      templateUrl: "main_init.html"
  )  
  .state("main.1", 
      controller:'mainController1',
      parent: 'main',
      url:"/1",
      templateUrl: 'form_1.html'
  )  
  .state("main.2", 
      controller:'mainController2',
      parent: 'main',
      url: "/2",
      templateUrl: 'form_2.html'
  )  

使用起来很简单,你有 3 个控制器,一个是共享的(mainController),每个视图都有自己的。

【讨论】:

然后在子控制器中访问父级的 $scope:$scope.$parent 我得到了范围,甚至没有提到“抽象:真实”所以如果我不提到有什么缺点【参考方案4】:

如果您使用嵌套视图,请不要编写任何其他控制器。通过这种方式,它们将共享相同的控制器数据。

.state("main", 
            url: "/main",
            templateUrl: "templates/Ders",
            controller: "DersController as DersC"
       ).state("main.child1", 
            url: "/child1",
            templateUrl: "templates/Ders/child1"
       ).state("main.child2", 
            url: "/child2",
            templateUrl: "templates/Ders/child2"
        )

【讨论】:

如果我想要 child1Controller 和 child2Controller 分别用于 child1 和 child2 怎么办?【参考方案5】:

将共享变量分组为您可以在每个控制器中访问的服务不是最简单的解决方案吗? ...

【讨论】:

这是一个简单的解决方案,但不会像(1)视图如何访问父控制器(干净地使用controller as)和(2)如何将父控制器注入指令(干净地使用require),如果控制器可以将依赖的控制器实例注入其中?

以上是关于如何在 angularjs ui-router 中的状态之间共享 $scope 数据?的主要内容,如果未能解决你的问题,请参考以下文章

Angularjs中使用ui-route如何异步加载组件?

如何在 angularjs ui-router 中的状态之间共享 $scope 数据?

如何在angularjs ui-router中的状态之间共享$ scope数据?

AngularJS中ui-router全攻略

angularJs的ui-router总结

AngularJS ui-router 登录认证