i can't get this structure to work!
I am trying to resolve my sidebarActions when the parent root state is called so the value can be used in all root.child states.
When i use root as a parent i don't get a view, tried to read about ui.router but i cant figure out what i am doing wrong. There is a ui-view="" specified in my layout & i can display home state if i remove root.
I also want to ask if i am planing this right? My goal is to fill out data for the sidebar based on state and IF the state has a sidebar view.
app.config([
'$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {
// For any unmatched url, redirect to root
$urlRouterProvider.otherwise('/');
$stateProvider
.state('root', {
url: '',
'abstract': true,
resolve: {
// Will resolve som data here for the child views.
sideBarActions: function () {
return { value: 'simple!' };
}
}
})
.state('root.home', {
url: '/',
templateUrl: '/App/Main/views/home/home.cshtml',
controller: 'app.controllers.views.home', // sideBarActions is injected in controller
});
}
]);
EDIT CREATED A PLUNKR:
Plunkr
This is how far i am, i have created the routes so they work. But i still want to solve the problem where im not doing this DRY.
Can i create this without repeating the sidebar all the time? and inject the resolved data inside the controller if the view should have a sidebar?
I did updated your plunker a bit here. Firstly the left and main areas are moved into root state - which is still abstract.
There are two substates home and customers... for which also generated navigation on the left, basd on the rosolved sideBarActions. Finally, there is a customer detail, substate of customers.
$stateProvider
.state('root', {
url: '',
'abstract': true,
resolve: {
sideBarActions: function() {
return {
actionNames: ['root.home','root.customers']
};
}
},
views: {
'': { templateUrl: 'tpl.layout.html',},
'sidebar#root': {
templateUrl: 'tpl.actionBar.html',
controller: 'actionBarCtrl',
}
}
})
.state('root.home', {
url: '/',
template: '<div>root.home content</div>',
})
.state('root.customers', {
url: '/customers',
templateUrl: 'tpl.customers.html',
})
.state('root.customers.customer', {
url: '/:customerId',
template: '<div>customer with {{id}}</div>',
controller: function($scope, $stateParams)
{$scope.id = $stateParams.customerId},
})
The only place where we can see absolute naming is in the root state definition, where we introduce the template, and do inject into there as well 'sidebar#root': {...}
That all should show how the ui-router multi-views and nested-states could bring us lot of profit. Check it here
Related
I have an app.config with UI-Router. It has a login page with it's controller, recoverLogin and I want to put a template with footer, header and more stuff with new states that could be loaded into the template (in an especificplace).
My module is:
var app = angular.module("app", [
"ui.router",
"pascalprecht.translate"
]);
My routes are;
app.config(function($stateProvider, $urlRouterProvider)
{
$stateProvider
.state("login", {
url: "/login",
templateUrl: "views/accessControl/login.html",
controller: "loginCtrl"
});
$stateProvider
.state("recoverLogin", {
url: "/recoverLogin",
templateUrl: "views/accessControl/recoverLogin.html",
controller: "recoverLoginCtrl"
});
$stateProvider
.state("template", {
url: "/template",
templateUrl: "views/templates/template.html",
controller: "templateCtrl"
})
.state("template.dashboard", {
url: "/dashboard",
templateUrl: "views/dashboard/dashboard.html",
controller: "dashboardCtrl"
})
$urlRouterProvider.otherwise("login");
})
I have in my index <ui-view></ui-view> for the place of the loadings and another <ui-view></ui-view> in template.html int he place where I want to load more stuff like dashboard.html, but this doesn't works. it loads dashboard.html without the template created in template.html. I have founded lot of documentation that doesn´t works for me. Any Idea?
Here there are a plunker example of the idea: https://plnkr.co/edit/ZsGZjDKOBTIXFpPtXasN?p=preview
There is updated plunker and working plunker.
The template of the mainTemplate state is now lookin like this:
place for main:
<div ui-view="main"></div>
place for other:
<div ui-view="other"></div>
so it has two (could be more) places for more stuff. And this is the state redefined:
.state("mainTemplate.dashboard", {
name: "main",
url: "/dashboard",
views: {
'main' : {
templateUrl: "dashboard.html",
controller: "dashboardCtrl"
},
'other' : {
template: "<h2>other view</h2>",
}
}
});
What we can see is views : {} object being used to defined multiple content for more targets. Read about that more details here:
Angular UI Router - Nested States with multiple layouts
Nested states or views for layout with leftbar in ui-router?
play or observe the changes here
I setup a small example based on the article posted on setting up UI routing.
I modified the example to test explicitly navigating from a child nested state to sibling state using $state.go(). any ideas what I am doing wrong?
I keep getting the error below:
Error resolving State. Could not resolve .paragraph from state home.list
$stateProvider
// HOME STATES AND NESTED VIEWS ========================================
.state('home', {
url: '/home',
templateUrl: 'partial-home.html'
})
// nested list with custom controller
.state('home.list', {
url: '/list',
templateUrl: 'partial-home-list.html',
controller: function($scope,$state) {
$scope.dogs = ['Bernese', 'Husky', 'Goldendoodle'];
$scope.navigateToNextState = function () {
$state.go('.paragraph');
};
}
})
// nested list with just some random string data
.state('home.paragraph', {
url: '/paragraph',
template: 'I could sure use a drink right now.'
})
http://plnkr.co/edit/Nae6xz9qcBp3IRYi0wcD?p=preview
Controller should be adjusted like this:
controller: function($scope, $state) {
$scope.dogs = ['Bernese', 'Husky', 'Goldendoodle'];
$scope.navigateToNextState = function () {
$state.go('^.paragraph');
};
}
We need a $state as one of function params. And we are in a child, so we have to use '^.paragraph' (instead of '.paragraph') to ask for another child of our parent
Checked working fixed version here
I'm having problems loading my child states on an abstract true parent state.
This is my parent state
.state('main', {
url: '/main',
templateUrl: 'templates/main.html',
abstract: true
})
This is the child states
.state('main.panels', {
views: {
'ticketsPanel': {
templateUrl: 'templates/ticketsPanel.html'
},
'productsPanel': {
templateUrl: 'templates/productsPanel.html'
},
'categoriesPanel': {
templateUrl: 'templates/categoriesPanel.html'
}
}
})
I have a login page after I login I want to load all 3 child views.
This is the code that process the login.
.controller('loginController', function($scope, Authentication, $log, $state){
$scope.formData = {};
$scope.processForm = function(){
Authentication.login($scope.formData);
var promise = Authentication.getEmployee();
promise.then(function(respond){
localStorage.setItem('employee', JSON.stringify(respond));
$state.go('main.panels');
})
}
})
The $state.go('main.panels') activates the child state of the main state parent, but the problem I'm having is that DOM is showing the element have being loaded but I can only see them partially in my view. It's like they didn't got fully loaded.
My question is how can I wait for all the views in the main.panels to be loaded completely before I transition to that view.
We do have 'resolve' property that can be provided in the definition of each and every state (or view) whatever you want to load. So what angular-ui-router does is that it resolves the 'resolve' property first and only then the HTML template is being rendered on the browser.
You can define the child state in the following way :
.state('main.panels', {
views: {
'ticketsPanel': {
templateUrl: 'templates/ticketsPanel.html',
resolve: function(LoginService){return LoginService};
},
'productsPanel': {
templateUrl: 'templates/productsPanel.html',
resolve: function(LoginService){return LoginService};
},
'categoriesPanel': {
templateUrl: 'templates/categoriesPanel.html',
resolve: function(LoginService){return LoginService};
}
}
})
You can even read the following links for more details :
https://github.com/angular-ui/ui-router/wiki
https://github.com/angular-ui/ui-router/wiki/Nested-States-%26-Nested-Views#inherited-resolved-dependencies
http://www.jvandemo.com/how-to-resolve-angularjs-resources-with-ui-router/
It has been explained in detail. Hope this helps :)
nested states also makes the views nested, meaning the router will look for a named ui-view within the parent template and render it there, and since that's not what you're trying to do you have to implicitly state that it's the parent view (absolute vs relative) like so:
.state('main.panels', {
views: {
'ticketsPanel#': {
templateUrl: 'templates/ticketsPanel.html',
resolve: function(LoginService){return LoginService};
},
'productsPanel#': {
templateUrl: 'templates/productsPanel.html',
resolve: function(LoginService){return LoginService};
},
'categoriesPanel#': {
templateUrl: 'templates/categoriesPanel.html',
resolve: function(LoginService){return LoginService};
}
}
})
'productsPanel#' is like saying 'productsPanel' # nothing which mean the upper parent or root view.
https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views#view-names---relative-vs-absolute-names
I am trying to put a nested view inside my modal. I can pull in the first-layer views fine but the nested view is tricking me somehow. Not sure what I am missing here?
http://plnkr.co/edit/g9cScdORPOz57zGCzQDA
var App = angular.module('App', ['ui.router']);
// routes
// -------------------------
App.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
// default state route
.state('app',{
url: '/',
views: {
'content': {
templateUrl: 'home.html'
},
'modals': {
templateUrl: 'modal.html'
}
}
})
// + modal content
.state('app.form', {
url: '/form',
views: {
'modal-content#modals': {
templateUrl: 'form.html'
}
}
})
//catch all route
$urlRouterProvider.otherwise('/');
})
Like Nikhil.agw said, you are not changing your state when you open your modal.
You could do it like that: http://plnkr.co/edit/eMNBBUYmKI6PRPiyU4xx?p=preview
<li>Open this modal</li>
Then just include a way to return to the previous state when the modal closes.
It is not going to work because on click you are only toggling the modal. Your state/route is not being changed. And route/state is not being changed, how will the nested state come in picture?
I have my routes set up as below. Its too frustrating that the view in view.tab is loaded but its controller isn't called. I tried without the paramaters, but it still doesn't work as expected. Does anyone have any idea on how to solve this?
$stateProvider
.state('index', {
url: '/',
templateUrl: viewsRoot + 'restaurants/index.htm',
controller: 'RestaurantsCtrl'
})
.state('view', {
url: '/view',
controller: 'RestaurantsViewCtrl',
templateUrl: viewsRoot + '/restaurants/view.htm'
})
.state('view.tab', {
url: '/orders',
// controller: 'OrdersIndexCtrl',
controller: function ($scope) {
alert('This does not run');
},
views: {
"view": {
templateUrl: viewsRoot + '/restaurants/orders.htm'
}
}
});
$urlRouterProvider.otherwise("/");
You need to declare the controller along side the template:
views: {
"view": {
templateUrl: viewsRoot + '/restaurants/orders.htm',
controller: 'MyController' // (or a function, etc.)
}
The UI-Router wiki sort of alludes to this:
If you define a views object, your state's templateUrl, template and templateProvider will be ignored. So in the case that you need a parent layout of these views, you can define an abstract state that contains a template, and a child state under the layout state that contains the 'views' object.
Controllers are paired with a view. So if it ignores the "template" properties defined on the state, it seems to imply that it will ignore the controller too.
If you want all of your named views to share a controller, define an abstract parent state as the wiki suggests.