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

dop*_*man 325 javascript angularjs angularjs-controller

我有两个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
}
Run Code Online (Sandbox Code Playgroud)

我不能Ctrl1在里面使用,Ctrl2因为它是未定义的.但是,如果我尝试传递它...

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

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

Ctrl2.prototype = new Ctrl1();
Run Code Online (Sandbox Code Playgroud)

也失败了.

注意:这些控制器不是彼此嵌套的.

Glo*_*opy 500

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

简单的服务示例:

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

        return {
            getProperty: function () {
                return property;
            },
            setProperty: function(value) {
                property = value;
            }
        };
    });
Run Code Online (Sandbox Code Playgroud)

在控制器中使用该服务:

function Ctrl2($scope, sharedProperties) {
    $scope.prop2 = "Second";
    $scope.both = sharedProperties.getProperty() + $scope.prop2;
}
Run Code Online (Sandbox Code Playgroud)

这篇博客非常精彩地描述了这一点(第2课及其后).

我发现,如果你要绑定到这些属性在多个控制器,如果你绑定到一个对象的属性,而不是基本类型(布尔,字符串,数字)保留界限参考效果更好.

示例:var property = { Property1: 'First' };代替var property = 'First';.


更新:为了(希望)让事情变得更加清晰,这是一个小提琴,展示了一个例子:

  • 绑定到共享值的静态副本(在myController1中)
    • 绑定到基元(字符串)
    • 绑定到对象的属性(保存到范围变量)
  • 绑定到更新值时更新UI的共享值(在myController2中)
    • 绑定到返回基元的函数(字符串)
    • 绑定到对象的属性
    • 双向绑定到对象的属性

  • 如果要检测并响应控制器中的更改,可以选择将`getProperty()`函数添加到作用域并使用[$ scope.$ watch](http://docs.angularjs.org/api/ng .$ rootScope.Scope#$ watch)喜欢在[这个例子](http://jsfiddle.net/tg78g/1/).希望这些例子有帮助! (11认同)
  • 在这种情况下 - 当sharedProperties.getProperty()改变值时,Ctrl2的范围如何"知道"? (5认同)
  • 如果您希望每次更改属性时更新UI,您可以将"both"更改为函数,并在角度摘要过程中调用/重新评估.有关示例,请参见[this fiddle](http://jsfiddle.net/x8vfR/).此外,如果您绑定到对象的属性,您可以直接在视图中使用它,它将在数据更改时更新,类似于[此示例](http://jsfiddle.net/tg78g/2/). (5认同)
  • 试图了解如何以及为什么这个答案使用`.service`而不是`.factory`,如Angular文档中所述.当文档使用不同的方法时,为什么这个答案投票如此之高? (4认同)

Dmi*_*sev 44

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

这是一个非常简单的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;
});
Run Code Online (Sandbox Code Playgroud)

这里的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;
});
Run Code Online (Sandbox Code Playgroud)

这里的jsbin


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

请参阅此处的相关最佳实践注释的答案


AFP*_*555 26

---我知道这个答案不是针对这个问题的,但是我希望有人能够阅读这个问题,并希望处理工厂等服务,以避免麻烦这样做----

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

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

关于数据共享这一主题的一个非常好的注释是如何声明对象.我不走运,因为在我读到它之前我陷入了一个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'
  });
Run Code Online (Sandbox Code Playgroud)

而不是这样的:

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

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

<div ng-model="someModel.someValue"></div>  //NOTICE THE DOT.
Run Code Online (Sandbox Code Playgroud)

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

但在您的情况下,您不希望嵌套作用域,但是有一个类似的方面可以将对象从服务转移到控制器.

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

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

$scope.neededObjectInController = Factory.objectA.objectB.objectC;
Run Code Online (Sandbox Code Playgroud)

那不会工作...... 而只使用一个点.

$scope.neededObjectInController = Factory.ObjectA;
Run Code Online (Sandbox Code Playgroud)

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

  • 我认为这是一个很好的答案,但很难消化. (2认同)

San*_*eev 17

使用$ rootScope创建Service的解决方案:

要在应用控制器之间共享属性,您可以使用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;
}]);
Run Code Online (Sandbox Code Playgroud)

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

<div ng-controller="Ctrl1">
    <div class="banner" ng-show="$root.showBanner"> </div>
</div>
Run Code Online (Sandbox Code Playgroud)

  • 你在那个时候使用了全局范围的变量,这与AngularJS在各种结构中局部确定所有内容的想法不同.添加全局变量文件可以实现相同的目的,并且更容易找到最初定义变量的位置.无论哪种方式,都没有建议. (5认同)
  • @Organiccat - 我理解你的担忧,这就是为什么我已经提到过,首选的方式是服务,毫无疑问.但是,ya angular也提供了这种方式.这是你想要管理全球的方式.我有一个场景,这种方法最适合我. (4认同)

Jua*_*ora 8

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

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

    var hashtable = {};

    return {
        setValue: function (key, value) {
            hashtable[key] = value;
        },
        getValue: function (key) {
            return hashtable[key];
        }
    }
});
Run Code Online (Sandbox Code Playgroud)


小智 6

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

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

myApp.value('sharedProperties', {}); //set to empty object - 
Run Code Online (Sandbox Code Playgroud)

然后根据服务注入值.

在ctrl1中设置:

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

并从ctrl2访问:

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

});
Run Code Online (Sandbox Code Playgroud)


Zan*_*non 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();
    });
  });
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)