Using logic between factories and controllers in Angular.js

67 Views Asked by At

Here is a description of what I am trying to do:

I currently have an angular.module on my web app that I am building that is a price calculator where users will be able to put in how many days/weeks they would like to stay at a Hotel and have the module calculate their estimated price with fees/days/weeks included for the dates they would like to stay.

I currently have my select menu of seasons pulling from my angular.factory via a controller(see below). The user can select from the different options that I have stored in the factory as object literals and depending on the 'label' they have selected in the menu, it will calculate their price based on 1 weeks stay at this hotel. Great.

Now I would like to add some functionality to my steppers that I have set up through the [Revolunet/angular-stepper][1] directive that I have chosen to use as my stepper for each day and week.

The issue that I am running into is I am unsure as to where to do my logic for the calculations. I would like the user to be able to select a season in the select menu, and then use the stepper to add any additional days/weeks using the stepper and to dynamically adjust the estimated total based on how many days/weeks the user has chosen.

I know that I cannot have controllers talk to one another and I cannot have $scope look for any global variables aside from the app.factory I have set up? Could i store all of the angular-stepper stuff in the factory and have my app.controller inherit it?

So, in summary, I would like to dynamically change my dollar amount for the price estimator when the user adds days and weeks to their requests using the stepper I have provided and I am stuck as to where to put my logic for this. I hope this makes sense!

Here is my code:

HTML:

<div id= "estimator-wrapper" ng-app="priceEstimator">
    <h3> Price Estimator</h3>
    <h4> (with fees):</h4>
    <div ng-controller="weekStepper">
      <div  ng-controller="seasonSelector">
        <h2>{{ seasonsList.value }}</h2>
        <p> Select a season:</p>
        <select ng-model="seasonsList" ng-options="season as season.label for season in seasons"></select>
      </div>
      <label>Number of weeks:</label>
        <div min="minRating" max="maxRating" ng-model="rating" rn-stepper></div>
    <div ng-controller="dayStepper">
      <label>Number of days:</label>
        <div min="minRating" max="maxRating" ng-model="rating" rn-stepper></div>
      </div>
  </div>

Here is my Angular.js Module:

const app = angular.module('priceEstimator', ['revolunet.stepper']);

app.factory('seasonFactory', () => {
  let factory = {};
  let seasons = [
    { label:'-', value: '$' + 0},
    { label:'Fall/Winter', value: '$' + Math.floor((2100 + 245) * 1.115) },
    { label: 'Spring', value: '$' + Math.floor((2900 + 245) * 1.115) },
    { label: 'Summer', value: '$' + Math.floor((3995 + 245) * 1.115) }
  ];
  factory.getSeasons = () => {
    return seasons;
  };
  return factory;
});

app.controller("weekStepper",($scope) => {
  $scope.rating = 0;
  $scope.minRating = 0;
  $scope.maxRating = 8;
});

app.controller("dayStepper",($scope) => {
  $scope.rating = 0;
  $scope.minRating = 0;
  $scope.maxRating = 6;
});

app.controller("seasonSelector",($scope, seasonFactory) => {
  $scope.Math = Math;
  $scope.seasons = seasonFactory.getSeasons();
  $scope.seasonsList = $scope.seasons[0];
});
1

There are 1 best solutions below

2
On

You definitely can have your controllers talk to each other and already have a parent-child relationship between the weekStepper and dayStepper because day is nested within week in your html.

You can use $parent from within day stepper to talk to the weekStepper controller or since they are nested, the child controller will automatically inherit the parent's properties.

However, since you already have the factory set up, simply inject the factory into each controller and access the properties from there. Factories are singletons, so even if you injecting it into each controller, all of those references will point to the same instance and have the same data.

Based on what I said above, because of how your controllers are nested in your html if you inject seasonFactory and into weekStepper and store it into a property (say season factory), then $scope.seasonFactory will be available in all of the controllers. You could store the data in the factory once its retrieved or move the code that stores the results of your factory methods to the outer most controller and make it available everywhere that way.

There are a lot of great questions and answers here with regard to parent & child controllers. This one is one of the more popular ones: AngularJS access parent scope from child controller

Also, if you're on angular 1.5 or later, this would be a great opportunity to start using components.