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>