AngularJS,路由之间如何传递作用域

87

我有一个表格的情况,需要跨越多个页面 (可能不是理想的方式,但事实如此)。我希望在整个表单中设定一个作用域,使其随着你的操作而填充,这样如果用户在步骤之间来回切换就很容易记住状态。

所以,在非常伪代码中,我需要做以下几步:

  1. 设置 $scope.val = <某些动态数据>
  2. 点击一个链接并路由到一个新的模板(很可能还是同一个控制器)。
  3. $scope.val 应该仍然是上一页的相同值。

是否以某种方式持久化作用域的数据才是解决这个问题的正确方法,还是有其他方法?除了将其保存在数据库中,您甚至可以创建具有路由之间持久化作用域的控制器吗?


作为对ganaraj的补充:在这里,您可以找到一篇非常好的博客文章,并配有屏幕录像,介绍如何使不同的控制器进行通信。还有一些有用的jsfiddles可供使用。http://onehungrymind.com/angularjs-communicating-between-controllers/ 希望能帮到您。 - F Lekschas
3个回答

138

你需要使用服务,因为服务将在您的应用程序生命周期内持续存在。

假设您想保存与用户相关的数据,

这是您定义服务的方式:

app.factory("user",function(){
        return {};
});

在你的第一个控制器中:

app.controller( "RegistrationPage1Controller",function($scope,user){
    $scope.user = user;
    // and then set values on the object
    $scope.user.firstname = "John";
    $scope.user.secondname = "Smith";
});

app.controller( "RegistrationSecondPageController",function($scope,user){
        $scope.user = user;
        // and then set values on the object
        $scope.user.address = "1, Mars";

    });

6
啊!我之前尝试过,但无法使其运作,因为我在两个路由中使用了相同的控制器,所以每次进入新路由时,旧页面上输入的值会被默认值覆盖。现在有两个控制器或没有默认值,这种情况就不会再发生了。谢谢! - Erik Honn
1
Value Recipe是什么意思?https://docs.angularjs.org/guide/providers,例如`myApp.value('clientId', 'a12345654321x');`,它是否也在路由之间保持持久性? - The Bndr
@TheBndr:应该是的。就我所知,值只是服务的一种特殊形式。 - Robert Koritnik
3
如果重新加载页面,服务不会保留数据...因此,如果您在表单的第4页并重新加载该页面,则会丢失所有已填写的数据。 - danielrvt
1
好答案!此外,对于采用此答案的人而言,一个风格指南:那些本身不是构造函数(即用作new XX的服务)的服务应以小写驼峰命名:https://github.com/mgechev/angularjs-style-guide。 - Matt Byrne
显示剩余3条评论

9
这项服务可以运行,但只使用普通的作用域和控制器实现它的逻辑方式是设置您的控制器和元素,使其反映您的模型结构。特别是,您需要一个父元素和控制器来建立一个父作用域。表单的各个页面应该驻留在一个视图中,这个视图是父级的子级。即使更新了子视图,父作用域仍然存在。
我假设您正在使用ui-router,以便您可以拥有嵌套的命名视图。然后,在伪代码中:
<div ng-controller="WizardController">
  <div name="stepView" ui-view/>
</div>

然后,WizardController定义了您希望在多页表单(我称之为“向导”)的各个步骤之间保留的作用域变量。然后,您的路由将仅更新stepView。每个步骤都可以有自己的模板、控制器和作用域,但它们的作用域会在页面之间丢失。但是,在WizardController中的作用域将在所有页面上保持不变。
要从子控制器更新WizardController作用域,您需要使用类似于$scope.$parent.myProp = 'value'的语法,或者为每个作用域变量在WizardController上定义一个setMyProp函数。否则,如果您尝试直接从子控制器设置父作用域变量,您最终只会在子级上创建一个新的作用域变量,遮蔽父变量。
这有点难以解释,对于缺乏完整示例的情况我感到抱歉。基本上,您需要一个建立父作用域的父控制器,该作用域将在表单的所有页面上保留。

1
这可以使用ui-router实现(这是一种非常好的设计页面的方式),但不能直接使用。直接使用服务方法是最好的选择。 - Erik Honn
1
只是为了澄清,父级作用域属性将始终被子作用域继承。但是,如果您想从子作用域设置父作用域属性,则需要在父对象上访问它,否则您将在子作用域上创建一个同名的新属性。可以通过以下方式设置父级作用域属性:$scope.$parent.myProp = 'hello world'; - mbursill
1
这种方法比使用服务要好得多。服务是单例的,因此在那里定义的任何状态都是应用程序全局的。如果用户在向导的某个部分退出,然后重新启动它,那么服务中将保留来自上一次运行的剩余状态 - 除非您确保在每个退出点正确清理服务,但这很容易成为一个重大的维护问题! - Dan King
更加热切地期待这个答案。 - Clay Banks
如果您没有使用Angular UI Router,那么服务可能是首先想到的东西。但是,如果您正在使用UI Router,则它具有嵌套解析功能,可以在嵌套视图之间保留信息。我认为这比尝试访问父作用域更加清晰。https://medium.com/opinionated-angularjs/advanced-routing-and-resolves-a2fcbf874a1c - losmescaleros

6

数据可以通过两种方式在控制器之间传递

  1. $rootScope
  2. Model

以下示例演示使用模型传递值的方法

app.js

angular.module('testApp')
  .controller('Controller', Controller)
  .controller('ControllerTwo', ControllerTwo)
  .factory('SharedService', SharedService);

SharedService.js

function SharedService($rootScope){

 return{
    objA: "value1",
    objB: "value2"
  }
}

//修改控制器A中的值

Controller.js

function Controller($scope, SharedService){

 $scope.SharedService = SharedService;

 $scope.SharedService.objA = "value1 modified";
}

//访问controllertwo中的值

ControllerTwo.js

function ControllerTwo($scope, SharedService){

 $scope.SharedService = SharedService;

 console.log("$scope.SharedService.objA"+$scope.SharedService.objA); // Prints "value1 modified"
}

希望这可以帮到您。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接