331

我有两个 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
}

我不能Ctrl1在里面使用,Ctrl2因为它是未定义的。但是,如果我尝试像这样传递它......</p>

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

我得到一个错误。有谁知道如何做到这一点?

正在做

Ctrl2.prototype = new Ctrl1();

也失败了。

注意:这些控制器没有相互嵌套。

4

16 回答 16

508

在多个控制器之间共享变量的一种方法是创建一个服务并将其注入您想要使用它的任何控制器中。

简单的服务示例:

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

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

在控制器中使用服务:

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

这个博客(尤其是第 2 课)对此进行了很好的描述。

我发现如果你想跨多个控制器绑定到这些属性,如果你绑定到对象的属性而不是原始类型(布尔值、字符串、数字)来保留绑定的引用,效果会更好。

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


更新:为了(希望)让事情更清楚这里是一个小提琴,它显示了一个例子:

  • 绑定到共享值的静态副本(在 myController1 中)
    • 绑定到原语(字符串)
    • 绑定到对象的属性(保存到范围变量)
  • 绑定到在更新值时更新 UI 的共享值(在 myController2 中)
    • 绑定到返回原语(字符串)的函数
    • 绑定到对象的属性
    • 两种方式绑定到对象的属性
于 2012-08-17T16:17:16.747 回答
45

我喜欢用简单的例子来说明简单的事情:)

这是一个非常简单的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;
});

这里是 jsbin

这是一个非常简单的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;
});

这里是 jsbin


如果这太简单了,这里有一个更复杂的例子

请参阅此处的答案以获取相关的最佳实践评论

于 2014-08-09T17:34:17.507 回答
26

---我知道这个答案不适用于这个问题,但我希望阅读这个问题并想要处理工厂等服务的人避免这样做----

为此,您将需要使用服务或工厂。

这些服务是在非嵌套控制器之间共享数据的最佳实践。

关于数据共享这个主题的一个非常好的注释是如何声明对象。我很不幸,因为我在阅读之前就陷入了 AngularJS 的陷阱,我非常沮丧。所以让我帮你避免这个麻烦。

我从“ng-book: The complete book on AngularJS”中读到,在控制器中作为裸数据创建的 AngularJS ng-model 是错误的!

应该像这样创建一个 $scope 元素:

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

而不是这样:

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

这是因为建议(最佳实践)DOM(html 文档)将调用包含为

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

如果您希望您的子控制器能够从父控制器更改对象,这对嵌套控制器非常有帮助......

但是在您的情况下,您不需要嵌套范围,但是有一个类似的方面可以将对象从服务获取到控制器。

假设您有您的服务“工厂”,并且在返回空间中有一个包含 objectB 的 objectA,其中包含 objectC。

如果您想从您的控制器中将 objectC 获取到您的范围内,那么这样说是错误的:

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

那行不通…… 而是只使用一个点。

$scope.neededObjectInController = Factory.ObjectA;

然后,在 DOM 中,您可以从 objectA 调用 objectC。这是与工厂相关的最佳实践,最重要的是,它将有助于避免意外和不可捕获的错误。

于 2014-06-24T07:21:45.093 回答
17

使用 $rootScope 不创建服务的解决方案:

要跨应用控制器共享属性,您可以使用 Angular $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;
}]);

在模板中使用 $rootScope(使用 $root 访问属性):

<div ng-controller="Ctrl1">
    <div class="banner" ng-show="$root.showBanner"> </div>
</div>
于 2014-08-27T18:58:31.953 回答
9

上面的示例就像一个魅力。我只是做了一个修改,以防我需要管理多个值。我希望这有帮助!

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

    var hashtable = {};

    return {
        setValue: function (key, value) {
            hashtable[key] = value;
        },
        getValue: function (key) {
            return hashtable[key];
        }
    }
});
于 2014-07-15T16:35:38.507 回答
6

我倾向于使用价值观,很高兴任何人都可以讨论为什么这是一个坏主意..

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

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

然后根据服务注入值。

在 ctrl1 中设置:

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

并从 ctrl2 访问:

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

});
于 2016-02-16T16:37:19.267 回答
5

下面的例子展示了如何在兄弟控制器之间传递变量在值改变时采取行动。

用例示例:您在侧边栏中有一个过滤器,可以更改另一个视图的内容。

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>

于 2016-03-24T02:10:08.110 回答
4

我想通过指出在控制器甚至指令之间共享数据的推荐方法是使用已经指出的服务(工厂)来为这个问题做出贡献,但我也想提供一个应该如何做的工作实际例子。

这是工作的 plunker: http ://plnkr.co/edit/Q1VdKJP2tpvqqJL1LF6m?p=info

首先,创建您的服务,它将拥有您的共享数据

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

然后,只需将其注入您的控制器并在您的范围内获取共享数据:

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;
});

您也可以为您的指令执行此操作,它的工作方式相同:

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>'
  }
}]);

希望这个实用而干净的答案对某人有所帮助。

于 2015-02-21T23:21:33.877 回答
3

你可以通过服务或工厂来做到这一点。除了一些核心差异之外,它们基本上是相同的。我发现thinkster.io上的这个解释是最容易理解的。简单、中肯、有效。

于 2014-07-14T07:26:12.637 回答
2

难道你不能也让属性成为范围父级的一部分吗?

$scope.$parent.property = somevalue;

我并不是说它是正确的,但它确实有效。

于 2014-05-15T00:19:35.510 回答
2

啊,有一点这种新东西作为另一种选择。它是本地存储,可以在 Angular 工作的地方工作。别客气。(但真的,谢谢那家伙)

https://github.com/gsklee/ngStorage

定义您的默认值:

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

访问值:

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

存储值

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

请记住在您的应用程序中注入 ngStorage 并在控制器中注入 $localStorage。

于 2014-09-10T11:03:03.760 回答
2

有两种方法可以做到这一点

1) 使用获取/设置服务

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

 $rootScope.$on('key', function (event, data) {}); // to get the value
于 2015-11-24T14:23:39.570 回答
2

第二种方法:

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; 
    });
  }
])

网页:

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

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

有关更多详细信息,请参见 plunker:

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

于 2016-03-08T14:18:45.823 回答
2

我查看了上面的答案,我推荐 pejman 的 2016 年 12 月 29 日 13:31 的建议,但他/她没有留下完整的答案。在这里,我将其设置为 --> (您需要一个服务和一个监听器$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
    );
});
于 2020-09-04T23:15:43.287 回答
0

如果您不想提供服务,那么您可以这样做。

var scope = angular.element("#another ctrl scope element id.").scope();
scope.plean_assign = some_value;
于 2013-03-01T11:12:35.683 回答
-1

除了 $rootScope 和服务之外,还有一个干净且简单的替代解决方案来扩展 Angular 以添加共享数据:

在控制器中:

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

此属性属于 'angular' 对象,与范围分离,并且可以在范围和服务中共享。

它的一个好处是您不必注入对象:在您定义后立即可以在任何地方访问它们!

于 2015-07-13T17:00:56.613 回答