如何在 angular 服务之间正确共享数据

How to properly share data between angular services

我正在尝试重写一个庞大而复杂的表单,该表单在控制器中执行所有操作。我首先将相关功能分成它们自己的 modules/services。 我不明白我应该如何维护表单数据而不会使控制器拥挤或需要将过多的参数传递给服务函数。

我目前的做法是在服务上设置变量,然后在其他服务中使用该服务并尝试访问保存的数据。这似乎不起作用。我认为这是因为将服务注入另一个服务会创建一个没有所有保存值的新实例。

这里有一个 plunker 总结了这种方法:https://plnkr.co/edit/vyKtlXk8Swwf7xmoCJ4q

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

app.service('productService', [function() {
  let products = [
    { name: 'foo', value: 'foo' },
    { name: 'bar', value: 'bar' },
    { name: 'baz', value: 'baz' }
  ];

  let selectedProduct = null;

  this.getAvailableProducts = function() {
    return products;
  }

  this.setSelectedProduct = function(product) {
    selectedProduct = product;
  }
}]);
app.service('storeService', ['productService', function(productService) {
  let states = [
    { name: 'SC', value: 'SC' },
    { name: 'GA', value: 'GA' },
    { name: 'LA', value: 'LA' }
  ];

  let selectedState = '';

  this.getAvailableStates = function() {
    return states;
  }

  this.setSelectedState = function(state) {
    selectedState = state;
  }

  this.getPrice = function() {
    // This console.log will always return undefined.
    // productService.selectedProduct is not available.
    console.log(productService.selectedProduct);
    if (productService.selectedProduct == "foo" && selectedState == 'SC') {
      return 10;
    }
    return 5;
  }
}]);
app.controller('myController', function($scope, storeService, productService) {
  $scope.name = '';
  $scope.deliveryState = '';
  $scope.selectedProduct = null;
  $scope.price = 0;

  $scope.productSelection = productService.getAvailableProducts();
  $scope.states = storeService.getAvailableStates();

  $scope.productChanged = function() {
    productService.setSelectedProduct($scope.selectedProduct);
    $scope.price = storeService.getPrice();
  }

  $scope.stateChanged = function() {
    storeService.setSelectedState($scope.deliveryState);
    $scope.price = storeService.getPrice();
  }
});

我正在努力避免这样的事情:

$scope.price = storeService.getPrice(
     $scope.state,
     $scope.selectedProduct,
     $scope.servicePackage,
     $scope.serviceFee,
     $scope.shippingSelection,
     // etc…
);

我是否应该创建第三个服务来设置和获取其他服务的所有数据?

我应该只维护控制器上的所有数据吗?

你不应该注入 $scope,$scope 是一种过时的开发方式AngularJs,你应该研究组件或 controllerAs 语法。

控制器应该只在服务和视图之间编组数据。

服务应提供数据功能,如获取产品或创建新产品,控制器应执行类似

的操作
$ctrl = this;
$ctrl.product = productService.new();

$ctrl.product = productService.get(productId);

然后在您看来您绑定到产品的属性

<input name="name" ng-model="$ctrl.product.name">

当您保存产品时,您会将整个产品传回给服务

<form name="productForm" ng-submit="productForm.$valid && $ctrl.save()">

并在控制器中

$ctrl.save = function() {
  productService.save($ctrl.product);
}

why do I get undefined when accessing a variable on the injected service?

let 声明创建了一个私有变量。

为变量添加一个getter:

app.service('productService', [function() {
  let products = [
    { name: 'foo', value: 'foo' },
    { name: 'bar', value: 'bar' },
    { name: 'baz', value: 'baz' }
  ];

  let selectedProduct = null;

  this.getAvailableProducts = function() {
    return products;
  }

  this.setSelectedProduct = function(product) {
    selectedProduct = product;
  }

  //ADD getter

  this.getSelectedProduct = function() {
      return selectedProduct;
  }

}]);

并使用 getter:

  this.getPrice = function() {
    // This console.log will always return undefined.
    // productService.selectedProduct is not available.
    console.log(productService.selectedProduct);
     ̶i̶f̶ ̶(̶p̶r̶o̶d̶u̶c̶t̶S̶e̶r̶v̶i̶c̶e̶.̶s̶e̶l̶e̶c̶t̶e̶d̶P̶r̶o̶d̶u̶c̶t̶ ̶=̶=̶ ̶"̶f̶o̶o̶"̶ ̶&̶&̶ ̶s̶e̶l̶e̶c̶t̶e̶d̶S̶t̶a̶t̶e̶ ̶=̶=̶ ̶'̶S̶C̶'̶)̶ ̶{̶
     if (productService.getSelectedProduct() == "foo" && selectedState == 'SC') {
      return 10;
    }
    return 5;
 }

更新

Should my services be communicating like that or is there a different, more accepted method?

I am trying to avoid something like this:

$scope.price = storeService.getPrice(
     $scope.state,
     $scope.selectedProduct,
     $scope.servicePackage,
     $scope.serviceFee,
     $scope.shippingSelection,
     // etc…
);

避免这种情况的一种方法是使用对象作为参数来提供多个选项:

$scope.options = {};

$scope.price = storeService.getPrice(
     $scope.selectedProduct,
     $scope.options
);

表单可以直接填充options对象:

<select ng-model="options.state">
    <option ng-repeat="state in states">{{ state.name }}</option>
</select><br>

<select ng-model="options.serviceFee">
    <option ng-repeat="fee in feeList">{{ fee.name }}</option>
</select><br>

<!-- //etc... -->

在一项服务中设置变量,然后再在另一项服务中计算某些内容会产生不良结果 coupling,这会使代码难以理解、调试、维护和测试。

相反,控制器所需的所有信息都应以 coherent 方式提供给定价服务。