I create a sidebar in a directive and append ui-sref-active="active" to all elements.
I must be having an issue targeting my states, or something with the abstract parent state is causing the ui-sref-active directive not to work..
In my routes I have:
$stateProvider.
state('main', {
url: '',
abstract: true,
template: '<div ui-view=""></div>',
resolve:{
otherCharts: function($q, $timeout, secondaryCharts){
var deferred = $q.defer();
var charts;
$timeout(function() {
charts = secondaryCharts.getSecondaryCharts();
deferred.resolve(charts);
}, 250);
return deferred.promise;
}
}
}).
state('dashboard', {
parent: 'main',
url: '/dashboard/',
templateUrl: '/app/free/templates/dashboard.html',
controller: function($scope, secondaryCharts){
$scope.secondaryCharts = secondaryCharts.getSecondaryCharts();
},
data: {
name: 'Dashboard'
}
}).
state('growth', {
parent: 'main',
url: '/dashboard/growth',
templateUrl: '/app/free/modules/donor-growth/donor-growth.html',
controller: 'make-donor-growth',
data: {
name: 'Donor Growth',
id: 0,
type: 'chart'
}
})
Then, in my html I have:
<li ui-sref="dashboard" ui-sref-active="active" href="/dashboard/" class="title Dashboard"><a "ui-sref="dashboard" href="/dashboard/"><i class="fa fa-tachometer"></i>Dashboard</a></li>
Yet, when I am on a specific state such as myapp.com/dashboard the active class is not being added.. Where am I going wrong targeting my state?
Thanks in advance!
Related
Say i am on a page http://localhost/#/edit/10/step2 and i want to have a link (anchor tag) that takes me to http://localhost/#/edit/10/step1.
What shall one put in ng-href="" and could this be achieved without specifying id (10) in the link?
<a ng-href="step1">Previous</a>
edit (routing):
.config(["$stateProvider", "$urlRouterProvider", "$httpProvider", ($stateProvider: ng.ui.IStateProvider, $urlRouterProvider: ng.ui.IUrlRouterProvider, $httpProvider: ng.IHttpProvider) => {
$urlRouterProvider.otherwise("/home");
$stateProvider
.state("MyModule", {
template: "<div ui-view></div>"
})
.state("home", {
url: "/home",
templateUrl: "App/home.html",
controller: "homeController as ctrl"
});
$httpProvider.interceptors.push("busyHttpInterceptor");
}]);
state (edit):
.state("edit", {
url: "/edit/:id",
templateUrl: "App/edit.html",
controller: "editController",
controllerAs: "ctrl",
resolve: {
}
})
I think you can do the redirection by a ng-click function :
//for the 'state', you can add a new one or edit the existing one depending on your requirement and restirctions
//Add a new one:
.state("edit.action", {
url: "/edit/:id/:action",
templateUrl: "App/edit.html",
controller: "editController",
controllerAs: "ctrl",
resolve: {
}
})
//in the html
<a ng-click=goToAction("step1")>Previous</a>
//in the controller 'editController', inject the service '$stateParams' and '$state'
$scope.goToAction = function(action) {
//get the ':id' from the url
var currentId = $stateParams['id'];
$state.go('edit.action', {
id: currentId,
action: action
});
}
If you want you can also apply regex to the parameter part of the url:
url: "/edit/{id:[a-zA-Z0-9]*}/:action
How do I access other subviews in the same state. I am building a page with a toolbar on top and a sidebar and I want a button on the toolbar to open/close the sidebar and buttons in the sidebar to change the content. easy of it's all in the same controller but what I did is to use ui-router's subview feature like this:
.state('dash', {
url: '/dash/:id',
views: {
nav: {
controller: 'NavCtrl',
controllerAs: 'ctrl',
templateUrl: '/views/navbar.html'
},
sidebar: {
controller: 'SidebarCtrl',
controllerAs: 'ctrl',
templateUrl: '/views/sidebar.html'
},
content: {
controller: 'DashCtrl',
controllerAs: 'ctrl',
templateUrl: '/views/dash.html'
}
}
})
UI looks like this:
Define a resolve and use it as a place to store common data for the activated 'dash' state.
app.config(function($stateProvider) {
$stateProvider.state('dash', {
url: '/',
resolve: {
dashData: function() {
return { input: "default value" };
}
},
views: {
nav: {
controller: function() {
},
controllerAs: 'ctrl',
template: '<h3>This is the Navbar</h3>'
},
sidebar: {
controller: function(dashData) { // Inject reference to resolve object
this.dashData = dashData;
},
controllerAs: 'ctrl',
template: 'content data visible in ' +
'the sidebar: <b>{{ ctrl.dashData.input }}<b>'
},
content: {
controller: function(dashData) { // Inject reference to resolve object
this.dashData = dashData;
},
controllerAs: 'ctrl',
template: '<input type="text" ng-model="ctrl.dashData.input">' +
'This is bound to dashData.input'
}
}
})
});
Inject the shared object into each controller
app.controller('DashCtrl', function(dashData, $scope) {
$scope.dashData = dashData;
});
app.controller('... ....
I put this example in a plunker for you: http://plnkr.co/edit/8M1zXN0W5ybiB8KyxvqW?p=preview
This would be a good example of where an abstract parent state comes in handy:
An abstract state can have child states but can not get activated itself. An 'abstract' state is simply a state that can't be transitioned to. It is activated implicitly when one of its descendants are activated.
https://github.com/angular-ui/ui-router/wiki/Nested-States-and-Nested-Views#abstract-states
And then especially this usecase:
inherit $scope objects down to children
Consider the following abstract parent state and it's child state:
$stateProvider.state('root', {
abstract: true,
url: '/dash',
templateUrl: 'root.html',
controller: 'rootController'
});
$stateProvider.state('dash', {
parent: 'root',
url: '/:id',
views: {
'navbar': {
templateUrl: 'navbar.html',
controller: 'navbarController'
},
'sidebar': {
templateUrl: 'sidebar.html',
controller: 'sidebarController'
},
'content': {
templateUrl: 'content.html',
controller: 'contentController'
}
}
});
Now you can store logic (and data) you need in your childstate in the controller of the abstract parent state:
angular.module('app').controller('rootController', [
'$scope',
function ($scope) {
$scope.sidebar = {
show: true
};
$scope.items = [{
name: 'Alpha'
}, {
name: 'Bravo'
},{
name: 'Charlie'
},{
name: 'Delta'
}];
$scope.selected = $scope.items[0];
$scope.select = function (item) {
$scope.selected = item;
}
}
]);
Example of using this logic/data in a template of the child state, sidebar.html:
<ul class="nav nav-pills nav-stacked">
<li ng-repeat="item in items" role="presentation">
{{item.name}}
</li>
</ul>
Here's a complete example with your requirements, i could post all the code here but i think that would be a bit too much:
http://embed.plnkr.co/2jKJtFM0GWsylyLcAdne/
I'll gladly answer any question you may have, just holler. Good luck!
if you'd name your controllers differently with controller as, you could use the NavCtrl in the sidebarCtrl's template. Maybe use some boolean value that exists on the NavCtrl, that decides what to show in the sidebar? (from the comment)
This should work, haven't tried it though.
.state('dash', {
url: '/dash/:id',
views: {
nav: {
controller: 'NavCtrl',
controllerAs: 'navCtrl',
templateUrl: '/views/navbar.html'
},
sidebar: {
controller: 'SidebarCtrl',
controllerAs: 'sidebarCtrl',
templateUrl: '/views/sidebar.html'
},
content: {
controller: 'DashCtrl',
controllerAs: 'dashCtrl',
templateUrl: '/views/dash.html'
}
}
})
sidebarService:
angular.module('app').value('sidebarService', {show: true});
navCtrl something like this:
function(sidebarService){
var vm = this;
vm.toggleSideBar = function(){sidebarService.show = !sidebarService.show;}//used in navbar.html
}
sidebarCtrl:
function(sidebarService){
var vm = this;
vm.showSideBar= sidebarService;
}
and then in sidebar.html you use the sidebar value service:
<div ng-if="sidebarCtrl.showSideBar.show">
<!--SideBar-->
</div
You can use events to communicate between controllers. Check the AngularJS documentation for $scope.$broadcast and `$scope.$on : https://docs.angularjs.org/api/ng/type/$rootScope.Scope
I am having an issue loading controllers / templates for each child state. I have a console.log in each state controller, yet they don't fire. Any ideas will be greatly appreciated!
Intent is to always load artist for every child state following.
var stateConfig = ['$stateProvider', function($stateProvider) {
// State Configurations
$stateProvider
.state('artist', {
abstract: true,
url: '/' + artistSlug,
controller: "artistCtrl",
resolve: {
artist: function(artist){
return artist.getArtist();
}
}
})
.state('events', {
parent: 'artist',
url: '',
controller: 'eventsCtrl',
templateUrl: "/templates/artist/events.html"
})
I think you need to revise your states / params
It should go artists -> artists.artist -> artists.artist.events. Then if you go to //site.com/artists/justintimberlake/events it will resolve artist and then events
var stateConfig = ['$stateProvider', function($stateProvider) {
// State Configurations
$stateProvider
.state('artists', {
abstract: true,
url: '/artists'
})
.state('artists.artist', {
url: '/:artistId',
controller: 'artistCtrl',
template: '<div ui-view>Artist Template Wrapper for Artist and Events</div>',
resolve: {
artist: function (artist, $stateParams) {
return artist.getArtist($stateParams.artistId);
}
}
})
.state('artists.artist.events', {
url: '/events',
controller: 'eventsCtrl',
templateUrl: '/templates/artist/events.html',
resolve: {
events: function (artist, $stateParams) {
return artist.getArtistEvents($stateParams.artistId);
}
}
})
}];
I have this state:
}).state('sport', {
url: "/:sport",
templateUrl: '/app/sports/sport.tpl.html',
controller: 'SportController',
controllerAs: 'controller'
});
and the controller looks like this:
.controller('SportController', ['$stateParams', function ($stateParams) {
var self = this;
// Object to hold our parameter
self.slug = $stateParams.sport;
}]);
So, what I am trying to do is pass this parameter to another state. Which I have set up like this:
.config(['$stateProvider', function ($stateProvider) {
// Set up our state(s)
$stateProvider.state('sport.designer', {
url: "/designer",
abstract: true,
templateUrl: '/app/designer/designer.tpl.html',
controller: 'DesignerController',
controllerAs: 'controller'
}).state('sport.designer.team', {
url: "",
templateUrl: '/app/designer/team.tpl.html'
}).state('sport.designer.kit', {
url: "/kit",
templateUrl: '/app/designer/kit.tpl.html'
}).state('sport.designer.design', {
url: "/design",
templateUrl: '/app/designer/design.tpl.html'
}).state('sport.designer.refine', {
url: "/refine",
templateUrl: '/app/designer/refine.tpl.html'
}).state('sport.designer.order', {
url: "/order",
templateUrl: '/app/designer/order.tpl.html'
});
}])
and the controller looks like this:
.controller('DesignerController', ['$stateParams', 'DesignerService', 'HttpHandler', 'Api', function ($stateParams, service, handler, api) {
var self = this;
var slug = $stateParams.sport; // Get our slug
console.log(slug);
}]);
So, there are a couple of issues here.
If set up a link like this: ui-sref="sport.designer.team({ sport: controller.slug })" then the view doesn't move from the sport state.
The reason I am using .team is because .designer is an abstract state and the team state is the default state that loads
Here is my html for the sport state:
<a ui-sref="sport.designer.team({ sport: controller.slug })">Test</a>
Can anyone see what I am doing wrong?
I got this working today.
My sport state stayed the same.
I changed the designer states to this:
// Set up our state(s)
$stateProvider.state('designer', {
url: ':sport/designer',
abstract: true,
templateUrl: '/app/designer/designer.tpl.html',
controller: 'DesignerController',
controllerAs: 'controller'
}).state('designer.team', {
url: '',
templateUrl: '/app/designer/team.tpl.html'
}).state('designer.kit', {
url: '/kit',
templateUrl: '/app/designer/kit.tpl.html'
}).state('designer.design', {
url: '/design',
templateUrl: '/app/designer/design.tpl.html'
}).state('designer.refine', {
url: '/refine',
templateUrl: '/app/designer/refine.tpl.html'
}).state('designer.order', {
url: '/order',
templateUrl: '/app/designer/order.tpl.html'
});
and then in my sport.tpl.html I set the link up:
<div class="container">
<div class="row">
<div class="col-md-12">
<h1>{{ controler.slug }}</h1>
<p>This will be the sport homepage.</p>
<p><a ui-sref="designer.team({ sport: controller.slug })">Click to get started</a></p>
</div>
</div>
</div>
and that was it. Designer, did not have to be a child of sport.
Hi I'm trying to dynamically create templates based on the uri eg, contacts/jane would use the template contacts.jane.html
contacts.js
'use-strict';
angular.module('meanApp')
.config(function ($stateProvider) {
$stateProvider
.state('contacts', {
url: '/contacts',
controller: 'ContactsCtrl',
views: {
'': {
templateUrl: 'app/contacts/contacts.html'
},
'list#contacts': {
templateUrl: 'app/contacts/contacts.list.html'
},
'details#contacts': {
templateUrl: function ($stateParams) {
return 'app/contacts/' + $stateParams.id + '.html';
},
controller: function ($scope, $stateParams) {
}
}
}
})
.state('contacts.details', {
url: '/:id',
controller: 'ContactsCtrl'
});
});
contacts.html
<div ng-controller="ContactsCtrl">
<h1>My Contacts</h1>
<div ui-view="details"></div>
<div ui-view="list"></div>
There is a working example. What we need here, is to define the template inside of the child state:
$stateProvider
.state('contacts', {
url: '/contacts',
controller: 'ContactsCtrl',
views: {
'': {
templateUrl: 'app/contacts/contacts.html'
},
'list#contacts': {
templateUrl: 'app/contacts/contacts.list.html'
},
'details#contacts': {
// this could be, filled on a contacts state
// with some default content
template: "place for detail",
}
}
})
// this state has the 'id' defined
// so, here we can decide which template to use
// based on the $stateParams
.state('contacts.details', {
url: '/:id',
views: {
"details": {
controller: 'ContactsCtrl',
templateUrl: function($stateParams) {
url = 'app/contacts/' + $stateParams.id + '.html'
return url;
},
}
}
});
Also, the controller is defined in state so the template contacts should/could for example look like this (no ng-controller):
<div>
<h1>My Contacts</h1>
<div ui-view="list"></div>
<hr />
<div ui-view="details"></div>
</div>
Check that in action here