首页 文章

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

提问于
浏览
318

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

我无法在 Ctrl2 中使用 Ctrl1 ,因为它未定义 . 但是,如果我尝试传递它...

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

也失败了 .

NOTE: 这些控制器没有彼此嵌套 .

15 回答

  • 495

    在多个控制器之间共享变量的一种方法是create a service并将其注入您想要使用它的任何控制器中 .

    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 blog(特别是第2课及其后)中描述得非常好 .

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

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


    UPDATE: To(希望)让事情更加清晰here is a fiddle,展示了一个例子:

    • Binding to static copies of the shared value (in myController1)

    • 绑定到基元(字符串)

    • 绑定到对象的属性(保存到范围变量)

    • Binding to shared values that update the UI as the values are updated (in myController2)

    • 绑定到返回基元的函数(字符串)

    • 绑定到对象的属性

    • 双向绑定到对象的属性

  • -1

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

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

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

    here the jsbin


    如果这太简单了,here is a more sophisticated example

    see the answer here for related best practices comments

  • 7

    --- 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 ----

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

    这些服务是 BEST PRACTICE ,用于在非嵌套控制器之间共享数据 .

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

    我从“ng-book:关于AngularJS的完整书籍”中读到,作为裸数据在控制器中创建的AngularJS ng模型是错误的!

    应该像这样创建$ 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文档)包含调用的最佳实践(BEST PRACTICE)

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

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

    But in your case you don't want nested scopes, but there is a similar aspect to get objects from services to the controllers.

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

    如果你想从控制器中获取objectC到你的范围,那么说错了:

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

    That wont work... 而是只使用一个点 .

    $scope.neededObjectInController = Factory.ObjectA;
    

    然后,在DOM中,您可以从objectA调用objectC . 这是与工厂相关的最佳实践,最重要的是 it will help to avoid unexpected and non-catchable errors.

  • 3

    Solution without creating Service, using $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>
    
  • 0

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

    app.service('sharedProperties', function () {
    
        var hashtable = {};
    
        return {
            setValue: function (key, value) {
                hashtable[key] = value;
            },
            getValue: function (key) {
                return hashtable[key];
            }
        }
    });
    
  • 42

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

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

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

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

    首先, create 你的 service ,这将是你的 shared data

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

    然后,只需将其注入 controllers 并获取范围内的共享数据:

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

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

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

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

  • 3

    以下示例显示如何在 siblings 控制器之间传递变量 and 在值更改时执行操作 .

    用例示例:边栏中有一个用于更改的过滤器另一种观点的内容 .

    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>
    
  • 25

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

    $scope.$parent.property = somevalue;
    

    我不是说它是对的但它有效 .

  • 16

    啊,有一些这样的新东西作为另一种选择 . 它是本地存储,适用于有角度的工作 . 别客气 . (但是真的,谢谢那家伙)

    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;
    

    记得在你的app中注入ngStorage,在你的控制器中注入$ localStorage .

  • 1

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

  • 5

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

    1)使用get / set服务

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

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

    第二种方法:

    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>
    

    有关详细信息,请参阅plunker:

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

  • 2

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

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

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

    在控制器中:

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

    此属性属于“angular”对象,与范围分离,可以在范围和服务中共享 .

    它的一个好处是你不必注入物体:它们可以在你的定义后立即到达任何地方!

相关问题