Angular ui.router dynamic sidebar - javascript

I have now tried whole day and i cant figure out how i shall solve this issue.
My goal is to display a sidebar thats get filled with data based on what state it is.
Lets say i am on the home page i may like this items:
Home item 1
Home item 2
And if i am on the about page i want this items:
About me
About my dog
I would like the data to get fetched from a service that returns data to the view based on what state it is.
I have tried to use ui.router's resolve function but i can't get the correct structure in my head to make it work.
Created a plunkr that shows how i mean but without the solution, what are the best practices and preferred ways when creating a dynamic sidebar with Angular and ui.router?
myapp.config(function($stateProvider) {
$stateProvider
.state('home', {
url: "",
views: {
"content": {
template: "This is the home.content"
},
"sidebar": {
templateUrl: 'sidebar.html',
controller: 'sidebarCtrl'
}
}
})
.state('about', {
url: "/about",
views: {
"content": {
template: "This is the about.content"
},
"sidebar": {
templateUrl: 'sidebar.html',
controller: 'sidebarCtrl'
}
}
})
})
Plunkr here
Edit
Can't figure out what i am doing wrong, no view is shown with this code:
app.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {
// For any unmatched url, redirect to root
$urlRouterProvider.otherwise("/");
$stateProvider
.state('root', {
url: '',
'abstract': true,
views: {
'sidebar#': {
templateUrl: '/App/Main/views/shared/sidebars/sidebar.cshtml',
controller: 'app.controllers.views.shared.sidebars.sidebar',
resolve: {
sidebarData: function (sidebarService) {
return sidebarService.getActions();
}
}
}
},
})
.state('root.home', {
url: "/",
views: {
'': {
templateUrl: '/App/Main/views/home/home.cshtml',
controller: 'app.controllers.views.home'
},
'content#root.home': {
templateUrl: '/App/Main/views/home/home-content.cshtml',
controller: 'app.controllers.views.home'
}
}
})
.state('root.about', {
url: "/customers",
views: {
'': {
templateUrl: '/App/Main/views/customers/customers.cshtml',
controller: 'app.controllers.views.customers'
},
'content#root.about': {
templateUrl: '/App/Main/views/customers/customers-content.cshtml',
controller: 'app.controllers.views.customers'
}
}
});
}]);
and here is how my home and customer views look like:
<div data-ui-view="sidebar">
Loading sidebar view.
</div>
<div data-ui-view="content">
Loading content view.
</div>

you could try to implement named and also an abstract view for your sidebar to reuse it among your other routes, also you can use the resolve parameter an return whatever dynamic data you need (from a service, resource, whatever), it could be something like this:
var myapp = angular.module('myapp', ["ui.router"])
myapp.config(function($stateProvider) {
$stateProvider
.state('root',{
url: '',
abstract: true,
views: {
'sidebar#': {
templateUrl: 'sidebar.html',
controller: 'sidebarCtrl',
resolve:{
sidebarData:function(){
return [{
state: '/stateHere',
text: 'Need'
}, {
state: '/stateHere',
text: 'to'
}, {
state: '/stateHere',
text: 'fill'
}, {
state: '/stateHere',
text: 'this'
}, {
state: '/stateHere',
text: 'with'
}, {
state: '/stateHere',
text: 'dynamic'
}, {
state: '/stateHere',
text: 'data'
}];
}
}
}
})
.state('root.home', {
url: "/",
views: {
'content#': {
template: "This is the home.content"
}
}
})
.state('root.about', {
url: "/about",
views: {
'content#': {
template: "This is the about.content"
}
}
})
});
myapp.controller('sidebarCtrl', ['$scope','sidebarData'
function($scope,sidebarData) {
$scope.sidebarData= sidebarData,
}
]);
EDIT:
check this working example:
http://plnkr.co/edit/Nqwlkq1vGh5VTBid4sMv?p=preview

Related

Is it possible to combine ion-tree-list with a navigation view?

I'm working on a web-app with ionic tabs.
On one of my pages i implemented the ion-tree-list from GitHub (Ion-tree-list from GitHub) as treeview.
In services.js i got the source for my tree:
.factory('VerificationTree', function () {
var verificationTree = [
{
id: 'operator',
name: 'Operator'
},
{
id: 'type_of_test',
name: 'Type of test',
},
{
id: 'system',
name: 'System'
},
{
id: 'component',
name: 'Component'
},
{
id: 'component_group',
name: 'Component group',
tree: [
{
id: 'component2',
name: 'Component'
}
]
}
];
return {
all: function () {
return verificationTree;
}
};
})
When i click on one the tree items - p.e. "type_of_test" - i want to open another page.
In controller.js i have defined a controller for the page with the tree.
Inside the Controller is a function, which opens the page by window.open.
.controller('VerificationCtrl', function ($scope, VerificationTree) {
$scope.verificationTree = VerificationTree.all();
$scope.$on('$ionTreeList:ItemClicked', function (event, item) {
if (item.id == 'type_of_test') {
window.open('templates/type-of-test.html');
};
//if (item.id == 'component2') {
// alert('The ion-tree-list item component2 was clicked');
//};
})
})
The page opens in a new tab but the layout is not okay anymore.
Is there a possibility to combine the tree with a navigation view like the following?
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('tab', {
url: '/tab',
abstract: true,
templateUrl: 'templates/tabs.html'
});
Or another example:
var app = angular.module('myApp', ['ionic']);
app.config(function($stateProvider) {
$stateProvider
.state('index', {
url: '/',
templateUrl: 'home.html'
})
.state('music', {
url: '/music',
templateUrl: 'music.html'
});
});
Not sure if I get you right, but what about doing a simple state change, when an item is clicked?
$stateProvider.state("tabs", {
url: "/tabs",
templateUrl: "templates/TabView.html",
abstract: true,
controller: "TabCtrl as tab"
}).state("tabs.home", {
url: "/overview",
templateUrl: "templates/HomeView.html",
controller: "HomeCtrl"
}).state("tabs.detail", {
url: "/detail/:id",
templateUrl: "templates/DetailView.html",
controller: "DetailCtrl"
})
On HomeView, add your TreeList and define the click function as follows:
.controller('HomeCtrl', function ($scope, $state, VerificationTree) {
$scope.verificationTree = VerificationTree.all();
$scope.$on('$ionTreeList:ItemClicked', function (event, item) {
if (item.id == 'type_of_test') {
$state.go('tabs.detail')
};
})
})
If you want to pass in the item as a param, you can define this in the stateProvider configuration as well. Check the UI-Router docs for additional information. https://github.com/angular-ui/ui-router/wiki/URL-Routing
Also if you don't want to transition to another tab when clicking an item, but stay in the tab and just change the state, you might try nested states. You could define your states like this:
$stateProvider.state("tabs", {
url: "/tabs",
templateUrl: "templates/TabView.html",
abstract: true,
controller: "TabCtrl as tab"
}).state("tabs.home", {
url: "/home",
abstract: true,
views: {
"home": {
template: "<ion-nav-view></ion-nav-view>"
}
}
}).state("tabs.home.overview", {
url: "/overview",
templateUrl: "templates/HomeView.html",
controller: "HomeCtrl"
}).state("tabs.home.detail", {
url: "/detail/:id",
templateUrl: "templates/DetailView.html",
controller: "DetailCtrl"
})
And then transition from Overview to Detail like this:
$state.go('tabs.home.detail')

Access a service in AngularUI Router onEnter callback

Im using Angular 1.5.6 and am using AngularUI Router (https://github.com/angular-ui/ui-router). I have different routes e.g. customer and users. In each of these there are different 'sub-roots' e.g. one for list and one for edt. Im setting up the customer route here:
import customerListModule from './list/customer.list';
import customerServiceModule from './services/customer.service';
...
...
function customerModule($stateProvider, $urlRouterProvider) {
'ngInject';
$urlRouterProvider
.when('/customer', ['$state', function($state) {
$state.go('customer.list.tracked');
}]);
$stateProvider
.state('customer', {
parent: 'root',
url: '/customer',
abstract: true,
views: {
'root#app': {
template: '<div class="customer" ui-view=""></div>'
}
},
onEnter: () => {
// in here I want to change my customer servce
},
})
.state('customer.list', {
url: '',
views: {
'#customer': {
template: '<customer></customer>'
}
},
breadcrumbs: {
name: 'customer.breadcrumbs.list'
},
params: {
saving: false
}
})
.state('customer.edit', {
parent: 'customer.list',
url: '/:id/edit',
views: {
'#customer': {
template: editTemplate(),
controller: manageCustomerCtrl,
controllerAs: 'manageCustomerVM'
}
},
breadcrumbs: {
name: 'customer.breadcrumbs.edit'
},
resolve: {
isAuthorized: 'readWriteAccess'
},
bodyClass: 'product-form'
});
}
export default angular.module('customerAdminUI.customer', [
'ui.bootstrap',
'ui.router',
customerListModule.name,
customerServiceModule.name,
...
...
])
.config(customerModule);
I have a customer service which I want to access in the onEnter callback of the customer state. I tried to inject it into the customerModule method so that I can use it in the onEnter() callback:
function customerModule($stateProvider, $urlRouterProvider, CustomerService) {
...
...
$stateProvider
.state('customer', {
parent: 'root',
url: '/customer',
abstract: true,
views: {
'root#app': {
template: '<div class="customer" ui-view=""></div>'
}
},
onEnter: () => {
CustomerService.clearSearch();
},
})
However I get the error:
Unknown provider: CustomerService
How can I use a service in the onEnter callback?
We can ask for a service as a param
// not ready for minification
onEnter: function(CustomerService) {
CustomerService.dowhatneeded...
},
// preferred way
onEnter: ['CustomerService', function(service) {
service.dowhatneeded...
}],

Dynamic template Angular UI-Router

I'm trying to load a navbar according to the user.
To do this, I need to set a dynamic template, but I can't see my $rootScope
$stateProvider
/*Login*/
.state('login', {
url: '/',
data: {pageTitle: 'Inicio de sesiĆ³n.'},
resolve: {},
views: {
'navbar': {
templateUrl: null,
controller: null
},
'body': {
templateUrl: "views/login.html",
controller: 'LoginController'
}
}
})
.state('home', {
url: '/home',
data: {pageTitle: 'Home.'},
views: {
'navbar': {
templateUrl: "views/navbar.html", //here dynamic template
controller: null
},
'body': {
templateUrl: "views/inicio.html",
controller: null
}
}
})
.state('perfil', {
url: '/perfil',
data: {pageTitle: 'Perfil de usuario.'},
views: {
'navbar': {
templateUrl: function (sessionProvider) {
var sessionFactory = sessionProvider.path();
return sessionFactory;
}, // this return a tring, but don't load anything
controller: null
},
'body': {
templateUrl: "views/usuario/perfil.html",
controller: 'UsuarioController'
}
}
});
i've tried use a service to load the data, but it didnt work, also tried to load it from the localStorageService, but don't display anything.
is there a single way to load it ?
There are features for this, like templateUrl and templateProvider. See all details here:
Trying to Dynamically set a templateUrl in controller based on constant
E.g. this could be an example of templateProvider used isntead of the 'templateUrl' static path
templateProvider: function(CONFIG, $templateRequest) {
console.log('in templateUrl ' + CONFIG.codeCampType);
var templateName = 'index5templateB.html';
if (CONFIG.codeCampType === "svcc") {
templateName = 'index5templateA.html';
}
return $templateRequest(templateName);
},

Accessing child state parameters in parent in Angular UI-Router

I have the following state configuration. How can I get id parameters in index state # view so that it could be accessible by both, left and detail views controllers? Now if I try to access it via $state.params.id it is undefined, but if I console.log($state) I can see the parameter in my console. I only need the parameter if available on first load of left view.
$stateProvider
.state('index', {
url: '/',
views: {
'#' : {
template: '/**/'
resolve: {
params: function ($state) {
return $state.params.id;
}
}
},
'left#index' : {
template: '/**/',
controller: 'AppController',
controllerAs: 'app'
},
'main#index' : {
template: '/**/'
}
})
.state('index.detail', {
url: '/:id',
views: {
'detail#index' : {
template: '/**/',
controller: 'DetailController',
controllerAs: 'detail',
}
}
});

Reload View on change url

I'm using angularjs with ui-router (with the helper stateHelperProvider) to collect views and controllers into the page.
But got a problem with my views not updating.
My code (the one that is related)
config.js
app.config(function($httpProvider, $urlRouterProvider, RestangularProvider, stateHelperProvider) {
$urlRouterProvider.otherwise("/");
stateHelperProvider
.state({
name: 'division',
url: '/division/:division',
views: {
'main': {
templateUrl: '/templates/division.main?uri=' + segment(2),
controller: 'DivisionController'
}
},
children: [
{
name: 'appcontent',
url: '/content',
views: {
'content': {
templateUrl: "templates/division.appcontent?uri=" + segment(2) + '&root=' + segment(4),
controller: 'AppContentController'
}
},
children: [
{
name: 'root',
url: '/:root',
views: {
'roots': {
templateUrl: "templates/division.appcontent.roots?uri=" + segment(2) + '&root=' + segment(4)
}
}
}
]
}
]
});
});
the code I use for linking
// linking to another division
<a ui-sref="division.appcontent({division: 'test2')">test2</a>
// linking to another root
<a ui-sref="division.appcontent.root({division: 'test2', root: 'test')">test2</a>
Explaining
But got a problem with my views not updating.
My views are the one with the actual data, so I need them to reload on change.
Like when :division in url is test1, then the template template/division.main have one set of data. But when :division in url is test2, then the template template/division.main have another set of data.
So whenever :division in url changes, I need to reload the template template/division.main and as well all the child templates.
But when :root changes in the url, I only need to reload the template template/division.appcontent.roots and not the template/division.main template.
Is this possible somehow or should I change to use only an API in order to get data.
I really hope this makes sense.
Note
segment is a function I have made to get some data from the angular route.
Thanks to the comment from #ChrisT I managed to get it to work using templateUrl as a fucnction.
My new config.js:
app.config(function($httpProvider, $urlRouterProvider, RestangularProvider, stateHelperProvider) {
$urlRouterProvider.otherwise("/");
stateHelperProvider
.state({
name: 'division',
url: '/division/:division',
views: {
'main': {
templateUrl: function(params) {
return '/templates/division.main?uri=' + params.division;
},
controller: 'DivisionController'
}
},
children: [
{
name: 'appcontent',
url: '/content',
views: {
'content': {
templateUrl: function(params) {
return 'templates/division.appcontent?uri=' + params.division + '&root=';
},
controller: 'AppContentController'
}
},
children: [
{
name: 'root',
url: '/:root',
views: {
'roots': {
templateUrl: function(params) {
return 'templates/division.appcontent.roots?uri=" + params.division + '&root=' + params.root;
}
}
}
}
]
}
]
});
});

Categories