<!DOCTYPE html>
<html>

  <head>
    <script data-require="jquery@3.0.0" data-semver="3.0.0" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.js"></script>

    <script data-require="angular.js@1.5.6" data-semver="1.5.6" src="https://code.angularjs.org/1.5.6/angular.min.js"></script>
    <script data-require="sanitize@1.4.8" data-semver="1.4.8" src="https://code.angularjs.org/1.4.8/angular-sanitize.js"></script>

    <script data-require="ui-bootstrap@1.3.3" data-semver="1.3.3" src="https://cdn.rawgit.com/angular-ui/bootstrap/gh-pages/ui-bootstrap-tpls-1.3.3.js"></script>
    <link data-require="bootstrap@3.3.2" data-semver="3.3.2" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />

    <script data-require="ui-select@0.18.1" data-semver="0.18.1" src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.18.1/select.js"></script>
    <link data-require="ui-select@0.18.1" data-semver="0.18.1" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.18.1/select.css" />

    <script src="decision-tree.js"></script>
    <script src="script.js"></script>

    <link rel="stylesheet" href="style.css" />
  </head>

  <body ng-app="MainModule" ng-controller="MainController as ctrl">

    <ui-select ng-model="ctrl.selectedDecisionTreeMode" theme="bootstrap" style="width: 250px;">
      <ui-select-match allow-clear="false" placeholder=""><span ng-bind="$select.selected.label"></span></ui-select-match>
      <ui-select-choices repeat="mode in (ctrl.decisionTreeModes | filter: { label: $select.search }) track by $index">
        <div ng-bind-html="mode.label | highlight: $select.search"></div>
      </ui-select-choices>
    </ui-select>
    
    <button class="btn btn-primary" ng-click="ctrl.openDecisionTreeWizard()">Launch Wizard</button>
    
    <decision-tree-result result="ctrl.result"></decision-tree-result>

  </body>

</html>
var mainModule = angular.module('MainModule', ['ui.select', 'ngSanitize', 'decision.tree']);

mainModule.controller('MainController', ['$decisionTree', function($decisionTree) {
  
  var vm = this;
  
  var RiskFactor = Object.freeze({ "HIGH": "HIGH", "MODERATE": "MODERATE", "LOW": "LOW"});
    
  var riskAssessmentTree =
    {
      question: "Income:",
      children: [
        { value: "£0 to £12K", result: { risk: RiskFactor.HIGH, description: "Low income" } },
        {
          value: "£12K to £30K",
          question: "Credit History:",
          children: [
            {
              value: "Unknown",
              question: "Debt:",
              children: [
                { value: "High", result: { risk: RiskFactor.HIGH, description: "Mid income, unknown credit history & high debt" } },
                { value: "Low", result: { risk: RiskFactor.MODERATE, description: "Mid income, unknown credit history & low debt" } }
              ]
            },
            { value: "Bad", result: { risk: RiskFactor.HIGH, description: "Mid income, bad credit history" } },
            { value: "Good", result: { risk: RiskFactor.MODERATE, description: "Mid income, good credit history" } }
          ]
        },
        {
          value: "Over £30K",
          question: "Credit History:",
          children: [
            { value: "Unknown", result: { risk: RiskFactor.LOW, description: "High income, unknown credit history" } },
            { value: "Bad", result: { risk: RiskFactor.MODERATE, description: "High income, bad credit history" } },
            { value: "Good", result: { risk: RiskFactor.LOW, description: "High income, good credit history" } }
          ]
        }
      ]
    };

	function tweak(tree, tweaker) {
	  tweaker(tree);
	  angular.forEach(tree.children, function (value) {
	    tweak(value, tweaker);
	    
	  });
	  
	  return tree;
	}

	vm.decisionTreeModes = [
		{ label: "ALL Buttons", tree: riskAssessmentTree },
		{ label: "ALL Selects", tree: tweak(
			angular.copy(riskAssessmentTree),
			function (child) {
				if (child.children) {
					child.selector = "drop-down";
				}
			}
		) },
		{ label: "Mixed (DDs when > 4 options)", tree: tweak(
			angular.copy(riskAssessmentTree),
			function (child) {
				if (child.children && child.children.length > 4) {
					child.selector = "drop-down";
				}
			}
		) }
	];
	vm.selectedDecisionTreeMode = vm.decisionTreeModes[0];

  vm.openDecisionTreeWizard = function () {
    
    $decisionTree.openWizard(
      {
        title: 'Selecty Thingy Wizard',
        resultTemplateUrl: 'risk-assessment-result.html',
        decisionTree: vm.selectedDecisionTreeMode.tree
      }  
    ).then(
      function (result) {
        vm.result = result;
      }
    );
  };

}]);

mainModule.directive('decisionTreeResult', function () {
  return {
    restrict: 'E',
    scope: {
      result: '='
    },
    templateUrl: 'risk-assessment-result.html'
  }
});
body {
  margin: 50px;
}

button {
  margin: 5px;
}
<div ng-if="result">
    <label>Risk Assessment:</label>
    <div class="alert" ng-class="{ 'alert-success': result.risk === 'LOW', 'alert-warning': result.risk === 'MODERATE', 'alert-danger': result.risk === 'HIGH'}" role="alert">
        {{result.risk}}<span ng-if="result.description">: {{result.description}}</span>
    </div>
</div>
angular.module('decision.tree', ['ui.select', 'ngSanitize', 'ui.bootstrap'])

.directive('decisionTree', ['$compile', '$timeout', function($compile, $timeout) {

    return {
        restrict: 'E',
        scope: {
            node: '=',
            onResult: '&',
            onClear: '&'
        },
        templateUrl: 'decision-tree.html',
        link: function(scope, element, attributes) {

            scope.decision = {};

            // Grab container for next decision
            var childDecisionContainer = element.find('.next-decision-container');

            // Shallow copy all the immediate children so we can safely set extra properties
            scope.children = [];
            angular.forEach(scope.node.children, function (child) {
                scope.children.push(angular.extend({}, child));
            });

            // Focus on the first "focusable" element found
            $timeout(function() {
                element.find('* [data-focusable]').first().focus();
                scope.$broadcast('new-decision-appended');
            });

            scope.selectNode = function(node) {

                scope.decision.selected = node;
            };

            scope.$watch('decision.selected', function (node) {

                if (node) {
                    angular.forEach(scope.children, function (child) {
                        child.selected = (child === node);
                    });

                    childDecisionContainer.empty();

                    if (node.result) {
                        if (scope.onResult) {
                            $timeout(function(){
                                scope.onResult({result: node.result});
                            });
                        }
                    } else {
                        if (scope.onClear) {
                            scope.onClear();
                        }

                        var el = angular.element('<decision-tree node="decision.selected" on-result="onResult({result: result})" on-clear="onClear()"></decision-tree>');
                        $compile(el)(scope);
                        childDecisionContainer.html(el);
                    }
                }
            });
        }
    };
}])

.directive('modalBody', ['$compile', '$templateRequest', function ($compile, $templateRequest) {

    return {
        restrict: 'C',
        link: function (scope, element, attributes) {

            var resultContainer = element.find('div.decision-tree-result');

            function injectResultTemplate(template) {

                var el = angular.element(template);

                $compile(el)(scope);
                resultContainer.html(el);
            }

            if (scope.resultTemplate) {
                injectResultTemplate(scope.resultTemplate);
            } else if (scope.resultTemplateUrl) {
                $templateRequest(scope.resultTemplateUrl)
                    .then(
                        function(template) {
                            injectResultTemplate(template);
                        }
                    );
            }
        }
    };
}])

.factory('$decisionTree', ['$uibModal', '$timeout', function ($uibModal, $timeout) {

    return {

        openWizard: function (config) {

            return $uibModal.open({
                animation: false,
                templateUrl: 'decision-tree-wizard-modal.html',
                resolve: {
                    config: function () { return config; }
                },
                controller: function ($scope, $uibModalInstance, config) {

                    $scope.title = config.title;
                    $scope.decisionTree = config.decisionTree;
                    $scope.resultTemplate = config.resultTemplate;
                    $scope.resultTemplateUrl = config.resultTemplateUrl;

                    $scope.onDecisionResult = function (result) {

                      $scope.result = result;
                        
                      $timeout(function() {
                            $('#acceptButton').focus();
                      });
                    };

                    $scope.onDecisionClear = function () {

                        $scope.result = undefined;
                    };
                }
            }).result;
        }
    };
}]);
<div class="decision-tree">
    <div class="container-row">
        <div class="form-group">
            <label>{{node.question ? node.question : 'Please select an option:'}}</label>

            <ng-switch on="node.selector">
                <div ng-switch-when="drop-down" class="decision-tree-select-wrapper">
                    <ui-select autofocus focus-on="new-decision-appended" ng-model="decision.selected" theme="bootstrap" style="width: 330px;">
                        <ui-select-match allow-clear="false" placeholder=""><span ng-bind="$select.selected.value"></span></ui-select-match>
                        <ui-select-choices repeat="child in (children | filter: { value: $select.search })">
                            <div ng-bind-html="child.value | highlight: $select.search"></div>
                        </ui-select-choices>
                    </ui-select>
                </div>
                <div ng-switch-default class="decision-tree-buttons-container">
                    <button autofocus data-focusable ng-repeat="child in children" ng-click="selectNode(child)" ng-bind="child.value" class="btn" ng-class="{'btn-success': child.selected, 'btn-default': !child.selected}"></button>
                </div>
            </ng-switch>
        </div>
    </div>
    <div class="next-decision-container"></div>
</div>
<div class="modal-header">
    <h3 class="modal-title" ng-bind="title"></h3>
</div>
<div class="modal-body">
    <decision-tree node="decisionTree" on-result="onDecisionResult(result)" on-clear="onDecisionClear()"></decision-tree>
    <div class="decision-tree-result"></div>
</div>
<div class="modal-footer">
    <button class="btn btn-primary" id="acceptButton" ng-click="$close(result)" ng-disabled="!result">Accept</button>
    <button class="btn btn-default" ng-click="$dismiss()">Cancel</button>
</div>