Как правильно обмениваться данными между угловыми сервисами - PullRequest
1 голос
/ 17 апреля 2019

Я пытаюсь переписать большую и сложную форму, которая делает все в контроллере. Я начал с разделения связанных функций на свои собственные модули / сервисы. Я не понимаю, как я должен поддерживать данные формы, не перегружая контроллер и не требуя передачи чрезмерного количества аргументов в сервисную функцию.

Мой текущий подход заключается в установке переменных в службе, затем использовании этой службы в других службах и попытке доступа к сохраненным данным. Это не похоже на работу. Я думаю, это потому, что внедрение службы в другой создает новый экземпляр без всех сохраненных значений.

Вот плункер, который обобщает этот подход: 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…
);

Должен ли я создавать третий сервис, который устанавливает и получает все данные других сервисов?

Должен ли я просто сохранить все данные на контроллере?

Ответы [ 2 ]

2 голосов
/ 17 апреля 2019

почему я получаю undefined при доступе к переменной во внедренной службе?

Объявление let создает закрытую переменную.

Добавление получателядля переменной:

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

}]);

И используйте метод получения:

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

Обновление

Должны ли мои службы взаимодействовать таким образом или естьдругой, более приемлемый метод?

Я пытаюсь избежать чего-то вроде этого:

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

Установка переменной в одном сервисе перед вычислением чего-либо в другом сервисе создает нежелательные соединение , которое затрудняет понимание, отладку, обслуживание и тестирование кода.

Вместо этого вся информация, необходимая от контроллера, должна предоставляться службе ценообразования согласованным способом.

0 голосов
/ 17 апреля 2019

Вы не должны вводить $ scope, $ scope - это устаревший способ разработки AngularJ, и вам следует изучить синтаксис компонентов или 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);
}
...