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

AngularJS: How can I pass variables between controllers?

我有两个角度控制器:

1
2
3
4
5
6
7
8
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
}

我不能在Ctrl2内使用Ctrl1,因为它是未定义的。但是,如果我试着这样传递它…

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

我得到一个错误。有人知道怎么做吗?

1
Ctrl2.prototype = new Ctrl1();

也失败了。

注意:这些控制器不嵌套在彼此内部。


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

简单服务示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
angular.module('myApp', [])
    .service('sharedProperties', function () {
        var property = 'First';

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

在控制器中使用服务:

1
2
3
4
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示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

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

有关相关最佳实践意见,请参见此处的答案。


---我知道这个答案不适合这个问题,但我希望那些阅读这个问题并想处理诸如工厂等服务的人避免这样做的麻烦----

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

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

关于数据共享这个主题的一个非常好的注释是如何声明对象。我很不走运,因为我在读到之前掉进了安古拉吉斯的陷阱,我很沮丧。所以让我帮你避免这个麻烦。

我从"ng book:the complete book on angularjs"中读到,在控制器中创建的AngularJS ng模型作为裸数据是错误的!

应该这样创建$scope元素:

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

而不是这样:

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

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

1
  //NOTICE THE DOT.

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

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

假设您有自己的服务"工厂",并且在返回空间中有一个包含objectc的objecta。

如果您想从控制器将对象C放入您的作用域中,则错误地说:

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

那不管用…相反,只使用一个点。

1
$scope.neededObjectInController = Factory.ObjectA;

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


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

要跨应用程序控制器共享属性,可以使用Angular$rootScope。这是共享数据的另一种选择,可以让人们了解数据。

在控制器之间共享某些功能的首选方法是服务,读取或更改可以使用$rootscope的全局属性。

1
2
3
4
5
6
7
8
9
10
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访问属性):

1
 


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

1
2
3
4
5
6
7
8
9
10
11
12
13
app.service('sharedProperties', function () {

    var hashtable = {};

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


我倾向于使用价值观,乐于让任何人讨论这是个坏主意的原因。

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

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

然后根据服务注入值。

在CTRL1中设置:

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

从ctrl2访问:

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

});


下面的示例演示如何在同级控制器之间传递变量,并在值更改时执行操作。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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();
    });
  });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js">


 
  Controller 1 Scope
 
    <input type="text" ng-model="value"/>
    <button ng-click="update()">Update</button>
 
 
 
 
  Controller 2 Scope
 
    Value: {{ value }}


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

这是一个工作平台:http://plnkr.co/edit/q1vdkjp2tpvql1lf6m?P=信息

首先,创建具有共享数据的服务:

1
2
3
4
5
6
7
8
app.factory('SharedService', function() {
  return {
    sharedObject: {
      value: '',
      value2: ''
    }
  };
});

然后,只需将其注入控制器,并获取作用域上的共享数据:

1
2
3
4
5
6
7
8
9
10
11
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;
});

您也可以为您的指令这样做,它的工作方式相同:

1
2
3
4
5
6
7
8
9
app.directive('myDirective',['SharedService', function(SharedService){
  return{
    restrict: 'E',
    link: function(scope){
      scope.model = SharedService.sharedObject;
    },
    template: '<input type="text" ng-model="model.value"/>'
  }
}]);

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


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

网址:https://github.com/gsklee/ngstorage

定义默认值:

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

访问值:

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

存储值

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

记住在应用程序中注入ngstorage,在控制器中注入$localstorage。


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


您不能将属性也作为作用域父级的一部分吗?

1
$scope.$parent.property = somevalue;

我不是说这是对的,但它起作用了。


第二种方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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:

1
2
3
4
5
6
  <p>
{{both}}
</p>


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

有关更多详细信息,请参阅Plunker:

http://plnkr.co/edit/ckvspcfss1a1wlud2jto?P=预览


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

1)使用get/set服务

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

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

如果你不想做服务,你可以这样做。

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


除了$rootscope和services之外,还有一个干净、简单的替代解决方案来扩展angle以添加共享数据:

在控制器中:

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

此属性属于"角度"对象,与作用域分离,可以在作用域和服务中共享。

1好处是,你不必注射物体:在你污秽之后,它们就可以在任何地方被接触到!