在 Angular JS 中的控制器之间传递数据?

IT技术 javascript angularjs angular-services
2021-02-03 07:26:46

我有一个显示我的产品的基本控制器,

App.controller('ProductCtrl',function($scope,$productFactory){
     $productFactory.get().success(function(data){
           $scope.products = data;
     });
});

在我看来,我正在列表中显示此产品

<ul>
    <li ng-repeat="product as products">
        {{product.name}}
    </li>
</ul

我想要做的是当有人点击产品名称时,我有另一个名为购物车的视图,其中添加了该产品。

 <ul class="cart">
      <li>
          //click one added here
      </li>
      <li>
          //click two added here
      </li>
 </ul>

所以我的疑问是,如何将点击的产品从第一个控制器传递给第二个控制器?我认为推车也应该是控制器。

我使用指令处理点击事件。另外我觉得我应该使用服务来实现上述功能只是不知道如何?因为购物车将预定义添加的产品数量可能是 5/10,具体取决于用户所在的页面。所以我想保持这个通用。

更新:

我创建了一个广播服务,并在第二个控制器中接收它。现在查询是如何更新dom?因为我要删除的产品列表是非常硬编码的。

6个回答

从描述来看,您似乎应该使用一项服务。查看http://egghead.io/lessons/angularjs-sharing-data-between-controllersAngularJS 服务在控制器之间传递数据以查看一些示例。

您可以这样定义您的产品服务(作为工厂):

app.factory('productService', function() {
  var productList = [];

  var addProduct = function(newObj) {
      productList.push(newObj);
  };

  var getProducts = function(){
      return productList;
  };

  return {
    addProduct: addProduct,
    getProducts: getProducts
  };

});

依赖将服务注入到两个控制器中。

在您的 中ProductController,定义一些将所选对象添加到数组的操作:

app.controller('ProductController', function($scope, productService) {
    $scope.callToAddToProductList = function(currObj){
        productService.addProduct(currObj);
    };
});

在您的 中CartController,从服务中获取产品:

app.controller('CartController', function($scope, productService) {
    $scope.products = productService.getProducts();
});
调用 getProducts() 时,购物车控制器会更新一次吗?还是每次添加新产品时?
2021-03-15 07:26:46
如果您希望它自动更新,您可以添加来自 Maxim Shoustin 的回答的广播并在 $on 函数中调用 getProducts() 以更新 CartCtrl 的范围。
2021-03-15 07:26:46
@DeveshM 是的,按照你的建议去做。您可能需要考虑扩展这些方法,以便它们不仅将数据保存在内存中,而且更加持久($http例如,通过调用保存到服务器)。
2021-03-27 07:26:46
例如,如果我有 2 个 productControllers 和 2 个购物车,会发生什么?两者都会添加元素吗?在这种情况下,你如何解决这个问题?
2021-03-31 07:26:46
@krillgar 你是完全正确的,最初被忽视了。我已经编辑了答案以反映有效的解决方案。
2021-04-05 07:26:46

如何将这个点击的产品从第一个控制器传递到第二个?

单击时,您可以调用调用广播的方法

$rootScope.$broadcast('SOME_TAG', 'your value');

第二个控制器将监听这个标签,如:

$scope.$on('SOME_TAG', function(response) {
      // ....
})

由于我们不能将 $scope 注入到服务中,所以没有什么比单例 $scope 更合适的了。

但是我们可以注入$rootScope. 因此,如果您将值存储到 Service 中,则可以$rootScope.$broadcast('SOME_TAG', 'your value');在 Service 主体中运行(请参阅@Charx 关于服务的描述)

app.service('productService',  function($rootScope) {/*....*/}

请查看关于 $broadcast$emit 的好文章

是的,这就像我使用工厂的魅力?只有最后一件事让我陷入困境,每次单击产品时,我都会在新控制器中获取数据。现在我如何在 DOM 中更新它?因为我已经有了 5 个带边框的硬编码列表,所以每个产品都需要放入其中
2021-03-10 07:26:46
$watch如果值存在于$rootScope级别上,我们可以使用否则只有广播可能会通知其他控制器。仅供参考,如果其他程序员在您的代码中看到broadcast- 逻辑很清楚您尝试做什么 - “广播事件”。无论如何,从我的经验。使用rootscopefor不是一个好习惯 watch关于“仅第一次触发”:看看这个例子:plnkr.co/edit/5zqkj7iYloeHYkzK1Prt?p=preview你有新旧值。确保每次获得不等于旧值的新值
2021-03-11 07:26:46
@MS 感谢您的回复。有没有办法使用 $watch 来做到这一点?顺便说一句,我的是并行控制器,我使用你的方法让它工作。对我来说,每当我尝试添加 $watch(甚至到 $rootScope)时,与第二个控制器中的 $watch 关联的方法只会在第一次触发(第二个控制器的初始化)。谢谢。
2021-03-21 07:26:46
@daylight 回答你的问题。取决于您拥有的控制器结构:并行或子父。$rootScope.$broadcast通知所有具有并行结构又名相同级别的控制器。
2021-03-31 07:26:46
@KT - 你有没有得到答案?这似乎是一个显而易见的问题,但我在任何地方都找不到答案。我想要一个控制器来改变一些值。当该应用程序值更改时,任何其他监听控制器都应根据需要自行更新。找不到。
2021-04-03 07:26:46

不创建服务的解决方案,使用 $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>
@Shaz 你能详细说明为什么吗?
2021-03-14 07:26:46
@Mirko 您应该尽量避免全局状态,因为任何人都可以更改它-使您的程序状态不可预测。
2021-03-14 07:26:46
$rootScope 应该尽量避免。
2021-03-17 07:26:46
$rootScope 具有全局作用域,因此像本地全局变量一样,我们必须谨慎使用它们。如果任何控制器更改其值,它将在全局范围内更改。
2021-03-18 07:26:46
服务和工厂都是 Singleton ,但你可以选择在你的控制器中注入或不注入任何服务。但是所有子作用域都源自 rootscope 并遵循原型链。因此,如果您尝试访问作用域上的属性但该属性不存在,那么它将查找链。您可能会无意中更改 rootscope 属性。
2021-03-23 07:26:46

您可以通过两种方法来做到这一点。

  1. 通过使用$rootscope,但我不建议这样做。$rootScope是最顶层的范围。一个应用程序只能有一个$rootScope将在应用程序的所有组件之间共享。因此它就像一个全局变量。

  2. 使用服务。您可以通过在两个控制器之间共享服务来实现此目的。服务代码可能如下所示:

    app.service('shareDataService', function() {
        var myList = [];
    
        var addList = function(newObj) {
            myList.push(newObj);
        }
    
        var getList = function(){
            return myList;
        }
    
        return {
            addList: addList,
            getList: getList
        };
    });
    

    你可以在这里看到我的小提琴

和第三个选项,您可以发送事件,只需添加到列表中
2021-03-11 07:26:46
@shreedharbhat 问题不是询问跨页面重新加载保留数据。
2021-03-23 07:26:46
如果用户刷新页面怎么办?然后 getProducts() 不会给你任何东西!(你不能告诉所有用户不要刷新,你能吗?)
2021-03-24 07:26:46

在控制器之间共享数据的一种更简单的方法是使用嵌套数据结构。而不是,例如

$scope.customer = {};

我们可以用

$scope.data = { customer: {} };

data属性将从父作用域继承,因此我们可以覆盖其字段,保持来自其他控制器的访问。

他在谈论我认为的嵌套控制器。对我也没什么用。
2021-03-12 07:26:46
控制器从父控制器继承范围属性到它自己的范围。干净的!简单使它美丽
2021-03-23 07:26:46
不能让它工作。在第二个控制器上我使用 $scope.data 并且它是未定义的。
2021-03-29 07:26:46