Angular UI-Router: nested views - angularjs

I have two col layout with header and footer. Header has page navigation (GetStarted, Component). Of the 2 columns, one is for sidenav and other is for main content.
When "GetStarted" nav is active, sidenav is populated with respective links (overview, examples)
When "Component" nav is active, sidenav is populated with respective links (checkbox, alert)
Upon clicking "Overview" link area is populated with its data
<ul class="nav nav-tabs">
<li role="presentation" class="active">Default</li>
<li role="presentation">Disabled</li>
</ul>
<section class="content__main__tab__content col-xs-12 col-sm-12 col-md-12 col-lg-12">
<form id="checkbox--default">
<div class="input__checkbox--default" id="checkbox--default">
<!-- <div class="form-group"> -->
<fieldset>
<legend>Default</legend>
<label for="gi-checkbox">Checkbox Label
<div class="checkbox-input-wrapper group__input-wrapper">
<input type="checkbox" class="checkbox" id="gi-checkbox">
</div>
</label>
</fieldset>
<!-- </div> -->
</div>
</form>
</section>
Main content has 2 nav tabs for checbox states (default & disable). By clicking the "default" its content must be displayed and same goes for disabled. I'm new to angular and I kinda got first level nested view working. But couldn't the whole thing working. here is the code sample
index.html
<body ng-app="mendouiApp" id="mendo__home" data-spy="scroll" data-target=".scrollspy">
<nav class="navbar navbar-fixed-top navbar-inverse">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" ui-sref="home"><img src="images/gi-logo.png" alt="logo"/></a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="active"><a ui-sref="home">Get Started</a></li>
<li><a ui-sref="components">Components</a></li>
</ul>
</div><!-- /.nav-collapse -->
</div><!-- /.container -->
</nav><!-- /.navbar -->
<div class="wrapper" ui-view></div> <!--/.container-->
component.html
<div class="content__wrapper">
<div class="row">
<div class="content__secondary content__secondary--l scrollspy">
<ul id="sidenav-fixed-l" class="nav hidden-xs hidden-sm affix-top" data-spy="affix">
<li>
<h5>COMPONENTS</h5>
</li>
<li ng-repeat="item in componentsList">
<a ui-sref="{{item.link}}" ng-cloak>{{item.name}}</a>
</li>
</ul>
</div>
<div ui-view></div>
</div> <!--/.row-->
</div> <!--/.content-wraper-->
app.js
(function(){
var mendouiApp = angular.module('mendouiApp', ['ui.router', 'ui.router.stateHelper']);
mendouiApp.constant('COMPONENTS_LIST', {
name: 'sidenav',
templateUrl: '../components/components.list.html',
abstract: true,
children: [{
name: 'alerts',
url: '/alerts',
templateUrl: '../components/alerts/alerts.html'
}]
});
mendouiApp.config(function($stateHelperProvider, $urlRouterProvider, $locationProvider, $urlMatcherFactoryProvider, COMPONENTS_LIST) {
$urlMatcherFactoryProvider.strictMode(false);
$urlRouterProvider.otherwise('/home');
$locationProvider.hashPrefix('!');
$stateHelperProvider
.state('home', {
url: '/home',
templateUrl: '../gettingstarted.html',
controller: 'getStartedController'
})
.state('layouts', {
url: '/layouts',
templateUrl: '../layouts.html'
})
.state('screenpatterns', {
url: '/screenpatterns',
templateUrl: '../screenpatterns.html'
})
.state('yogi', {
url: '/yogi',
templateUrl: '../yogi.html'
})
.state('components', {
url: '/components',
templateUrl: '../components.html',
controller: 'componentsController'
})
.state(COMPONENTS_LIST, {
keepOriginalNames: true
})
.state('components.button', {
url: '/button',
templateUrl: '../components/button/button.html'
}) .state('components.checkbox', {
url: '/checkbox',
templateUrl: '../components/checkbox/checkbox.html'
})
.state('components.forms', {
url: '/forms',
deepStateRedirect: true,
sticky: true,
views: {
'': { templateUrl: '..forms.html' },
'inline#components.forms': {
templateUrl: '../components/forms/form-inline/forminline.html'
},
'default#components.forms': {
templateUrl: '../components/forms/form-default/formdefault.html'
},
'multicolumn#components.forms': {
templateUrl: '../components/forms/form-multicolumn/formmulticolumn.html'
}
}
});
// use the HTML5 History API
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
});
mendouiApp.controller('componentsController', ['$scope', '$state', 'sideNavService', function($scope, $state, sideNavService, COMPONENTS_LIST){
$scope.componentsList = sideNavService.components;
$scope.componentsnav = COMPONENTS_LIST.children;
$scope.go = function(tab) {
$state.go(tab.name);
}
}]);
mendouiApp.controller('getStartedController', ['$scope', '$state', 'sideNavService', 'fixedSideNavService', function($scope, $state, sideNavService, fixedSideNavService ){
$scope.getstartedList = sideNavService.getstarted;
}]);
/*** This is for the external url reference ***/
mendouiApp.run(function($rootScope, $state, $stateParams, $window, fixedSideNavService, copyToClipBoardService) {
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams, $state, $stateParams) {
if (toState.external) {
event.preventDefault();
$window.open(toState.url, '_self');
}
});
$rootScope.$on('$viewContentLoaded', function(event){
fixedSideNavService.fixedsidenav();
copyToClipBoardService.copytoclipboard();
});
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
$state.transitionTo('home');
});
})();
service.js
angular.module('mendouiApp').service('sideNavService', function() {
return {
"getstarted" : [
{
"name" : "Overview",
"link" : "home.overview"
}
{
"name" : "Summary",
"link" : "home.overview"
}
],
"components" : [
{
"name" : "Alerts",
"link" :"components.alert"
},
{
"name" : "Button",
"link" :"components.button"
},
{
"name" : "Button Groups",
"link" :"components.buttongroup"
},
{
"name" : "Button Icons",
"link" :"components.buttonicons"
},
{
"name" : "Checkbox",
"link" :"components.checkbox"
},
{
"name" : "Datepicker",
"link" :"components.datepicker"
},
{
"name" : "Forms",
"link" : "components.forms"
}
]
};
});

Your question was a bit messy, but after a while playing with I could understand I made this fiddle: http://jsfiddle.net/canastro/c4kt2myc/2/ I hope it works as you were expecting.
The main thing to focus on here is:
.state("root.components.button", {
url: '/components/button',
views: {
'main#': {
template: `
<div>
<a ui-sref="root.components.button.default">default</a>
<a ui-sref="root.components.button.disabled">disabled</a>
<div ui-view="buttonsContent"></div>
</div>
`
}
}
})
.state("root.components.button.default", {
url: '/components/button/default',
views: {
'buttonsContent#root.components.button': {
template: 'root.components.button.default'
}
}
})
.state("root.components.button.disabled", {
url: '/components/button/disabled',
views: {
'buttonsContent#root.components.button': {
template: 'root.components.button.disabled'
}
}
})
In the first level you have a abstract route so you can always have your basic layout present.
Then in the Started / Components routes, you load content into the main and side ui-views.
In all of the Started and Component child routes you just override the main views.
And finally, in the last level you need to say you want to fill the content of a ui-view created in the previous state, by doing something like VIEWNAME#STATENAME.

Related

angularjs, load template and controller partialy using lazy load

Please help me,
I was get an error when loading partialy template view and controller in angularjs using lazyload.
I got these error message:
Error: ng:areq
Bad Argument
Argument 'meSygroupController' is not a
How to fix it, when I will build big project, so its imposible to load all javascript controller in one time while load first page. And how to apply new controller to existing module
Here some codes :
Filename : angular-app.js
var colorAdminApp = angular.module('colorAdminApp', [
'ui.router',
'ui.bootstrap',
'oc.lazyLoad'
]);
colorAdminApp.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/app/dashboard/v2');
$stateProvider
.state('app', {
url: '/app',
templateUrl: 'demo?page=template/app',
abstract: true
})
.state('app.sys', {
url: '/system',
template: '<div ui-view></div>',
abstract: true
})
.state('app.sys.sygroup', {
url: '/sygroup',
templateUrl: 'me_sygroup',
// controller: "meSygroupController",
data: { pageTitle: 'Master Grup Akses' },
resolve: {
service: ['$ocLazyLoad', function($ocLazyLoad) {
return $ocLazyLoad.load({
serie: true,
files: [
'me/meSygroupController.js',
'coloradmin/assets/plugins/jquery-jvectormap/jquery-jvectormap-1.2.2.css',
]
});
}]
}
})}]);
colorAdminApp.run(['$rootScope', '$state', 'setting', function($rootScope, $state, setting) {
$rootScope.$state = $state;
$rootScope.setting = setting;
}]);
And here template :
<div ng-controller="meSygroupController" class="frm">
<!-- <div> -->
<ol class="breadcrumb pull-right">
<li>Beranda</li>
<li>Sistem</li>
<li class="active">Grup User</li>
</ol>
<h1 class="page-header">Grup User <small>kelompok otorisasi user...</small></h1>
<!-- begin panel -->
<div class="panel panel-inverse">
<div class="panel-heading">
<div class="panel-heading-btn">
<i class="fa fa-expand"></i>
<i class="fa fa-repeat"></i>
<i class="fa fa-minus"></i>
<i class="fa fa-times"></i>
</div>
<h4 class="panel-title">Daftar Grup User</h4>
</div>
<div class="panel-body">
Panel Content Here
</div>
</div>
<!-- end panel -->
</div>
And here the controller
colorAdminApp.controller('meSygroupController', function($scope, $rootScope, $state) {
angular.element(document).ready(function() {});
$scope.test = function() { alert(111); }
$scope.test();
});
Please Helpme.
Arif Diyanto

angularjs accordion list anchor alternate elements

I have an accordion list populated as follows:
<ion-list>
<div ng-repeat="day in days"><br>
<div class="item item-icon-left" ng-click="toggleGroup(day)" ng-class="{active: isGroupShown(day)}">
<i class="icon icon-accessory" ng-class="isGroupShown(day) ? 'ion-minus' : 'ion-plus'"></i>
{{day.name}}
</div>
<a class="item item-icon-left item-accordion" ng-show="isGroupShown(day)" ng-repeat="exercise in day.exercises" type="item-text-wrap"
href="#/tab/plan/{{exercise.id}}">
{{exercise.name}}
<!-- Trial LED -->
<span style="float:right;"><i ng-show="{{exercise.watchedToday}}==true" class="ion-checkmark-round"></i></span>
</a>
</div>
</ion-list>
This populates list as follows:
Route which handles this is:
.state('tab.exercise', {
url: '/plan/:exerciseId',
resolve: {
authenticated: ['djangoAuth', function(djangoAuth){
return djangoAuth.authenticationStatus();
}],
},
views: {
'tab-plan': {
templateUrl: '/templates/video.html',
controller: 'videoCtrl'
}
},
cache: false
})
However I have few other routes like:
.state('tab.wordschatz', {
url: '/plan/12', <= notice here (this can be 8/9/10/11/12)
resolve: {
authenticated: ['djangoAuth', function(djangoAuth){
return djangoAuth.authenticationStatus();
}],
},
views: {
'tab-plan': {
templateUrl: '/templates/wortschatz.html',
controller: 'wortschatzCtrl',
data: {
css: '/css/wortschatz.css'
}
}
},
cache: false
})
I basically want to navigate to different pages on alternate accordion elements clicks. How can I have separate anchor links for alternate elements?

Angular ui-router crashing browsers

So I have no idea what is wrong, but im assuming i have a loop running in the background of my code or that im routing incorrectly. But all i know is when i try to go to my index page, my entire browser is taken down, no errors or anything, just crashing. Any help would really be appreciated im just trying to move on from this problem.And in case this changes anything i am using a rails backend.
planoxApp.config(['$stateProvider','$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/',
templateUrl: 'templates/home/nav.html',
authenticate: true
})
.state('home.index', { // our home page
url: '/index',
views: {
"": {templateUrl: 'templates/home/home.html'},
"assembly#index": { templateUrl: "templates/home/assembly.html" },
"client#index": { templateUrl: "templates/home/client.html" },
"photoplan#index": { templateUrl: "templates/home/home_photoplan.html" }
},
authenticate: true
})
Here is the main routes causing problems, the home one is just a nav bar, and when you go to the home tab its supposed to take you to the index page, but no dice. Im not sure how much of my controller i should show, but here a small part.Its the parts that directly effect the routes.
app.run(function ($rootScope,$location, $localStorage){
$localStorage.recent = ""
$rootScope.$on('$routeChangeSuccess', function() {
console.log("working")
recent.push($location.$$path);
});
});
app.run(function ($rootScope, $state, AuthService) {
$rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState, fromParams){
if (toState.authenticate && !AuthService.isAuthenticated()){
// User isn’t authenticated
console.log(AuthService.isAuthenticated())
$state.transitionTo("login");
event.preventDefault();
}
});
});
// GET request Area
$http.get('client.JSON').success(function(data){
$scope.clients = data;
});
$http.get('photoplan.JSON').success(function(data){
$scope.photoplans = data;
$scope.complete = true;
// if(main.photoplans.plano_order_status === "Complete"){
// console.log()
// $scope.complete = true;
// }else{
// $scope.complete = false;
// }
});
$http.get('assembly.JSON').success(function(data){
// main.assemblys = $filter('filter')(data, function(d){return d.employee_id == mainid});
$scope.assemblys = data;
console.log($scope.assemblys)
});
$http.get('employee.JSON').success(function(data){
$scope.employees = data;
});
}]);
This is the index page, and one of the nested views it has, all the views look roughly the same.
<div class="container" ng-controller="MainCtrl">
<!-- Main Section -->
<div class="home no-subheader container">
<div class="row" >
<!-- left -->
<section name="assembly-queue" class="molding col-md-4" id="assembly">
<div class="gutter" >
<div ui-view="assembly"> </div>
</div>
</section>
<!-- <section name="employee-queue" ng-if="type === 'admin'" class="molding col-md-4" id="employee">
<div class="gutter" id="scrollArea">
<div ui-view=".employee"></div>
</div>
</section> -->
<!-- middle -->
<section name="clients" class="molding col-md-4" id="clients">
<div class="gutter" >
<div ui-view="client"> </div>
</div>
</section>
<!-- right -->
<section name="photoplans" class="molding col-md-4" id="photoplans">
<div class="gutter" >
<div ui-view="photoplan"> </div>
</div>
</section>
</div>
</div>
</div>
This is the assembly page.
<div id="expanding" >
<div class="top row">
<h2> Assembly Queue</h2>
<form class="navbar-form navbar-left default" role="search">
<div class="form-group">
<input type="text" ng-model="searchassembly" class="form-control query" placeholder="Search Assembly Queue">
</div>
</form>
</div>
</div>
<article class="assembly snippet row" ng-repeat="assembly in assemblys|filter:searchassembly" >
<div class="left col-xs-7" >
<address>{{assembly.address_part1}},{{assembly.address_part2}}</address>
<p class="timeline-data"> Due on {{assembly.date_due}}</p>
<p class="timeline-data"> Job Type: {{assembly.job_type}}</p>
<p class="timeline-data"> Delivery Type: {{assembly.delivery_type}}</p>
</div>
<div class="right col-xs-5 text-center">
<div class="corner-ribbon" ng-click="open(assembly.id)" > </div>
<button ng-if="assembly.new_order" class="btn btn-default" ui-sref="photoplans({ id : assembly.photoplan_id })" ><span class="fa fa-pencil-square-o" aria-hidden="true"></span></button>
<button ng-if="assembly.new_order === false" class="btn btn-default" ui-sref="assign({address : assembly.address, realtor: assembly.realtor})" ><span class="fa fa-external-link" aria-hidden="true"></span></button>
</div>
</article>
If anyone has had similar issues or can see red flags in this please let me know, i am really stuck on this issue.
Okay so i actually found the answer myself, and im leaving the solution here for future people who might have this issue. But basically i need to have word of some kind in my home route, so instead of just /, i need /home. Because the browser was trying to load this #//index, and that was causing crashes. When using rails and angular together, make sure to have named routes to prevent this problem. Also make sure your nested views look like this, whatever#parent.child. Heres my new code.
planoxApp.config(['$stateProvider','$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'templates/home/nav.html',
authenticate: true
})
.state('home.index', { // our home page
url: '/index',
views: {
"": {templateUrl: 'templates/home/home.html'},
"assembly#home.index": { templateUrl: "templates/home/assembly.html" },
"client#home.index": { templateUrl: "templates/home/client.html" },
"photoplan#home.index": { templateUrl: "templates/home/home_photoplan.html" }
},
authenticate: true
})

Angular ui-router, scroll to next step on state change with different controller and template

I'm using UI-router in my app and I'd like to so a simple "scrollTo" to an anchor when the URL/state changes. I want to load new controller and template when state changes.
I'm using ng-boilerplate.
Index file
<div class="collapse navbar-collapse" collapse="menuCollapsed" ng-click="collapse()">
<ul class="nav navbar-nav navbar-right nav-link">
<li ui-sref-active="active">
<a href ui-sref="home">
<i class="fa fa-home"></i>
Home
</a>
</li>
<li ui-sref-active="active">
<a href ui-sref="service">
<i class="fa fa-info-circle"></i>
Service
</a>
</li>
<li ui-sref-active="active">
<a href ui-sref="portfolio">
<i class="fa fa-briefcase"></i>
Portfolio
</a>
</li>
<li ui-sref-active="active">
<a href ui-sref="team">
<i class="fa fa-users"></i>
Team
</a>
</li>
<li ui-sref-active="active">
<a href ui-sref="testimonial">
<i class="fa fa-comments"></i>
Testimonial
</a>
</li>
<li ui-sref-active="active">
<a href ui-sref="contact">
<i class="fa fa-envelope"></i>
Contact
</a>
</li>
</ul>
</div>
</div>
</div>
<div ui-view="main">
</div>
Home template and js
<div class="banner">
<div class="intro-body">
<h1>CREATIVE DIGITAL<br> SOLOUTIONS</h1>
<p>Proin iaculis consequat sem cure.</p>
<a href ui-sref="portfolio" class="btn btn-success">VIEW PORTFOLIO</a>
</div>
</div>
angular.module( 'ngBoilerplate.home', [
'ui.router',
'plusOne'
])
/**
* Each section or module of the site can also have its own routes. AngularJS
* will handle ensuring they are all available at run-time, but splitting it
* this way makes each module more "self-contained".
*/
.config(function config( $stateProvider ) {
$stateProvider.state( 'home', {
url: '/home',
views: {
"main": {
controller: 'HomeCtrl',
templateUrl: 'home/home.tpl.html'
}
},
data:{ pageTitle: 'Home' }
});
})
/**
* And of course we define a controller for our route.
*/
.controller( 'HomeCtrl', function HomeController( $scope ) {
})
;
Service Template & Js
<div class="container" id="service">
<div class="service-intro">
<h2>Why to choose company?</h2>
</div>
</div>
angular.module( 'service', [
'ui.router'
])
.config(function config( $stateProvider ) {
$stateProvider.state( 'service', {
url: '/service',
views: {
"main": {
controller: 'ServiceCtrl',
templateUrl: 'service/service.tpl.html'
}
},
data:{ pageTitle: 'service' }
});
})
.controller( 'ServiceCtrl', function HomeController( $scope ) {
})
;
APP JS
angular.module( 'ngBoilerplate', [
'templates-app',
'templates-common',
'ngBoilerplate.home',
'ngBoilerplate.about',
'service',
'portfolio',
'team',
'testimonial',
'contact-us',
'ui.router',
'ngAnimate'
])
.config( function myAppConfig ( $stateProvider, $urlRouterProvider ) {
$urlRouterProvider.otherwise( '/home' );
})
.run( function run () {
})
.controller( 'AppCtrl', function AppCtrl ( $scope, $location,$rootScope ) {
$rootScope.$on('$stateChangeStart', function () {
$scope.slide = $scope.slide || 'slide-left';
});
$scope.collapse = function() {
$scope.menuCollapsed = true;
};
$scope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){
if ( angular.isDefined( toState.data.pageTitle ) ) {
$scope.pageTitle = toState.data.pageTitle + ' | Teknuk' ;
}
});
})
;
So, when you enter the page the URL would be domain.com/home
When you click the first button I'd like my controller code to change the URL to domain.com/#/service and scroll down to the "service" div and controller + template updated.
Ideally, when the user hits the back button it would revert to the first URL and scroll back up to home.
Anybody know how to do this?
Why you dont use native scrolling ? https://github.com/angular-ui/ui-router/wiki/Quick-Reference#autoscroll

AngularJS Step wizard, disable progress based on values

I am using ui.router to create my views and I have set up this set of states:
.config(['$stateProvider', function ($stateProvider) {
// Set up our state(s)
$stateProvider.state('designer', {
url: '/:sport/designer',
abstract: true,
templateUrl: '/app/designer/index.tpl.html',
controller: 'DesignerController',
controllerAs: 'controller'
}).state('designer.team', {
url: '',
templateUrl: '/app/designer/team.tpl.html',
data: {
pageTitle: 'Create your team'
}
}).state('designer.kit', {
url: '/kit',
templateUrl: '/app/designer/kit.tpl.html',
data: {
pageTitle: 'Choose your garments'
}
}).state('designer.design', {
url: '/design',
templateUrl: '/app/designer/design.tpl.html',
data: {
pageTitle: 'Choose your design'
}
}).state('designer.refine', {
url: '/refine',
templateUrl: '/app/designer/refine.tpl.html',
data: {
pageTitle: 'Refine your design'
}
}).state('designer.order', {
url: '/order',
templateUrl: '/app/designer/order.tpl.html',
data: {
pageTitle: 'Order your kit'
}
}).state('designer.save', {
url: '/save',
templateUrl: '/app/designer/save.tpl.html',
data: {
pageTitle: 'Save your kit',
requireLogin: true
}
});
}])
The index template looks like this:
<div class="container designer">
<div class="row designer-header">
<div class="col-md-6" ng-include="'/app/designer/tpls/header.tpl.html'">
</div>
<div class="col-md-6" ng-include="'/app/designer/tpls/navigation.tpl.html'">
</div>
</div>
<div class="row">
<div class="col-md-12" ng-include="'/app/designer/tpls/total.tpl.html'" ng-hide="controller.garments.loading">
</div>
</div>
<div class="row designer-body">
<ui-view></ui-view>
</div>
</div>
The navigation include looks like this:
<nav class="navbar navbar-designer">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="collapse navbar-collapse" id="designer-menu">
<ul class="nav navbar-nav navbar-right">
<li ui-sref-active="active"><a ui-sref=".team">Your team</a></li>
<li><a>|</a></li>
<li ui-sref-active="active"><a ui-sref=".kit">Kit</a></li>
<li><a>|</a></li>
<li ui-sref-active="active"><a ui-sref=".design">Design</a></li>
<li><a>|</a></li>
<li ui-sref-active="active"><a ui-sref=".refine">Refine</a></li>
<li><a>|</a></li>
<li ui-sref-active="active"><a ui-sref=".order">Order</a></li>
</ul>
</div>
</nav>
So, the idea is that I want to build this in steps; i.e. When the page is first loaded I would like the user to only be able to advance to the next step (.kit) when they have filled in the first page, which looks like this:
<div class="col-md-12">
<div class="alert alert-warning alert-dismissable" ng-show="controller.colours.data && controller.colours.data.length === 0">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
You must have at least one colour in the database before you can create a team / kit.
</div>
<alert-error error="controller.colours.error"></alert-error>
<form name="teamForm" novalidate ng-show="!controller.colours.loading && !controller.colours.error">
<div class="form-group">
<label class="sr-only" for="teamName">Team name</label>
<div class="input-group">
<div class="input-group-addon">1</div>
<input type="text" class="form-control" id="teamName" placeholder="Enter your team name" ng-model="controller.model.team.data.name" ng-change="controller.saveSession()" required>
</div>
</div>
<div class="form-group">
<label class="sr-only" for="colours">Colours</label>
<div class="picker colour-picker">
<div class="input-group">
<div class="input-group-addon">2</div>
<input type="text" class="form-control" id="colours" placeholder="Choose your colours" disabled>
</div>
<ul class="picker-dropdown list-inline form-control">
<li ng-repeat="colour in controller.colours.data" ng-class="{ 'active': controller.matchColour(colour) }">
<a href style="background-color: #{{ colour.hex }};" ng-click="controller.setColour(colour)"></a>
</li>
</ul>
</div>
</div>
</form>
<p><a class="btn btn-primary pull-right" ui-sref="designer.kit">Choose teamwear</a></p>
</div>
All the other "tabs" should be disabled. And then similarly, when I advance to the kit view I would like the user only to be able to advance when they have made a selection, this is the kit page:
<div class="col-md-12">
<div class="alert alert-warning alert-dismissable" ng-show="controller.garments.data && controller.garments.data.length === 0">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
It appears that your sport does not have any garments associated with it.
</div>
<alert-error error="controller.garments.error"></alert-error>
<form ng-show="!controller.garments.loading && !controller.garments.error">
<div class="form-group">
<label class="sr-only" for="clubName">Club name</label>
<div class="input-group">
<div class="input-group-addon">1</div>
<input type="text" class="form-control" id="clubName" placeholder="Choose your teamwear">
</div>
</div>
<div class="picker garment-picker">
<ul class="picker-dropdown list-inline">
<li ng-repeat="garment in controller.garments.data" ng-class="{ 'active': controller.matchGarment(garment) }"><a href ng-click="controller.setGarment(garment)">{{ garment.title }}</a></li>
</ul>
</div>
</form>
<p><a class="btn btn-primary pull-right" ui-sref="designer.design">Design teamwear</a></p>
</div>
Does anyone know how I could do this?
I can provide more information if needed.
I have answered this myself with the aid of resolve.
Here are my states now:
// Set up our state(s)
$stateProvider.state('designer', {
url: '/:sport/designer',
abstract: true,
templateUrl: '/app/designer/index.tpl.html',
controller: 'DesignerController',
controllerAs: 'controller',
resolve: {
model: ['DesignerService', function (service) {
console.log('hi');
// return our model
return service.get();
}]
}
}).state('designer.team', {
url: '',
templateUrl: '/app/designer/team.tpl.html',
data: {
pageTitle: 'Create your team'
}
}).state('designer.kit', {
url: '/kit',
templateUrl: '/app/designer/kit.tpl.html',
data: {
pageTitle: 'Choose your garments'
},
resolve: {
model: ['$q', 'DesignerService', function ($q, service) {
// Defer our promise
var deferred = $q.defer();
// Get our model
var model = service.get();
// If we have selected our colours and our team name
if (model.team.data.colours.length > 0 && model.team.data.name) {
// resolve our promise
deferred.resolve(model);
} else {
// Otherwise reject our promise
deferred.reject();
}
// Return our promise
return deferred.promise;
}]
}
}).state('designer.design', {
url: '/design',
templateUrl: '/app/designer/design.tpl.html',
data: {
pageTitle: 'Choose your design'
},
resolve: {
model: ['$q', 'DesignerService', function ($q, service) {
// Defer our promise
var deferred = $q.defer();
// Get our model
var model = service.get();
// If we have selected any garments
if (model.kit.data.garments.length > 0) {
// resolve our promise
deferred.resolve(model);
} else {
// Otherwise reject our promise
deferred.reject();
}
// Return our promise
return deferred.promise;
}]
}
}).state('designer.refine', {
url: '/refine',
templateUrl: '/app/designer/refine.tpl.html',
data: {
pageTitle: 'Refine your design'
},
resolve: {
model: ['$q', 'DesignerService', function ($q, service) {
// Defer our promise
var deferred = $q.defer();
// Get our model
var model = service.get();
// If we have selected our design
if (model.kit.data.design) {
// resolve our promise
deferred.resolve(model);
} else {
// Otherwise reject our promise
deferred.reject();
}
// Return our promise
return deferred.promise;
}]
}
}).state('designer.order', {
url: '/order',
templateUrl: '/app/designer/order.tpl.html',
data: {
pageTitle: 'Order your kit'
},
resolve: {
model: ['$q', 'DesignerService', function ($q, service) {
// Defer our promise
var deferred = $q.defer();
// Get our model
var model = service.get();
// TODO: check for the applied colours
if (model.kit.data.templates.length > 50) {
// resolve our promise
deferred.resolve(model);
} else {
// Otherwise reject our promise
deferred.reject();
}
// Return our promise
return deferred.promise;
}]
}
}).state('designer.save', {
url: '/save',
templateUrl: '/app/designer/save.tpl.html',
data: {
pageTitle: 'Save your kit',
requireLogin: true
}
});
I admit the resolves are rather large, but I will find a way to make them smaller.
On a side note, because I am using resolve I can inject it into my controller without having to call the service again, i.e.:
.controller('DesignerController', ['$stateParams', 'model', function ($stateParams, model) {
var self = this,
slug = $stateParams.sport;
// Kit model
self.model = model;
}])
note: that the model is inject after all other dependencies. That makes a difference.

Resources