Alright so I am having an issue with my named views loading content into my state.
Its mostly problematic because I really do not know why it isnt working; with angular that usually means a typo but I have recreated my problem in a plunker and am getting the same results so maybe I am missing something.
I know this question has been asked before:: however in all the results I saw on here people were putting content into an abstract state's children. what I want to do is have a state; populate it with named views as well as other content relevant to that state; then have that states children load content into the main states named views. should be simple enough and rather straight forward but alas mine will not work for me.
Here is the link to the plunker made:: http://plnkr.co/edit/TWCQuoIyJRvTb42Z7xxe?p=preview
as you will see the main 'papers' state is loading. however none of the content from the named views is being loaded into the 'papers' state from its child state 'papers.views'.
Code for reference:
Module declaration and state config(app.js)
var app = angular.module( 'app', [ 'ui.router' ] );
app.config(['$stateProvider', '$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/papers');
// States
$stateProvider
.state( 'papers', {
url: "/papers",
templateUrl: 'papers.html'
}) // nested paper state + views
.state( 'papers.views', {
views: {
'#papers': {
templateUrl: 'papers.home.html'
},
'paper1#papers': {
templateUrl: 'papers.paper1.html'
},
'paper2#papers': {
templateUrl: 'papers.paper2.html'
}
}
})
}
])
.run(['$rootScope', '$state', '$stateParams',
function ($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
}])
Index page (papers.html loading here):
<body>
<div ui-view></div>
</body>
papers page ( where nested views are supposed to be loading )
<h1>This is the papers page. other views should load in here</h1>
<div ui-view ></div>
<div ui-view="paper1" ></div>
<div ui-view="paper2" ></div>
One way, how to fix this is to add two lines:
change your parent to be abstract : true and
force child to define url : ''
There is an upated and working plunker, this is the updated state def:
$urlRouterProvider.otherwise('/papers');
// States
$stateProvider
.state( 'papers', {
// NEW LINE
abstract: true,
url: "/papers",
templateUrl: 'papers.html'
}) // nested paper state + views
.state( 'papers.views', {
// NEW LINE - because parent is abstract, same url here - this will be loaded
url: '',
views: {
'#papers': {
templateUrl: 'papers.home.html'
},
'paper1#papers': {
templateUrl: 'papers.paper1.html'
},
'paper2#papers': {
templateUrl: 'papers.paper2.html'
}
}
})
More details about this in documentation:
How to: Set up a default/index child state
Check it here
Another way could be to change the default:
$urlRouterProvider.otherwise('/papers/view');
And add url: '/view' to child state:
...
.state( 'papers.views', {
url: '/view',
views: {
...
Check this version here
Related
I am trying to make a nested views, here is the plunker https://embed.plnkr.co/oRMnMW4QoWwhSkm9maHf/. The state changes but the template not changes.
Can anyone correct me what have I done wrong
Goto Link > Second Nested .
On Clicking the button , state changes successfully but the content is not injected. I want the link page content to be replaced by the second-nested content
Try to put abstract:true on the 'father' root like:
var routerApp = angular.module('routerApp', ['ui.router','ncy-angular-breadcrumb']);
routerApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home/list');
$stateProvider
// HOME STATES AND NESTED VIEWS ========================================
.state('home', {
url: '/home',
abstract: true,
templateUrl: './partial-home.html'
})
// nested list with custom controller
.state('home.list', {
url: '/list',
templateUrl: './partial-home-list.html',
controller: function($scope) {
$scope.dogs = ['Bernese', 'Husky', 'Goldendoodle'];
}
})
.state('home.second', {
url: '/second',
templateUrl: './second.html',
});
});
routerApp.run(['$rootScope', '$state', function ($rootScope, $state) {
$rootScope.$on('$stateChangeStart', function (event, toState) {
console.log("state Change")
});
}]);
but Remember .. if you put abstract: true .. the url is not a real one .. it's a prefix .. or as i call it .. a father of other routing ..so you can not call it in the .otherwise()
And in your link (and routing) of the second view .. just remove the .list ... so like this:
.state('home.second', { //<-- HERE .. REMOVE THE .list
url: '/second',
templateUrl: './second.html',
});
and in the link:
// AND HERE ..
<a ui-sref="home.second" class="btn btn-danger">Second Nested</a>
Answer is pretty simple - you are initializing 3rd level of nesting states but in ./partial-home-list.html you've didn't add ui-view directive.
Add <ui-view></ui-view> in ./partial-home-list.html and you will see that it works as you defined.
If you want to display home.list.second as separate page then define second state like this
.state('home.second', {
url: '/home/list/second',
templateUrl: 'second.html',
});
Remember to update ui-sref to home.second on button
--
Just to get nested breadcrumb I have not "nice" solution but will work.
-- Partial home list html
<div ng-if="state.current.name != 'home.list.second'">
<ul>
<li ng-repeat="dog in dogs">{{ dog }}</li>
</ul>
<div ncy-breadcrumb></div>
<a ui-sref="home.list.second" class="btn btn-danger">Second Nested</a>
</div>
<ui-view></ui-view>
App js
// nested list with custom controller
.state('home.list', {
url: '/list',
templateUrl: 'partial-home-list.html',
controller: function($scope, $state) {
$scope.state = $state;
$scope.dogs = ['Bernese', 'Husky', 'Goldendoodle'];
}
})
.state('home.list.second', {
url: '/second',
templateUrl: 'second.html',
});
I am using ui-router and I try to create several views inside one of my nested states.
In my logic, all of the views should be visible whenever the parent state is active.
I have read the wiki page on multiple named views multiple times, but could not get anything working yet.
My state template would show up, but my views never do.
Here is a working plunker
(You have to click on "Followers" in the navbar for the view to show up. Haven't figured why yet).
Important parts are the config
app.config([
'$stateProvider',
'$urlRouterProvider',
function ($stateProvider, $urlRouterProvider){
$stateProvider
.state('dashboard', {
url: '/dashboard',
templateUrl: 'dashboard.html',
controller: 'DashboardCtrl',
authenticate: true
}).state('dashboard.followers', {
url: '/followers',
templateUrl: 'dashboard.followers.html',
controller: 'DFollowersCtrl',
authenticate: true
}).state('dashboard.followers.add', {
views: {
'add': {
templateUrl: 'dashboard.followers.add.html',
controller: 'DFollowersAddCtrl',
authenticate: true
}
},
});
$urlRouterProvider.otherwise('dashboard');
}
]);
The main dashboard template (level 2, using a generic ui-view)
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<div class="flash-area">
<flash-message duration="2000" show-close="true"></flash-message>
</div>
<ui-view></ui-view>
</div>
and the dashobard.followers specific level 3 view, that has a specific name
<div>
<h1 class="page-header">Followers</h1>
<div ui-view="add"></div>
</div>
The trick is coming from, I think, a combination of :
I want to use level 3 nesting
Level 2 uses a generic ui-view, because it may contains my dashboard or something else.
Level 3 contains specific views, as it is where I want to use "views" and not "states" (as far as I understood, at least).
The final aim is to have more than one view in my template, but for now I reduced the attempts to only show the 'add' view.
I have seen several similar questions on SO already, such as this one or this other one but so far my attempts have not been fruitful.
I can access my "add" view directly if I reach its URL (when I try setting one)
But the dashboard.followers state does not get populated by the views.
I think there are several mistakes here you made:
if you want the url of dashboard.followers state and dashboard.followers.add state to be same, the child state dashboard.followers.add does not need the url option
probably can be a mistake(I am not sure because no code is provided), if you don't use the
views: { ... }
named views, but just directly use
url: '/followers',
templateUrl: '/partials/dashboard.followers.html'
angular just assume you want to insert the template in an unnamed <div ui-view></div> in the parents state's template not the root template. for example, in my example code, for state dashboard.followers, since it is a child state of dashboard, if I want to insert the template in root html template, I have to use
views: {
'#': {
template: '<div><h1 class="page-header">Followers</h1><a ui-sref="dashboard.followers.add">add</a><div ui-view="add"></div></div>'
}
}
/* myApp module */
var myApp = angular.module('myApp', ['ui.router'])
.config(['$stateProvider', function($stateProvider) {
$stateProvider
.state('landing', {
url: '/',
template: '<p>landing</p><a ui-sref="dashboard">dashboard</a>'
})
.state('dashboard', {
url: '/dashboard',
template: '<p>landing</p><a ui-sref="dashboard.followers">followers</a>'
})
.state('dashboard.followers', {
url: '/followers',
views: {
'#': {
template: '<div><h1 class="page-header">Followers</h1><a ui-sref="dashboard.followers.add">add</a><div ui-view="add"></div></div>'
}
}
})
.state('dashboard.followers.add', {
views: {
'add': {
template: '<p>followers</p>'
}
}
});
}])
.controller('MyAppCtrl', function($scope, $state /*, $stateParams*/ ) {
$state.go("landing");
});
<body ng-app="myApp" ng-controller="MyAppCtrl">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.18/angular-ui-router.js"></script>
<div ui-view></div>
</body>
update
I made two plunkers to fit two different situation:
if you want to dynamically load add state to ui-view="add" by a
link, check
this out.
if you just want a sub template to be loaded always on dashboard.followers state, simply remove add states, and use views: {...} to load the add template in. here is the plunker.
I'm having some difficulties to understand how UI-Router abstract state work.
Here's the thing :
I have an index.html with only a <ui-view> tag inside its <body>.
There is two main states : Landing and App ( /landing and /app ).
No problem with the landing state for now, because its only a static file ( no child view etc ).
But for my /app state, I need an abstract parent state that cover the whole application ( need to resolve User Profile for each child states ).
The thing is that child of this abstract state also have sub-view. And I can't make those render.
My $stateProvider config (simplified) :
//landing state, no problem here
.state('landing', {
url: '/landing',
templateUrl: 'landing.html'
})
// my abstract parent state, with the resolve
.state('root', {
url: '',
abstract: true,
template: "<div ui-view></div>",
resolve: {
current_user: function (UserFactory) {
return UserFactory.initCurrentUserProfile();
}
}
})
// the child which cannot render the view headerAndSearchbar
.state('root.app', {
url: '/app',
templateUrl: 'app.html',
views: {
'headerAndSearchbar': {
templateUrl: './partials/header/headerAndSearchbar.html'
}
}
})
app.html :
<div ui-view="headerAndSearchbar">
</div>
<div>
This is app.html
</div>
Note that if i remove views declaration in the state root.app, i can see the text "This is app.html".
headerAndSearchbar.html only contains simple html & css
Any ideas ? I'm bashing my head on this- What am I missing?
There are two issues.
Firstly, There are in fact two views, inside of the child 'root.app'.
Unnamed (the one, which is related to templateUrl 'app.html')
named view 'headerAndSearchbar'
And that means, that both most be declared inside of the views : {} setting:
.state('root.app', {
url: '/app',
//templateUrl: 'app.html',
views: {
'' : { templateUrl: 'app.html' },
'headerAndSearchbar': { ... n
}...
But that is not enough.
Secondly, we need absolute naming for the second (named) because it is not related to its parent, but to itself:
.state('root.app', {
url: '/app',
//templateUrl: 'app.html',
views: {
'' : { templateUrl: 'app.html' },
// this is the same as a path to parent view 'headerAndSearchbar#root'
// 'headerAndSearchbar': { ...
// this means ... search in this state, inside of app.html
'headerAndSearchbar#root.app': { ...
}...
Check these for more details:
Angularjs ui-router not reaching child controller
Angular UI Router - Nested States with multiple layouts
I just started migrating to AngularJS and I'm already having problems with the $stateProvider from the angular-ui/ui-router framework. This is what I have so far:
angular
.module('testApp', ['ui.router'])
.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/index/home");
$stateProvider
.state('index', {
abstract: true,
url: "/index",
template: "parent"
})
.state('index.home', {
url: "/home",
template: "child"
})
})
.controller("MainController", function() {
})
Now, running this script redirects me to http://example.com/#/index/home but it only displays the parent string on the page. The child string is not being shown. From my understanding this should load the first template because we are on the /#/index domain part and then the second because we are on a nested page /#/index/home.
Can someone help me and explain why this is not working as intended?
In your template for the parent you need another <div ui-view></div> in order to render child states.
If you want multiple nested views, you can have multiple ui-view in your parent template. You just have to name them. For example,
parent template:
<h1>parent</h1>
<div ui-view="child1"></div>
<div ui-view="child2"></div>
And you define the child states as follows:
$stateProvider
.state('index', {
abstract: true,
url: "/index",
template: "parent"
})
.state('index.home', {
url: "/home",
views: {
'child1': {
templateURL: "child1.html"
}
}
})
.state('index.home2', {
url: '/home2',
views: {
'child2': {
templateURL: 'child2.html'
}
}
})
*note I used templateURL instead of template. Assuming your app has modular file structure.
I have an Angular application that depends on Angular ui-router. This application has multiple pages which share a common template such as the navbar:
var app = angular.module('app', ['ngSanitize', 'ngResource', 'ngRoute', 'ui.router'])
.config(['$urlRouterProvider', '$stateProvider', ($urlRouterProvider, $stateProvider) => {
$urlRouterProvider.otherwise("/index");
$stateProvider
.state('index', {
url: "/index",
views: {
'navbar': {
templateUrl: 'Views/Partials/navbar.cshtml',
controller: 'App.Controllers.NavbarController'
},
'content': {
templateUrl: 'Views/index.cshtml',
controller: 'App.Controllers.IndexController'
}
}
})
.state('settings', {
url: "/settings",
views: {
'navbar': {
templateUrl: 'Views/Partials/navbar.cshtml',
controller: 'App.Controllers.NavbarController'
},
'content': {
templateUrl: 'Views/settings.cshtml',
controller: 'App.Controllers.SettingsController'
}
}
});
}]);
Both '/index' and '/settings' share the same template 'Views/Partials/navbar.cshtml'. Upon testing, i found out, that every time a "page" is loaded for an url, all the views in it are reloaded.
Is it possible to avoid reloading the navbar, if it has been previously loaded already?
You should be able to extract the navbar into a parent state of your existing states. This way the navbar only loads when the parent state is entered and you should be able to change child states that share this parent without affecting it.
While there are better organised ways to do this, my quick and dirty way would be to rename the states you have to withnav.index and withnav.settings. Then remove the navbar view from them and add the following state.
$stateProvider
.state('withnav', {
abstract: true,
views: {
'navbar': {
templateUrl: 'Views/Partials/navbar.cshtml',
controller: 'App.Controllers.NavbarController'
}
}
});