0

Im currently working on a voting app where users have to vote for the best item in 10 categories. This has to be presented as an accordion, meaning that each vote section must have its own div/element so that ng-leave and ng-enter is animated at different places/divs.


The Problem
Everything works fine on load, but when changing state, the state controllers aren't being called. eg, if i fire up the browser to app/#/voting/time everything is perfect! But when calling ui-sref="voting.store" or $state.go('voting.store')... the url changes, the template is loaded, the $statechangesuccess $emits, but the new state's controller doesn't execute.


Here is the JS:

angular.module('food', [ 
    'ngResource', 'ngAnimate', 'ui.router', 'ngSanitize',
    'food.voting', 'food.email', 'food.thankyou', 'app-templates'
])

angular.module('food.voting', [
    'foodAndDrink.voting.services', 'foodAndDrink.voting.states', 
    'foodAndDrink.voting.controllers'
]);

angular.module('food.voting.states', [])
    .config(function($stateProvider) {
        $stateProvider.state('voting', {
            url: "/voting",
            templateUrl: "voting/vote-page-wrapper.tpl.html",
            controller: "Voting"
        })
        .state('voting.time', {
            url: "/time",
            parent: 'voting',
            votingSectionName: "Time-Saver",
            voteViewName: 'timesaverview',
            views: {
                'timesaverview@voting': { 
                    controller: "Voting.Time",
                    templateUrl: 'voting/vote-section.tpl.html'
                }
            }
        })
        .state('voting.store', {
            url: '/store',
            parent: 'voting',
            votingSectionName: "Store Essential",
            voteViewName: 'cupboardessentialview',
            views: {
                'cupboardessentialview@voting': { 
                    templateUrl: 'voting/vote-section2.tpl.html',
                    controller: "Voting.Store"
                },
            }
        })
    });

angular.module('food.voting.controllers', [])
    .controller('Voting', ['$scope', '$state', 'UserData', function(,$scope, $state, UserData){
        $scope.products = {};
        $scope.savedvotes = {};
        $scope.currentStageNum = undefined;
        $scope.votingChildStates = [];
        $scope.state = {};
        var allStates = $state.get();

        for (var i=0; i < allStates.length; i++){
            if( allStates[i].name.indexOf('voting.') >= 0 ) $scope.votingChildStates.push( angular.extend(allStates[i]) );
        }

        for(var i=0; i < $scope.votingChildStates.length; i++){
            //get current stage number
            if( $scope.votingChildStates[i].name === $state.current.name ) $scope.currentStageNum = i;
        }


        $scope.getSectionProducts = function(savename, ngResourceService){
            if($scope.products[savename]){
                $scope.products.listingItems = $scope.products[savename];
            }else{
                ngResourceService().query()
                    .$promise.then(function(products){
                        $scope.products.listingItems = $scope.products[savename] = products;
                });
            }
        };

    }])

    .controller('Voting.Time', ['$scope', 'ProductFactory', 'ImageSaveLocation', 
        function($scope, ProductFactory, ImageSaveLocation){
            console.log('time controller loaded');
            $scope.voteSavename = 'time';
            $scope.imgSaveDir   = ImageSaveLocation.timeSaver();
            $scope.getSectionProducts($scope.voteSavename, ProductFactory.timeSaver);

    }])

    .controller('Voting.Store', ['$scope', 'ProductFactory', 'ImageSaveLocation', 
        function($scope, ProductFactory, ImageSaveLocation){
            console.log('store controller loaded');
            $scope.voteSavename = 'store';
            $scope.imgSaveDir   = ImageSaveLocation.cupboardEssesntials();
            $scope.getSectionProducts($scope.voteSavename, ProductFactory.storeCupboardEssesntials);
    }])

the template html for the parent state:

<div class="voting">
    <form name="sectionVoteForm" novalidate>

        <div class="text-center">
            <hgroup>
                <h2>Step {{(currentStageNum + 1)}} of {{votingChildStates.length}}</h2>
                <h3 class="hidden-xs">{{$state.current.votingSectionName}}</h3>
            </hgroup>

            <nav class="section-indicators hidden-xs">
                <a ui-sref="{{voteSection.name}}" ng-repeat="voteSection in votingChildStates" 
                ng-class="{current: $state.is(voteSection.name), 'pristine': voteSection.voteValid == undefined, invalid: voteSection.voteValid == false }"></a>
            </nav>
        </div>

        <div ng-repeat="voteSection in votingChildStates" class="votesection" ng-class="{'active-form': $state.is(voteSection.name)}">
            <ng-form name="vote">
                <div ui-view="{{voteSection.voteViewName}}" ng-class="{'back': state.back}"></div>
            </ng-form>
        </div>


        <p class="disclaimer">You must be 18 and stuff blah blah blah</p>
    </form>
</div>


Note:
When I manually list 10 divs for each category instead of ng-repeat, it works. according to https://github.com/angular-ui/ui-router/pull/858, dynamic ui-views are allowed e.g. <div ui-view="{{expression}}"></div>

DBrowne
  • 131
  • 9
  • Are you using 0.2.11? See: https://github.com/angular-ui/ui-router/issues/1324 Try building ui-router from 'master' – Chris T Sep 22 '14 at 15:29
  • Yea I tried that last night. No success. I found a work around by moving the definition of named states all into the views object for the voting parent state. And hide the states I didn't want with ng-show – DBrowne Sep 22 '14 at 20:41
  • Sorry just read the link you provided, I thought you meant that it is fixed in 0.2.11. I'm using ui-router with `bower`, how do i set the version to `master` in the `bower.json`? – DBrowne Sep 22 '14 at 20:48
  • found it! http://stackoverflow.com/questions/16949173/how-to-install-latest-untagged-state-of-a-repo-using-bower. I'll try it out tomorrow as i haven't updated the repo at work. Thanks @Chris T – DBrowne Sep 22 '14 at 21:01
  • You'll need to git clone the repository, build it using grunt, and test it (all outside of the bower environment). Here, I did it for you https://gist.github.com/christopherthielen/d9531f179078ff8369d7 – Chris T Sep 22 '14 at 21:34

0 Answers0