4

I'm not thinking about angular's $http.get workings correctly, so maybe you can help me re-adjust. I'm working on a wizard in which each step is a separate html file and the sequence of steps is in a JSON file. What I want to do is read in the JSON file and then:

  1. Create a list of the steps as a guide.
  2. Display the content of the step via ng-include.
  3. Create buttons that point to the previous and next steps.

From what I read in Service vs. Provider vs. Factory, AngularJS: factory $http.get JSON file, and similar topics, I can create a service or factory to read in the JSON. Doing so creates a promise object which then gets passed down the line to be filled whenever the data arrives. This works find when inserting the data into the model, which is bound to the view. If I need the data to calculate things like the next step buttons, though, all I have is a promise object - I can't build the links to the previous and next steps and set their states yet. Is there way to make angular wait until the data arrives before continuing with code execution? Is that the right way to think about it?

Here is a plunker and some code snippets:

JSON:

[{
    "name"  : "Step 1",
    "id"    : "step-1",
    "src"   : "step-1.html",
    "state" : "active"
    },

    {
    "name"  : "Step 2",
    "id"    : "step-2",
    "src"   : "step-2.html",
    "state" : "unavailable"
    },

    {
    "name"  : "Step 3",
    "id"      : "step-3",
    "src"   : "step-3.html",
    "state" : "unavailable"
}]

Factory:

workflow.factory('getWorkflow', function($http, $q) {
   return {
     getFlow: function() {
       var deferred = $q.defer();
       $http.get('steps.json').success(function(data) {
          deferred.resolve(data);
       }).error(function(){
          deferred.reject();
       });
       return deferred.promise;
     }
   }
});

Controller Snippets:

var workflow = angular.module("workflow", ['getWorkflow']);

workflow.controller("showStep", function($scope) {
    $scope.workFlow = {};         // Create the workFlow object
    $scope.workFlow.steps = [];   // Create an empty array to hold the steps
    $scope.workFlow.steps = getWorkflow.getFlow(); 

... set the first step as the active step and point to the HTML file ...

    $scope.workFlow.buildNavButtons = function() {
    scope.workFlow.buttonArray = [];    // Create/reset the array of buttons to nothing

    // The button for the PREVIOUS step.
    if ($scope.workFlow.activeStepIndex > 0) {  // Only add button if not the first step
        var prevButton = {};
        prevButton["destination"] = $scope.workFlow.activeStepIndex - 1;
        prevButton["buttonText"] = "<< " + $scope.workFlow.steps[$scope.workFlow.activeStepIndex - 1].name;
        prevButton["buttonClass"] = "workflow-previous";

        $scope.workFlow.buttonArray.push(prevButton);
    }
...

HTML

<!-- PREVIOUS AND NEXT STEP BUTTONS -->
<div id="workflow_navigation">
    <ul>
        <li data-ng-repeat="button in workFlow.buttonArray">
            <button class = "{{ button.buttonClass }}" 
            ng-click="workFlow.updateStep(button.destination)">
                {{ button.buttonText }}
            </button>
        </li>
    </ul>
</div>
Community
  • 1
  • 1
Scott McD.
  • 43
  • 1
  • 4

1 Answers1

2

You've got it almost right, just a couple of issues. First you need to inject the factory to your controller not as a dependency of the module.

var workflow = angular.module("workflow", []);

workflow.controller("showStep", function($scope, getWorkflow) {

And second, you need to wait for the promise to be fulfilled before acting on it:

  getWorkflow.getFlow().then(
    function(data) {
      $scope.workFlow.steps = data
      console.log($scope.workFlow.steps);

      // "activeStep" controls which step appears on screen.  
      // This initialize it and loads default content.
      $scope.workFlow.activeStep = $scope.workFlow.steps[0];
      $scope.workFlow.activeStepIndex = 0;
      console.log($scope.workFlow.activeStep);
      $scope.workFlow.content = $scope.workFlow.activeStep.src; // The display of the step content itself - changing this changes the display.

    }); // Use the factory below

That should fix main issues with promise and allow you to continue. You can check and working plunkr here.

pedromarce
  • 5,651
  • 2
  • 27
  • 27
  • This worked - thanks! I didn't understand how the .then method worked, and now it makes sense. (Will +1 it when I can. :) – Scott McD. Feb 18 '14 at 18:25