Navbar is duplicated automatically while using UI Router - angularjs

I need to have navbar with links for two sub-views: index.file and index.stats but when one of them clicked the new navbar appears inside. How to fix it?
app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider
.state('index', {
url: '',
templateUrl: "../../index.html",
controller: "Controller"
})
.state('index.file', {
templateUrl: "../js/views/file.html"
})
.state('index.stats', {
templateUrl: "../js/views/stats.html"
})
});
index.html
<div class="container">
<nav class="navbar navbar-default">
<ul class="nav navbar-nav">
<li class="active"><a ui-sref="index.file">File</a></li>
<li class="active"><a ui-sref="index.stats">Stats</a></li>
</ul>
</nav>
<div ui-view></div>
</div>

I know your problem is solved, But this may help others.
Generally the duplication in routes occurs when you try to land into the same base html where you include other html pages.
E.g : If my index.html has something like this
<div ng-include="navbar.html"></div>
<div ui-view></div>
In the navbar.html, you try to do the following
<a ui-sref="index">index</a>
$stateprovider.state='index',{
url:'/index', template: 'index.html'});
Then the index.html would be rendered with a duplicate view with a self reference of itself. To solve the problem, avoid including the same template. (Its better to always have home.html/landing.html saperated from index.html)

Related

reload controller when child state is changed - Angular UI Router

I'm new to Angular UI Router and am trying to create an application with nested views.
I've an index.html which hosts the 'header' state and the 'content' state. Within the content state, I have two nav bars representing a Global view and a Sub view. The Global View should open by default when the user opens the application.
However, at present, whenever I run the application, both Global and Sub view controllers are getting executed together(both views are getting loaded together).
What I wish instead is that only Global controller should get executed at first and then when the user clicks on Sub view, its controller should get executed. Following this, whenever the user switches between both the views, the controllers should reload.
I have been reading through Google and here but wasn't able to find the required solution. Please let me know if this is possible using ui-router. Thanks.
index.html
<html>
<body>
<div class="fluid-container">
<div ui-view="header"></div>
<div ui-view="content"></div>
</div>
</body>
</html>
content.html
<div class="row" style="background-color: #F9F9F8">
<div class="col-md-3"></div>
<div class="col-md-6">
<ul class="nav nav-pills nav-justified">
<li class="active"><a data-toggle="pill" href="#globalView">Global</a></li>
<li><a data-toggle="pill" href="#subView">Sub View</a></li>
</ul>
</div>
<div class="col-md-3"></div>
</div>
<div class="row">
<br>
<hr></hr>
<div class="tab-content">
<div id="globalView" class="tab-pane fade in active" ui-view="globalView"></div>
<div id="subAccountView" class="tab-pane fade" ui-view="subView"></div>
</div>
</div>
app.js
$urlRouterProvider.otherwise("/firstPage");
$urlRouterProvider.when('', '/firstPage');
$stateProvider
.state('home', {
url: '',
views: {
/** Find the views named in index.html and inject the named views**/
'header': {
templateUrl: 'views/header.html',
controller: 'headerController',
controllerAs: 'headerCtrl'
},
'content': {
templateUrl: 'views/content.html',
controller: 'contentController',
controllerAs: 'contentCtrl',
}
}
})
.state('home.summary', {
url: '/firstPage',
views: {
'globalView': {
templateUrl: "views/globalViewPage.html",
controller: "globalViewController",
controllerAs: "globalViewCtrl"
},
'subView': {
templateUrl: "views/subView.html",
controller: "subViewController",
controllerAs: "subViewCtrl"
}
}
});
I found the solution to my query by going through the tutorial provided by Weedoze in the comments. Below are the updated files.
index.html remains the same as above.
content.html
<div class="row">
<div class="col-md-3"></div>
<div class="col-md-6">
<ul class="nav nav-pills nav-justified">
<li class="active"><a ui-sref=".globalView">Global</a></li>
<li><a ui-sref=".subView">Sub View</a></li>
</ul>
</div>
<div class="col-md-3"></div>
</div>
<div class="row">
<br>
<hr></hr>
<div class="tab-content">
<div class="tab-pane fade in active" ui-view></div>
</div>
</div>
A point to add here is that I was earlier having data-toggle="pill" in my anchor tag which was causing issues in navigating between the two child views. After digging further, I found that if this toggle is removed, the navigation works smoothly.
app.js
$urlRouterProvider.otherwise("/globalView");
$urlRouterProvider.when('', '/globalView');
$stateProvider
.state('home', {
url: '',
views: {
/** Find the views named in index.html and inject the named views**/
'header': {
templateUrl: 'views/header.html',
controller: 'headerController',
controllerAs: 'headerCtrl'
},
'content': {
templateUrl: 'views/content.html',
controller: 'contentController',
controllerAs: 'contentCtrl',
}
}
})
.state('home.globalView', {
templateUrl: "views/globalViewPage.html",
controller: "globalViewController",
controllerAs: "globalViewCtrl",
url: '/globalView'
})
.state('home.subView', {
templateUrl: "views/subView.html",
controller: "subViewController",
controllerAs: "subViewCtrl",
url: '/subView'
});
This code lets me switch between the two child views and whenever I toggle between the views, the controllers get reloaded.

Can't get ui-views include in templates to include a view

I've studied this: https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views#view-names---relative-vs-absolute-names to exhaustion. I'm trying to get the following working:
...
<div ui-view="mdd"></div>
...
Which will get filled with a partial (or template or whatever you want to call it) which includes a view:
<div class="well" ng-controller="planningCtrl">
<div class="panel panel-default row">
<div class="col-xs-3">
<a class="btn btn-block btn-default btn-lg">
Add a plan
</a>
</div>
<div class="col-xs-9">
<div ui-view="plan"></div>
</div>
</div>
</div>
Debug<br />
<pre>{{state}}</pre>
<pre>{{stateParams}}</pre>
which if rendered statically would be:
...
<div ui-view="mdd">
<div ui-view="plan"></div>
</ui-view>
...
And I can't figure out how to get the ui-router to plug a partial in to the plan view when the planning template is loaded. I get the plan template just fine, but I can't get the initial view into the plan view.
Here's my config for the app:
.config(
[
'$stateProvider'
, '$urlRouterProvider'
, function(
$stateProvider
, $urlRouterProvider)
{
/*
* Make sure that a default path is defined for when no
* state matches.
*/
$urlRouterProvider.otherwise('welcome') ;
/*
* These are states which will get more complicated when I start
* to nest views.
*/
$stateProvider
.state(
'login'
, {
url: '/login'
, views:
{
'mdd': {
templateUrl: "view/login.html"
}
}
})
.state(
'planning'
, {
url: '/planning'
, views:
{
'mdd': {
templateUrl: "view/planning.html"
, controller: 'planningCtrl' // you have to specify the controller here using ui-router.
}
, 'plan#planning':
{
templateURL: 'view/plan/welcome.html'
, controller: 'planningCtrl' // you have to specify the controller here using ui-router.
}
}
})
/* .state(
'planning.welcome'
, {
views:
{
'plan#':
{
templateURL: 'view/plan/welcome.html'
}
}
})*/
.state(
'welcome'
, {
url: '/welcome'
, views:
{
'mdd':
{
templateUrl: "view/welcome.html"
}
}
}) ;
}
]) ;
and I've tried a number of variations on the views and state names with no joy. Any pointers would be appreciated. I'm probably doing something obvious wrong, but if I knew what it was, I wouldn't be asking.
I did some more poking, still puzzled, but maybe this will help somebody figure this out. Here's the HTML that gets generated including a bit of debugging information from the ui-router about what state it's in. This is the partial embedded in the mdd view but failing to have another view (a welcome page) embedded in the plan view:
<!DOCTYPE html>
<html class="ng-scope" ng-app="mdd" lang="en"><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"><style type="text/css">#charset "UTF-8";[ng\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>
<meta charset="UTF-8">
<title>My Divorce Decisions</title>
<link href="My%20Divorce%20Decisions_files/bootstrap.css" rel="stylesheet">
<link href="My%20Divorce%20Decisions_files/bootstrap-theme.css" rel="stylesheet">
<script src="My%20Divorce%20Decisions_files/angular.js"></script>
<script src="My%20Divorce%20Decisions_files/angular-resource.js"></script>
<script src="My%20Divorce%20Decisions_files/angular-ui-router.js"></script>
<script src="My%20Divorce%20Decisions_files/mdd.js"></script>
<script src="My%20Divorce%20Decisions_files/sessionSrvc.js"></script>
<script src="My%20Divorce%20Decisions_files/userSrvc.js"></script>
<script src="My%20Divorce%20Decisions_files/mddCtrl.js"></script>
<script src="My%20Divorce%20Decisions_files/loginCtrl.js"></script>
<script src="My%20Divorce%20Decisions_files/planningCtrl.js"></script>
</head>
<body class="ng-scope" ng-controller="mddCtrl">
<div class="panel panel-default">
<div class="panel-body">My Divorce Decisions</div>
</div>
<div class="navbar navbar-inverse">
<div class="container-fluid">
<ul class="nav navbar-nav">
<li>Home</li>
<li><a class="" href="#/planning" ui-sref="planning" ng-show="isLoggedIn()">Begin Planning</a></li>
<li><a class="ng-hide" href="#/login" ui-sref="login" ng-hide="isLoggedIn()">Sign In</a></li>
<li><a class="ng-scope" ng-click="logout()" ng-show="isLoggedIn()" ng-controller="loginCtrl">Sign Out</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a class="ng-binding" ng-show="isLoggedIn()">esplanner</a></li>
</ul>
</div>
</div>
<!-- uiView: mdd --><div class="ng-scope" ui-view="mdd"><div class="well ng-scope" ng-controller="planningCtrl">
<div class="panel panel-default row">
<div class="col-xs-3">
<a class="btn btn-block btn-default btn-lg">
Add a plan
</a>
</div>
<div class="col-xs-9">
<!-- uiView: plan --><div class="ng-scope" ui-view="plan"></div>
</div>
</div>
</div><span class="ng-scope">
Debug</span><br class="ng-scope">
<pre class="ng-binding ng-scope">{"url":"/planning","views":{"mdd":{"templateUrl":"view/planning.html","controller":"planningCtrl"},"plan#planning":{"templateURL":"view/plan/welcome.html"}},"name":"planning"}</pre>
<pre class="ng-binding ng-scope"></pre>
</div>
<div class="panel panel-default">
<div class="panel-body">
Footer
</div>
</div>
</body></html>
Looking at this: http://plnkr.co/edit/g9wgfMkD6TE3eqhDpkM1?p=info
the state information says this should be working and it isn't.
OK, after another few hours and experimentation, I got this working. One missing piece in my brain was that the index page of the application is the root for displaying views and isn't in the state table. This isn't explicitly discussed in the documentation for ui-router but strongly implied by the example here: http://plnkr.co/edit/7FD5Wf?p=preview
A second piece is that you really have to specify the controller to be used by each view. I discovered by accident that putting ng-controller tags in doesn't seem to work. I don't know if that's a bug or a feature, but it's works this way so I'll continue to do it right or wrong.
The third missing piece was that (for my application and I suspect most) the planning view I use never gets instantiated by itself, so it should have been abstract to get the template displayed and then the child state gets injected into the parent state (as ui-router says it does). Since I don't need parallel views at the moment, I could get rid of the view names in the divs and my state table turned into:
.config(
[
'$stateProvider'
, '$urlRouterProvider'
, function(
$stateProvider
, $urlRouterProvider)
{
/*
* Make sure that a default path is defined for when no
* state matches.
*/
$urlRouterProvider.otherwise('welcome') ;
$stateProvider
.state(
'login'
, {
url: '/login'
, templateUrl: "view/login.html"
, controller: 'loginCtrl'
})
.state(
'planning'
, {
url: '/planning'
, abstract: true
, templateUrl: "view/planning.html"
, controller: 'planningCtrl'
})
.state(
'planning.welcomeToPlan'
, {
url: '/welcome'
, templateUrl: 'view/plan/welcome.html'
, controller: 'planningCtrl'
})
.state(
'welcome'
, {
url: '/welcome'
, templateUrl: "view/welcome.html"
, controller: 'mddCtrl'
}) ;
}
]) ;
and things began to work.
Sorry for the wasted bandwidth and my being thick about this. ui-router is way cool and makes the design of my app a whole lot more intuitive.

AngularJS: how to refresh all visible controllers on page after state change? - Navigation after login

I managed to get it working by using a directive navbar and including it in my index.html, but after login, when I make a state change, my navbar does not get updated. If I refresh the page manually, then it reflects the changes.
Is there a better way to do this? Thanks.
index.html
<navbar></navbar>
<div class="container">
<ui-view></ui-view>
</div>
navbar.html
<ul class="nav navbar-nav navbar-right">
<li><a ui-sref="login" ng-hide="navbar.auth">Login</a></li>
<li>Logout</li>
</ul>
What I ended up doing was not using a directive for the navbar and instead just using multiple views for the same state. This automatically reloads all views on state change.
index.html
<div ui-view="nav"></div>
<div class="container">
<ui-view></ui-view>
</div>
And so the first page after login, gets the navbar as a second view, using the same template and controller as any other main state.
pivot.routes.js
routes.$inject = ['$stateProvider'];
export default function routes($stateProvider) {
$stateProvider
.state('pivot', {
url: '/pivot',
views: {
'': {
template: require('./pivot.html'),
controller: 'PivotController as pivot'
},
'nav': {
template: require('../nav/nav.html'),
controller: 'NavController as navbar'
}
}
});
}
Further reading: https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views

AngularJS & Spring MVC - set templateUrl with $stateProvider

I am developing a web application using angular js & spring-mvc.
In the header of my application
header.jsp
<nav class="navbar navbar-default navbar-fixed-top" >
<div class="container">
<div class="navbar-header" >
<a class="navbar-brand"
href="<c:url value="/home"/>" >Pipeline Tracker
</a >
</div >
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav navbar-right">
<li ui-sref-active="active">
<a ui-sref="empty">PIPELINE</a>
</li>
<li ui-sref-active="active">
<a ui-sref="employees">ADMIN</a>
</li>
</ul>
</div>
</div>
</nav>
app.js
app.config(function($stateProvider, $urlRouterProvider){
$stateProvider
.state('empty', {
url: '/',
view: {
'main':{
templateUrl: 'views/templates/empty.html',
controller: 'EmptyController'
}
}
})
.state('employees',{
url: '/admin/employees',
view: {
'main':{
templateUrl: 'http://localhost:8070/PipelineClient/views/templates/employee.jsp',
controller: 'TestController'
}
}
});
$urlRouterProvider.otherwise('/');
});
I am unable to set the templateUrl property, so my app navigates perfectly. I can see url changing accordingly to '#/' and '#/admin/employees' but nothing is displayed. There is no error in the console also.
I tried to set templateUrl two ways. One with html and another with jsp using context url. None of them working.
I removed routing and checked the data loads pefectly. No issue with data loading.
for loading dependencies:
var app = angular.module('pipeline', [
'ngResource',
'infinite-scroll',
'angularSpinner',
'jcs-autoValidate',
'angular-ladda',
'mgcrea.ngStrap',
'toaster',
'ngAnimate',
'ui.router'
]);
index.jsp
<div class="container main-content">
<div ui-view="main"></div>
</div>
How to set this templateUrl property? I am relatively new to angular, so do let know if you need any more info on this.
I believe it's a syntax error, should be "views" and not "view".
.state('employees',{
url: '/admin/employees',
views: { <--- change view to views
'main':{
templateUrl: 'http://localhost:8070/PipelineClient/views/templates/employee.jsp',
controller: 'TestController'
}
}
});
I'm not familiar with the "view:" syntax you're using. does it work if you do:
.state("test", {
templateUrl: "views/templates/empty.html",
controller: 'EmptyController'
}
http://localhost:8070/#/test

Nested ui-view in angularjs

I am trying to do something here but it does not work, I have the following view:
<header ui-view="header">
</header>
and here is my app.js file:
.state('root', {
url: '',
views: {
'header': {
templateUrl: '/js/app/partials/layout/header.html',
controller: 'HeaderController'
},
'slider': {
templateUrl: '/js/app/partials/slider.html'
},
'container#': {
templateUrl: '/js/app/partials/home.html',
controller: 'HomeController'
},
'sidebar': {
templateUrl: '/js/app/partials/layout/sidebar.html',
controller: 'SideBarController'
},
'footer':{
templateUrl: '/js/app/partials/layout/footer.html'
}
}
})
Now this particular view:
'slider': {
templateUrl: '/js/app/partials/slider.html'
},
is not in my index.html file but rather within my /partial/layout/header.html file. Now the header template is being loaded into the header view, but the slider view does not show.
This is my header.html partial with my slider view inside:
<div class="container-fluid">
<div class="col-md-12">
<a href="#" class="pull-left">
<img src="images/logo.png" alt="Your Happy Family" class="img-responsive">
</a>
<!-- Begin Top Navigation -->
<div class="menu_block">
<nav class="horizontal-nav full-width horizontalNav-notprocessed">
<ul class="sf-menu">
<li class="home"><a ui-sref="root.home">home</a></li>
<li class="tickets">
tickets
<ul>
<li class="bus">Bus</li>
<li class="airline">Local Airline</li>
<li class="events">Events</li>
</ul>
<div class="clear"></div>
</li>
<li class="partners"><a ui-sref="root.partners">partners</a></li>
<li class="contact"><a ui-sref="root.contact">contact us</a></li>
</ul>
</nav>
<div class="clear"></div>
</div>
<!-- End Top Navigation -->
<div class="clear"></div>
<!-- Slider View -->
<div ui-view="slider">
</div>
<div class="clear"></div>
</div>
</div>
I am doing this for a reason, I need my slider view to appear within the header section.
What you usually need is relative pathing for multiple nested views. If you scroll down to the bottom of the docs (https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views) they explain what the syntax of relative pathing does.
This might be what you're looking for but I always get a little tripped up without actually testing the pathing and without a plunker...
'slider#root': {
templateUrl: '/js/app/partials/slider.html'
},

Resources