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',
});
Related
I am trying to insert views inside view. But it is working only at the defined state but when I trying to change the view with the help of ngClick the state lost the path.
It is like
View 1
--Sub View 1.1
------Sub Sub View 1.2
But only one sub view will appear that too based on click.
Code is here
.config(function($stateProvider, $urlRouterProvider) {
//$urlRouterProvider.otherwise('/login');
$stateProvider
.state('login',{
url:'/login',
templateUrl: 'partials/login.html'
})
.state('home',{
url:'/home',
views:{
'':{templateUrl:'partials/home.html'},
'grid#home':{templateUrl:'partials/home-grid.html'},
'list#home':{templateUrl:'partials/home-list.html'},
},
controller: 'homeController'
})
})
And my Controller
.controller('homeController', function($rootScope, $scope, $location){
$rootScope.bodyClass = "backround-img1"
$scope.gridClick = function(){
$scope.Tview = 'grid#home'
}
$scope.listClick = function(){
$scope.Tview = 'list#home'
}
}) ;
and in my Main View i have declared the model as below:
<a ng-Click="gridClick()">Grid</a>
<a ng-Click="listClick()">List</a>
----------------------------------------
<div ui-view="{{Tview}}"></div>
Suggesting you with
$state.go('stateName');
You can use something like this in your controller
$scope.changeView=function()
{
$state.go('new');
}
The config should be
$stateProvider
.state("home", {
url: "/",
templateUrl: "newView.html",
controller: "MainCtrl",
})
.state("new", {
url: "/",
templateUrl: "someOtherView.html",
controller: "MainCtrl",
});
Here is the LIVE for your code
I'm new to angular and I'm trying to understand nested views concept.
Based on the example provided in their documentation: https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views
//home.html
<body>
<div ui-view="header"></div>
<div ui-view="settings"></div>
<div ui-view="content"></div>
</body>
I have settings.html which has a check box. If it's checked it will load in the view(not named) the advanced settings template if not it will load the basic template
//settings.html
<input type="checkbox" ng-change="change()" ng-model="advancedSettings" />
<div ui-view></div>
so far I have defined something like this:
$stateProvider
.state('home', {
views: {
'header': {},
'settings': {
templateUrl: 'settings.html'
},
'content': {},
}
})
since I have 2 templates basicSettings.html and advancedSettings.html that I need to load in the view from settings.html based on that checkbox, I thought I have to declare something like this:
.state('settings#home.basic',(){
templateUrl: 'basicSettings.html'
});
but it's not working, instead I receive a lot of errors on console. How is the best way to implement this, without removing names from homepage views(header,settings,content), also how do I change the view based on the check box?
Thanks
There is a working plunker
Solution here could be with states defined like this:
$stateProvider
.state('home', {
abstract: true,
url: "/home",
views: {
'header': {
template: "This is HEADER"
},
'settings': {
templateUrl: 'settings.html',
controller: 'HomeCtrl',
},
'content': {
template: "This is CONTENT"
},
}
})
.state('home.basic', {
url: "/basic",
templateUrl: 'basicSettings.html'
})
.state('home.advanced', {
url: "/advanced",
templateUrl: 'advancedSettings.html'
})
we have parent state "home" and two children. These are triggered on change by 'HomeCtrl', e.g. like this:
.controller('HomeCtrl', ['$scope', '$state',
function($scope, $state) {
$scope.advancedSettings = false;
$scope.change = function(){
var childState = $scope.advancedSettings
? "home.advanced"
: "home.basic";
$state.go(childState);
}
}])
So, based on the setting, the view target "settings" and its ui-view="" (unnamed one) is filled with a child state - basic or advanced
Check it here
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
Currently, main list html works
<div class="post row" ng-repeat="(postId, post) in posts">
{{ post.title }}
But when I click the item (one of the many in the list) and go to another page, the new page does not display the item in detail?
When I add the line below, including $stateParams in the dependencies, into the controller js file, {{ post.title }} appears but the data does not pass through.
$scope.post = $scope.posts[$stateParams.id]
UPDATE
This is the states code. (ignore missing syntax...im shortening it). Someone helped resolved the previous issue and provided the below codes for the viewing part (the last 2 states).
.state('tab.view', {
url: '/posts/:postId',
views: {
'tab-view': {
templateUrl: 'templates/tab-showpost.html',
controller: 'PostViewCtrl'
How the details are access after clicking on the list item.
app.controller('PostViewCtrl', function ($scope, $stateParams, Post) {
$scope.Post = Post.find($stateParams.postId); //i think this may be broken
One key piece that is missing in your question is how your stateProvider is configured. Please ensure that your states have the url set up correctly to send data though state parameters. I have a codepen here that shows one way to to have a list of items where clicking on one will take the user to it's details. Note how the states are set up...
angular.module('ionicApp', ['ionic'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('tabs', {
url: "/tab",
abstract: true,
templateUrl: "tabs.html"
})
.state('tabs.home', {
url: "/home",
views: {
'home-tab': {
templateUrl: "home.html",
controller: 'HomeTabCtrl'
}
}
})
.state('tabs.detailview', {
url: "/detailview/:index", //NOTE: :index is how you use $stateParams later on.
views: {
'home-tab': {
templateUrl: "detailview.html",
controller: 'DetailviewTabCtrl'
}
}
});
$urlRouterProvider.otherwise("/tab/home");
});
Then, in your controller...
.controller('DetailviewTabCtrl', function($scope,$stateParams) {
$scope.id = parseInt($stateParams.index);//NOTE: This is the same 'index'
$scope.previous = parseInt($stateParams.index) - 1;
$scope.next = parseInt($stateParams.index) + 1;
});
I don't know what {{post.url}} is in the ng-repeat; but I think you need a different $state that should handle the detail View.
Do something like:
<div class="post row" ng-repeat="(postId, post) in posts">
<a ui-sref="postDetail({id:post.id })">{{ post.title }}</a>
</div>
You then need a state definition in your app config's $stateProvider like this:
.state('postDetail', {
url: "/post/:id",
//NOTE: :id will be accessed from the controller using $stateParams later on.
templateUrl: "post_detail.html",
controller: 'PostDetailCtrl'
}) ...
That should do it.
I am trying to do what was essentially answered here Unable to open bootstrap modal window as a route
Yet my solution just will not work. I get an error
Error: [$injector:unpr] Unknown provider: $modalProvider <- $modal
My app has the ui.bootstrap module injected - here is my application config
var app = angular.module('app', ['ui.router', 'ui.bootstrap','ui.bootstrap.tpls', 'app.filters', 'app.services', 'app.directives', 'app.controllers'])
// Gets executed during the provider registrations and configuration phase. Only providers and constants can be
// injected here. This is to prevent accidental instantiation of services before they have been fully configured.
.config(['$stateProvider', '$locationProvider', function ($stateProvider, $locationProvider) {
// UI States, URL Routing & Mapping. For more info see: https://github.com/angular-ui/ui-router
// ------------------------------------------------------------------------------------------------------------
$stateProvider
.state('home', {
url: '/',
templateUrl: '/views/index',
controller: 'HomeCtrl'
})
.state('transactions', {
url: '/transactions',
templateUrl: '/views/transactions',
controller: 'TransactionsCtrl'
})
.state('login', {
url: "/login",
templateUrl: '/views/login',
controller: 'LoginCtrl'
})
.state('otherwise', {
url: '*path',
templateUrl: '/views/404',
controller: 'Error404Ctrl'
});
$locationProvider.html5Mode(true);
}])
I have reduced my controller to the following:
appControllers.controller('LoginCtrl', ['$scope', '$modal', function($scope, $modal) {
$modal.open({templateUrl:'modal.html'});
}]);
Ultimately, what I am hoping to achieve is when login is required not actually GO to the login page, but bring up a dialog.
I have also tried using the onEnter function in the ui-router state method. Couldn't get this working either.
Any ideas?
UPDATE
Ok - so as it turns out, having both ui-bootstrap.js AND ui-bootstrap-tpls breaks this - After reading the docs I thought you needed the templates to work WITH the ui-bootstrap. though it seems all the plunkers only load in the ..tpls file - once I removed the ui-bootstrap file my modal works...Am i blind? or doesn't it not really say which one you need in the docs on github? -
Now i just need to figure out how to prevent my url from actually going to /login, rather than just show the modal :)
update 2
Ok, so by calling $state.go('login') in a service does this for me.
Hi I had a hard time getting through the similar problem.
However, I was able to resolve it.
This is what you would probably need.
app.config(function($stateProvider) {
$stateProvider.state("managerState", {
url: "/ManagerRecord",
controller: "myController",
templateUrl: 'index.html'
})
.state("employeeState", {
url: "empRecords",
parent: "managerState",
params: {
empId: 0
},
onEnter: [
"$modal",
function($modal) {
$modal.open({
controller: "EmpDetailsController",
controllerAs: "empDetails",
templateUrl: 'empDetails.html',
size: 'sm'
}).result.finally(function() {
$stateProvider.go('^');
});
}
]
});
});
Click here for plunker. Hope it helps.
I'm working on something similar and this is my solution.
HTML code
<a ui-sref="home.modal({path: 'login'})" class="btn btn-default" ng-click="openModal()">Login</a>
State configuration
$stateProvider
// assuming we want to open the modal on home page
.state('home', {
url: '/',
templateUrl: '/views/index',
controller: 'HomeCtrl'
})
// create a nested state
.state('home.modal', {
url: ':path/'
});
Home controller
//... other code
$scope.openModal = function(){
$modal.open({
templateUrl: 'path/to/page.html',
resolve: {
newPath: function(){
return 'home'
},
oldPath: function(){
return 'home.modal'
}
},
controller: 'ModalInstanceController'
});
};
//... other code
Finally, the modal instance controller.
This controller synchronizes the modal events (open/close) with URL path changes.
angular.module("app").controller('ModalInstanceController', function($scope, $modalInstance, $state, newPath, oldPath) {
$modalInstance.opened.then(function(){
$state.go(newPath);
});
$modalInstance.result.then(null,function(){
$state.go(oldPath);
});
$scope.$on('$stateChangeSuccess', function () {
if($state.current.name != newPath){
$modalInstance.dismiss('cancel')
}
});
});
You may create a state with the same templateUrl and controller as your page where you want to show the modal, adding params object to it
$stateProvider
.state('root.start-page', {
url: '/',
templateUrl: 'App/src/pages/start-page/start-page.html',
controller: 'StartPageCtrl'
})
.state('root.login', {
url: '/login',
templateUrl: 'App/src/pages/start-page/start-page.html',
controller: 'StartPageCtrl',
params: {
openLoginModal: true
}
})
And in controller of the page, use this parameter to open the modal
.controller("StartPageCtrl", function($scope, $stateParams) {
if ($stateParams.openLoginModal) {
$scope.openLoginModal();
}
I found a handy hint to get this working. There are probably caveats, but it works for me. You can pass a result still but I have no need for one.
Using finally instead of the then promise resolve sorted this for me. I also had to store the previous state on rootScope so we knew what to go back to.
Save previous state to $rootScope
$rootScope.previousState = 'home';
$rootScope.$on('$stateChangeSuccess', function(ev, to, toParams, from, fromParams){
$rootScope.previousState = from.name;
})
State using onEnter
$stateProvider.state('contact', {
url: '/contact',
onEnter: function ($state, $modal, $rootScope){
$modal.open({
templateUrl: 'views/contact.html',
controller: 'ContactCtrl'
}).result.finally(function(){
$state.go($rootScope.previousState);
})
}
});