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

IT技术 javascript angularjs angularjs-controller
2021-01-26 12:47:33

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

我不能使用Ctrl1insideCtrl2因为它是未定义的。但是,如果我尝试像这样传递它......

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

也失败了。

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

6个回答

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

简单的服务示例:

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 中)
    • 绑定到返回原语(字符串)的函数
    • 绑定到对象的属性
    • 两种方式绑定到对象的属性
试图理解这个答案是如何以及为什么使用.service而不是.factory在 Angular 文档中描述的。当文档使用不同的方法时,为什么这个答案投票如此之高?
2021-03-14 12:47:33
在这种情况下 - 当 sharedProperties.getProperty() 更改值时,Ctrl2 的范围如何“知道”?
2021-03-19 12:47:33
这里有一个问题,因为服务应该是无状态的。在服务中存储属性是错误的(但很方便)。我开始使用 $cacheFactory 来读写数据。我使用与 Gloopy 几乎相同的服务,但不是在服务中存储状态,而是现在在缓存中。首先创建一个缓存服务: angular.module('CacheService', ['ng']) .factory('CacheService', function($cacheFactory) { return $cacheFactory('CacheService'); }); 包含在你的 app.js 中,将它注入到服务中,像这样使用它: return CacheService.get(key); 或 CacheService.put(key, value);
2021-03-19 12:47:33
如果你想检测控制器中的变化并做出反应,一个选项是将getProperty()函数添加到作用域并使用$scope.$watch ,本例所示希望这些例子有帮助!
2021-03-24 12:47:33
如果您希望您的 UI 在每次属性更改时更新,您可以将其更改both为一个函数,它将在 angular 摘要过程中被调用/重新评估。有关示例,请参阅此小提琴此外,如果您绑定到一个对象的属性,您可以直接在您的视图中使用它,并且它会随着数据的更改而更新,类似于此示例
2021-04-06 12:47:33

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

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


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

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

是的,我同意你的看法。总是试图让事情变得简单。
2021-03-15 12:47:33
var _dataObj = {};当您返回对它的直接引用时声明有什么意义..?那不是私人的在第一个例子中你可以做this.dataObj = {};,在第二个例子return { dataObj: {} };它是一个无用的变量声明恕我直言。
2021-03-31 12:47:33
@DmitriZaitsev 你说的是“简单的例子”,但除非你正确地展示了如何利用私有状态,否则你只会让人们感到困惑。只要您返回直接引用,您的示例中就没有私有状态。
2021-04-04 12:47:33
@TJ 重点是在其他组件之间共享这个变量。这是一个说明共享概念的基本示例。变量在块内是私有的,然后您使用揭示模式将其公开为公共变量。这样,持有变量和使用变量之间就存在职责分离。
2021-04-05 12:47:33
@TJ 我没有看到任何令人困惑的地方。私有变量可以由module公开。随意写一个更好的答案。
2021-04-06 12:47:33

--- 我知道这个答案不是针对这个问题的,但我希望阅读这个问题并想要处理诸如工厂之类的服务的人避免这样做的麻烦 ----

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

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

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

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

$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。这是与工厂相关的最佳实践,最重要的是,它将有助于避免意外和无法捕捉的错误。

我认为这是一个很好的答案,但它很难消化。
2021-04-05 12:47:33

不创建服务的解决方案,使用 $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>
此时您正在使用全局范围的变量,这偏离了 AngularJS 的想法,即在其各种结构中局部范围界定所有内容。添加一个全局变量文件可以达到同样的效果,并且可以更容易地找到变量最初定义的位置。无论哪种方式,都不建议。
2021-03-26 12:47:33
@Organiccat - 我理解您的担忧,这就是为什么我已经提到首选方式将是服务,毫无疑问。但是 ya angular 也提供了这种方式。您想如何管理您的全局变量取决于您。我有一个场景,这种方法最适合我。
2021-04-07 12:47:33

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

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

    var hashtable = {};

    return {
        setValue: function (key, value) {
            hashtable[key] = value;
        },
        getValue: function (key) {
            return hashtable[key];
        }
    }
});
在此处检查适配器模式dofactory.com/net/adapter-design-pattern
2021-03-22 12:47:33
即使它有效,这通常也是.factory. 根据docs.angularjs.org/api/auto/service/$provide#service,.service应该使用“如果您将服务定义为类型/类”
2021-03-26 12:47:33
如果我错了,请纠正我,服务旨在返回可以是对象或值的东西。工厂旨在创建对象。一张脸实际上是一个返回某些东西的功能的集合,是我认为服务的地方。包括从工厂调用功能。再次,我进入了这对我来说是什么的基本概念,而不是从 Angular 的角度来看实际上是什么。(抽象工厂dofactory.com/net/abstract-factory-design-pattern)和适配器方法是我将作为服务公开的内容
2021-04-01 12:47:33
我还创建了一个使用服务在不同控制器之间共享数据的示例。我希望你们喜欢。 jsfiddle.net/juazammo/du53553a/1
2021-04-04 12:47:33
Dmitri,你是对的,但是从我的角度来看,Angular 的人只是改变了我在服务(外观)和工厂之间的概念......哦......
2021-04-09 12:47:33