简体   繁体   English

AngularJS:如何在控制器之间传递变量?

[英]AngularJS: How can I pass variables between controllers?

I have two Angular controllers:我有两个 Angular 控制器:

function Ctrl1($scope) {
    $scope.prop1 = "First";
}

function Ctrl2($scope) {
    $scope.prop2 = "Second";
    $scope.both = Ctrl1.prop1 + $scope.prop2; //This is what I would like to do ideally
}

I can't use Ctrl1 inside Ctrl2 because it is undefined.我不能使用Ctrl1里面Ctrl2 ,因为它是不确定的。 However if I try to pass it in like so…但是,如果我尝试像这样传递它......

function Ctrl2($scope, Ctrl1) {
    $scope.prop2 = "Second";
    $scope.both = Ctrl1.prop1 + $scope.prop2; //This is what I would like to do ideally
}

I get an error.我收到一个错误。 Does anyone know how to do this?有谁知道如何做到这一点?

Doing正在做

Ctrl2.prototype = new Ctrl1();

Also fails.也失败了。

NOTE: These controllers are not nested inside each other.注意:这些控制器没有相互嵌套。

One way to share variables across multiple controllers is to create a service and inject it in any controller where you want to use it.在多个控制器之间共享变量的一种方法是创建一个服务并将其注入到您想要使用它的任何控制器中。

Simple service example:简单的服务示例:

angular.module('myApp', [])
    .service('sharedProperties', function () {
        var property = 'First';

        return {
            getProperty: function () {
                return property;
            },
            setProperty: function(value) {
                property = value;
            }
        };
    });

Using the service in a controller:在控制器中使用服务:

function Ctrl2($scope, sharedProperties) {
    $scope.prop2 = "Second";
    $scope.both = sharedProperties.getProperty() + $scope.prop2;
}

This is described very nicely in this blog (Lesson 2 and on in particular).这在这个博客中有很好的描述(特别是第 2 课及以后)。

I've found that if you want to bind to these properties across multiple controllers it works better if you bind to an object's property instead of a primitive type (boolean, string, number) to retain the bound reference.我发现,如果您想跨多个控制器绑定到这些属性,如果您绑定到对象的属性而不是原始类型(布尔值、字符串、数字)以保留绑定引用,则效果会更好。

Example: var property = { Property1: 'First' };示例: var property = { Property1: 'First' }; instead of var property = 'First';而不是var property = 'First'; . .


UPDATE: To (hopefully) make things more clear here is a fiddle that shows an example of:更新:为了(希望)让事情更清楚,这里有一个小提琴,显示了一个例子:

  • Binding to static copies of the shared value (in myController1)绑定到共享值的静态副本(在 myController1 中)
    • Binding to a primitive (string)绑定到原语(字符串)
    • Binding to an object's property (saved to a scope variable)绑定到对象的属性(保存到作用域变量)
  • Binding to shared values that update the UI as the values are updated (in myController2)绑定到在值更新时更新 UI 的共享值(在 myController2 中)
    • Binding to a function that returns a primitive (string)绑定到返回原语(字符串)的函数
    • Binding to the object's property绑定到对象的属性
    • Two way binding to an object's property两种方式绑定到对象的属性

I like to illustrate simple things by simple examples :)我喜欢用简单的例子来说明简单的事情:)

Here is a very simple Service example:这是一个非常简单的Service示例:


angular.module('toDo',[])

.service('dataService', function() {

  // private variable
  var _dataObj = {};

  // public API
  this.dataObj = _dataObj;
})

.controller('One', function($scope, dataService) {
  $scope.data = dataService.dataObj;
})

.controller('Two', function($scope, dataService) {
  $scope.data = dataService.dataObj;
});

And here the jsbin这里是jsbin

And here is a very simple Factory example:这是一个非常简单的Factory示例:


angular.module('toDo',[])

.factory('dataService', function() {

  // private variable
  var _dataObj = {};

  // public API
  return {
    dataObj: _dataObj
  };
})

.controller('One', function($scope, dataService) {
  $scope.data = dataService.dataObj;
})

.controller('Two', function($scope, dataService) {
  $scope.data = dataService.dataObj;
});

And here the jsbin这里是jsbin


If that is too simple, here is a more sophisticated example如果这太简单了,这里有一个更复杂的例子

Also see the answer here for related best practices comments请参阅此处的答案以获取相关的最佳实践评论

--- I know this answer is not for this question, but I want people who reads this question and want to handle Services such as Factories to avoid trouble doing this ---- --- 我知道这个答案不是针对这个问题的,但我希望阅读这个问题并想要处理诸如工厂之类的服务的人避免这样做的麻烦 ----

For this you will need to use a Service or a Factory.为此,您需要使用服务或工厂。

The services are the BEST PRACTICE to share data between not nested controllers.这些服务是在非嵌套控制器之间共享数据的最佳实践

A very very good annotation on this topic about data sharing is how to declare objects.关于这个关于数据共享的主题,一个非常好的注释是如何声明对象。 I was unlucky because I fell in a AngularJS trap before I read about it, and I was very frustrated.我很倒霉,因为我在读到它之前就掉入了 AngularJS 的陷阱,我非常沮丧。 So let me help you avoid this trouble.所以让我来帮你避免这个麻烦。

I read from the "ng-book: The complete book on AngularJS" that AngularJS ng-models that are created in controllers as bare-data are WRONG!我从“ng-book: The complete book on AngularJS”中读到,在控制器中作为裸数据创建的 AngularJS ng-models 是错误的!

A $scope element should be created like this: $scope 元素应该像这样创建:

angular.module('myApp', [])
.controller('SomeCtrl', function($scope) {
  // best practice, always use a model
  $scope.someModel = {
    someValue: 'hello computer'
  });

And not like this:而不是这样:

angular.module('myApp', [])
.controller('SomeCtrl', function($scope) {
  // anti-pattern, bare value
  $scope.someBareValue = 'hello computer';
  };
});

This is because it is recomended(BEST PRACTICE) for the DOM(html document) to contain the calls as这是因为建议(最佳实践)为 DOM(html 文档)包含调用作为

<div ng-model="someModel.someValue"></div>  //NOTICE THE DOT.

This is very helpful for nested controllers if you want your child controller to be able to change an object from the parent controller....如果您希望子控制器能够从父控制器更改对象,这对于嵌套控制器非常有用....

But in your case you don't want nested scopes, but there is a similar aspect to get objects from services to the controllers.但是在您的情况下,您不需要嵌套范围,但是从服务到控制器获取对象也有类似的方面。

Lets say you have your service 'Factory' and in the return space there is an objectA that contains objectB that contains objectC.假设您有您的服务“工厂”,并且在返回空间中有一个包含 objectB 的 objectA,其中包含 objectC。

If from your controller you want to GET the objectC into your scope, is a mistake to say:如果您想从您的控制器中将 objectC 获取到您的范围内,那么说:

$scope.neededObjectInController = Factory.objectA.objectB.objectC;

That wont work... Instead use only one dot.那行不通……而是只使用一个点。

$scope.neededObjectInController = Factory.ObjectA;

Then, in the DOM you can call objectC from objectA.然后,在 DOM 中,您可以从 objectA 调用 objectC。 This is a best practice related to factories, and most important, it will help to avoid unexpected and non-catchable errors.这是与工厂相关的最佳实践,最重要的是,它将有助于避免意外和无法捕获的错误。

Solution without creating Service, using $rootScope:不创建服务的解决方案,使用 $rootScope:

To share properties across app Controllers you can use Angular $rootScope.要在应用程序控制器之间共享属性,您可以使用 Angular $rootScope。 This is another option to share data, putting it so that people know about it.这是共享数据的另一种选择,让人们知道它。

The preferred way to share some functionality across Controllers is Services, to read or change a global property you can use $rootscope.跨控制器共享某些功能的首选方法是服务,要读取或更改可以使用 $rootscope 的全局属性。

var app = angular.module('mymodule',[]);
app.controller('Ctrl1', ['$scope','$rootScope',
  function($scope, $rootScope) {
    $rootScope.showBanner = true;
}]);

app.controller('Ctrl2', ['$scope','$rootScope',
  function($scope, $rootScope) {
    $rootScope.showBanner = false;
}]);

Using $rootScope in a template (Access properties with $root):在模板中使用 $rootScope(使用 $root 访问属性):

<div ng-controller="Ctrl1">
    <div class="banner" ng-show="$root.showBanner"> </div>
</div>

The sample above worked like a charm.上面的示例就像一个魅力。 I just did a modification just in case I need to manage multiple values.我只是做了一个修改,以防万一我需要管理多个值。 I hope this helps!我希望这有帮助!

app.service('sharedProperties', function () {

    var hashtable = {};

    return {
        setValue: function (key, value) {
            hashtable[key] = value;
        },
        getValue: function (key) {
            return hashtable[key];
        }
    }
});

I tend to use values, happy for anyone to discuss why this is a bad idea..我倾向于使用价值观,很高兴有人讨论为什么这是一个坏主意。

var myApp = angular.module('myApp', []);

myApp.value('sharedProperties', {}); //set to empty object - 

Then inject the value as per a service.然后根据服务注入值。

Set in ctrl1:在 ctrl1 中设置:

myApp.controller('ctrl1', function DemoController(sharedProperties) {
  sharedProperties.carModel = "Galaxy";
  sharedProperties.carMake = "Ford";
});

and access from ctrl2:并从 ctrl2 访问:

myApp.controller('ctrl2', function DemoController(sharedProperties) {
  this.car = sharedProperties.carModel + sharedProperties.carMake; 

});

The following example shows how to pass variables between siblings controllers and take an action when the value changes.下面的例子展示了如何在兄弟控制器之间传递变量在值改变时采取行动。

Use case example: you have a filter in a sidebar that changes the content of another view.用例示例:您在侧栏中有一个过滤器,用于更改另一个视图的内容。

 angular.module('myApp', []) .factory('MyService', function() { // private var value = 0; // public return { getValue: function() { return value; }, setValue: function(val) { value = val; } }; }) .controller('Ctrl1', function($scope, $rootScope, MyService) { $scope.update = function() { MyService.setValue($scope.value); $rootScope.$broadcast('increment-value-event'); }; }) .controller('Ctrl2', function($scope, MyService) { $scope.value = MyService.getValue(); $scope.$on('increment-value-event', function() { $scope.value = MyService.getValue(); }); });
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <div ng-app="myApp"> <h3>Controller 1 Scope</h3> <div ng-controller="Ctrl1"> <input type="text" ng-model="value"/> <button ng-click="update()">Update</button> </div> <hr> <h3>Controller 2 Scope</h3> <div ng-controller="Ctrl2"> Value: {{ value }} </div> </div>

I'd like to contribute to this question by pointing out that the recommended way to share data between controllers, and even directives, is by using services (factories) as it has been already pointed out, but also I'd like to provide a working practical example of how to that should be done.我想通过指出在控制器甚至指令之间共享数据的推荐方法是使用已经指出的服务(工厂)来为这个问题做出贡献,但我也想提供一个如何做到这一点的工作实际例子。

Here is the working plunker: http://plnkr.co/edit/Q1VdKJP2tpvqqJL1LF6m?p=info这是工作plunker: http ://plnkr.co/edit/Q1VdKJP2tpvqqJL1LF6m?p=info

First, create your service , that will have your shared data :首先,创建您的服务,它将拥有您的共享数据

app.factory('SharedService', function() {
  return {
    sharedObject: {
      value: '',
      value2: ''
    }
  };
});

Then, simply inject it on your controllers and grab the shared data on your scope:然后,只需将其注入您的控制器并在您的范围内获取共享数据:

app.controller('FirstCtrl', function($scope, SharedService) {
  $scope.model = SharedService.sharedObject;
});

app.controller('SecondCtrl', function($scope, SharedService) {
  $scope.model = SharedService.sharedObject;
});

app.controller('MainCtrl', function($scope, SharedService) {
  $scope.model = SharedService.sharedObject;
});

You can also do that for your directives , it works the same way:您也可以为您的指令执行此操作,它的工作方式相同:

app.directive('myDirective',['SharedService', function(SharedService){
  return{
    restrict: 'E',
    link: function(scope){
      scope.model = SharedService.sharedObject;
    },
    template: '<div><input type="text" ng-model="model.value"/></div>'
  }
}]);

Hope this practical and clean answer can be helpful to someone.希望这个实用而干净的答案可以对某人有所帮助。

You could do that with services or factories.你可以通过服务或工厂来做到这一点。 They are essentially the same apart for some core differences.除了一些核心差异之外,它们基本上相同。 I found this explanation on thinkster.io to be the easiest to follow.我发现thinkster.io上的这个解释最容易理解 Simple, to the point and effective.简单、中肯、有效。

Couldn't you also make the property part of the scopes parent?您不能也将属性作为范围父级的一部分吗?

$scope.$parent.property = somevalue;

I'm not saying it's right but it works.我不是说它是对的,但它有效。

Ah, have a bit of this new stuff as another alternative.啊,有一些这种新东西作为另一种选择。 It's localstorage, and works where angular works.它是 localstorage,在 angular 起作用的地方工作。 You're welcome.别客气。 (But really, thank the guy) (但真的,谢谢那家伙)

https://github.com/gsklee/ngStorage https://github.com/gsklee/ngStorage

Define your defaults:定义默认值:

$scope.$storage = $localStorage.$default({
    prop1: 'First',
    prop2: 'Second'
});

Access the values:访问值:

$scope.prop1 = $localStorage.prop1;
$scope.prop2 = $localStorage.prop2;

Store the values存储值

$localStorage.prop1 = $scope.prop1;
$localStorage.prop2 = $scope.prop2;

Remember to inject ngStorage in your app and $localStorage in your controller.请记住在您的应用程序中注入 ngStorage,在您的控制器中注入 $localStorage。

There are two ways to do this有两种方法可以做到这一点

1) Use get/set service 1)使用get/set服务

2) $scope.$emit('key', {data: value}); //to set the value 2) $scope.$emit('key', {data: value}); //to set the value $scope.$emit('key', {data: value}); //to set the value

 $rootScope.$on('key', function (event, data) {}); // to get the value

Second Approach :第二种方法:

angular.module('myApp', [])
  .controller('Ctrl1', ['$scope',
    function($scope) {

    $scope.prop1 = "First";

    $scope.clickFunction = function() {
      $scope.$broadcast('update_Ctrl2_controller', $scope.prop1);
    };
   }
])
.controller('Ctrl2', ['$scope',
    function($scope) {
      $scope.prop2 = "Second";

        $scope.$on("update_Ctrl2_controller", function(event, prop) {
        $scope.prop = prop;

        $scope.both = prop + $scope.prop2; 
    });
  }
])

Html :网址:

<div ng-controller="Ctrl2">
  <p>{{both}}</p>
</div>

<button ng-click="clickFunction()">Click</button>

For more details see plunker :有关更多详细信息,请参阅 plunker :

http://plnkr.co/edit/cKVsPcfs1A1Wwlud2jtO?p=preview http://plnkr.co/edit/cKVsPcfs1A1Wwlud2jtO?p=preview

I looked thru the answers above, I recommend pejman's Dec 29 '16 at 13:31 suggestion but he/she has not left a full answer.我查看了上面的答案,我推荐 pejman 于 2016 年 12 月 29 日 13:31 提出的建议,但他/她没有留下完整的答案。 Here it is, I will put this as --> (you need a service and a listener $watch on one of the scopes from controllers for changes in the service area)在这里,我将把它作为 --> (你需要一个服务和一个监听器$watch在控制器的一个作用域上,以改变服务区)

var app = 
angular.module('myApp', ['ngRoute', 'ngSanitize']);

app.service('bridgeService', function () {
    var msg = ""; 
    return msg;
});
app.controller('CTRL_1'
, function ($scope, $http, bridgeService) 
{
    $http.get(_restApi, config)
    .success(
    function (serverdata, status, config) {
        $scope.scope1Box = bridgeService.msg = serverdata;
    });
});
app.controller('CTRL_2'
, function ($scope, $http, bridgeService) 
{
    $scope.$watch( function () {
        return (bridgeService.msg);
    }, function (newVal, oldVal) {
        $scope.scope2Box = newVal;
    }, true
    );
});

If you don't want to make service then you can do like this.如果您不想提供服务,那么您可以这样做。

var scope = angular.element("#another ctrl scope element id.").scope();
scope.plean_assign = some_value;

Besides $rootScope and services, there is a clean and easy alternative solution to extend angular to add the shared data:除了 $rootScope 和 services 之外,还有一个干净且简单的替代解决方案来扩展 angular 以添加共享数据:

in the controllers:在控制器中:

angular.sharedProperties = angular.sharedProperties 
    || angular.extend(the-properties-objects);

This properties belong to 'angular' object, separated from the scopes, and can be shared in scopes and services.这些属性属于“angular”对象,与作用域分离,可以在作用域和服务中共享。

1 benefit of it that you don't have to inject the object: they are accessible anywhere immediately after your defination!它的一个好处是您不必注入对象:定义后可以立即在任何地方访问它们!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM