Angular UI-Router with named views, nested navbar not rendering - angularjs

Since updating npm to newest version, I have tried to maintain Angular 1.5.1, UI-Router 0.2.18 but it seems that nothing is rendering.
I need a layout where a top ui-view, nav, remains across several pages (eg, states). The page has a path variable containing the name of the state handed to it, which is the .run function attached.
Code (in .coffee)
angular.module('xxx', ['ui.router'])
.config([
'$stateProvider',
'$urlRouterProvider',
'$locationProvider',
'$sceProvider',
($stateProvider, $urlRouterProvider, $locationProvider, $sceProvider) ->
$sceProvider.enabled(false)
$urlRouterProvider.otherwise('/')
query = {
name: 'query',
url: '/query',
views: {
'nav#': {
templateUrl: 'nav/nav.html'
},
'main#query': {
templateUrl: 'query/query.html'
},
'builder#query': {
templateUrl: 'query/query-builder.html'
},
'result#query': {
templateUrl: 'query/query-result.html'
}
}
}
$stateProvider.state(query)
for r in ["a", "b", "c", "d", "e"]
query2 = {
name: r,
url: r,
views: {
'nav': {
templateUrl: 'nav/nav.html'
}
}
}
$stateProvider.state(query2)
])
.run([
'$rootScope',
'$state',
'$window',
'$timeout',
($rootScope, $state, $window, $timeout) ->
path = $window.path
if path
$state.transitionTo(path)
])
And related template files:
<ng-app="xxx">
<!-- Main base.html-->
<div ui-view="nav">
<!-- Specific query page -->
<div ui-view="main">
<!-- Within query page, nested ui-views -->
<div ui-view="builder"></div>
<div ui-view="result"></div>
Any thoughts?

Here is a documentation using nested views.
Here is a doc with the difference of route vs ui-route
As loading views nested to components and application, parent components will not load again in the below example the header. So the nav, remains across several pages.
Hope this is helpful.
function statesetup($stateProvider, $urlRouterProvider, $stateParams) {
console.log('Initiallizing State StartUp...');
$urlRouterProvider.otherwise('/');
$stateProvider
.state('main', {
url: '/',
template:
`
<header></header>
<div ui-view>I am init </div>
`
})
.state('main.a', { url: '/a',template: `<div>hi i am a </div>` })
.state('main.b', { url: '/b',template: `<div>hi i am b </div>` })
}
function run($rootScope, $location, $state) {
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
console.log('RootState Changed...');
var obj = {
event: event,
toState: toState,
toParams: toParams,
fromState: fromState,
fromParams: fromParams
};
return;
});
}
angular.module('xxx', ['ui.router'])
.component('header', {
template : `<ul>
<li ng-click="$ctrl.nav('main.a')">a</li>
<li ng-click="$ctrl.nav('main.b')">b</li>
</ul>`,
controller : function($state) { this.nav = (st) => $state.go(st); }
})
.config(['$stateProvider', '$urlRouterProvider', statesetup])
.run(["$rootScope", "$location", "$state", run])
;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.1/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.18/angular-ui-router.js"></script>
<div ng-app="xxx">
<div ui-view></div>
</div>

Related

Closing Modal Dialog does not return to original html page

I have a very simply Modal Dialog that is displayed from the main header bar.
When I close the modal dialog, it does not go back to the original page. The url displayed in the address bar is the modal that I closed.
How do I go back to the original page that was displayed when I clicked the button.
This is my code:
This is in app.js which is how the Modal, reportSettingModal is displayed.
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'lib/views/login.html',
controller: 'LoginCtrl'
})
.state('home', {
url: '/home',
templateUrl: 'views/home.html',
controller: 'HomeCtrl'
})
.state('renderReport',{
url: '/renderReport/{guid}',
templateUrl: 'views/renderReport.html',
controller: 'RenderReportCtrl'
})
.state('vAnalyze',{
url: '/vAnalyze',
templateUrl: 'views/vAnalyze.html',
controller: 'VAnalyzeCtrl'
})
.state('reportSetting',{
url: '/reportSettingModal',
onEnter: function($modal){
$modal.open({
templateUrl: 'views/reportSettingModal.html',
controller: 'ReportSettingModalCtrl'
});
}
});
This is the HTML:
<div class="modal-header" id="reportSettingModal" style="background-color: #A33441; color: white;">
<h4 class="modal-title">{{title}}</h4>
</div>
<div class="modal-body">
<button type="button" class="btn btn-danger" style="margin-right: 5px; margin-left: 5px;" ng-click="updateWarehouse()">Update Warehouse</button>
</div>
<div class="modal-footer">
<button class="btn btn-sm btn-vow" id="closeButton" ng-click="close()">Close</button>
</div>
This is the controller:
angular.module('vAnalyzeApp.controllers')
.controller('ReportSettingModalCtrl', [
'$scope',
'$uibModal',
'Session',
'$uibModalInstance',
function($scope, $uibModal, session, $uibModalInstance){
$scope.username = session.user;
$scope.title = 'Report Settings';
$scope.close = function() {
$uibModalInstance.close();
};
} //end main function
]);
So, if I am on the VAnalyze page and I open the modal, when I close the modal, i want to be on teh VAnalyze page.
UPDATE
.run(['AuthService', 'configSettings', '$rootScope',
function (AuthService, configSettings, $rootScope) {
// Apply Product Code
configSettings.productCode = 'VANALYZE';
AuthService.configProduct(configSettings.productCode);
},
function ($rootScope) {
$rootScope.$on('$stateChangeSuccess', function(event, to, toParams, from, fromParams) {
$rootScope.$previousState = from;
});
}
]);
UPDATE
I added the state.go function to the modal close function but is still not returning the previous url when the modal was opened. This is my current close function:
$scope.close = function() {
$uibModalInstance.close();
$state.go($rootScope.$previousState.name, {
url: $rootScope.$previousState.url,
templateUrl: $rootScope.$previousState.templateUrl,
controller: $rootScope.$previousState.controller
});
};
Stepping thru the code the url, name templateUrl and controller are all properly set.
Option 1:
Inside your close function, you should specify to which state you want to go. Once the user close the modal.
$scope.close = function() {
$uibModalInstance.close();
$state.go('state-name');
};
Option 2:
If the URL is not relevant, you could call the Modal service from the VAnalyze state Controller, which is VAnalyzeCtrl:
$modal.open({
templateUrl: 'views/reportSettingModal.html',
controller: 'ReportSettingModalCtrl'
});
By doing this, you wont have to Redirect the user to the previous URL.
For going back to the previous state you need to store it so that you can re-route to it on modal close.
You need to add this function in your app.js file same way as you have defined config,
.run(['AuthService', 'configSettings', '$rootScope', function (AuthService, configSettings, $rootScope)
{ // Apply Product Code
configSettings.productCode = 'VANALYZE';
AuthService.configProduct(configSettings.productCode);
$rootScope.$on('$stateChangeSuccess', function(event, to, toParams, from, fromParams) {
$rootScope.$previousState = from;
});
} ]);
Inside your ReportSettingModalCtrl,
angular.module('vAnalyzeApp.controllers')
.controller('ReportSettingModalCtrl', [
'$scope',
'$uibModal',
'Session',
'$uibModalInstance',
'$state',
'$rootScope'
function($scope, $uibModal, session, $uibModalInstance, $state, $rootScope){
$scope.username = session.user;
$scope.title = 'Report Settings';
$scope.close = function() {
$uibModalInstance.close();
$state.go($rootScope.$previousState.name);
};
} //end main function
]);

Using global template variable in controllers angularjs

I am trying to add viewTitle to base view or root web app page, e.g.
Root Page
<div ng-app="app">
{{viewTitle}}
<div ui-view=""></div>
</div>
can I change viewTitle in controllers ?
Controller-1
var myApp = angular.module(app, []);
myApp.controller('ChildController', ['$scope', function($scope) {
// how to update viewTitle here ?
}]);
One solution may be this:
If you use ui-router you can add a title in state: (I use this to translate the title)
.state('login', {
url: '/login',
controller: 'AdminLoginController',
templateUrl: 'app/admin/views/login.html',
title: {
'es': 'Iniciar sesión',
'en': 'Login',
'de': 'Einloggen'
}
})
.state('panelAdmin', {
url: '',
controller: 'AdminHomeController',
templateUrl: 'app/admin/views/panelAdmin.html',
title: {
'es': 'Panel de administración',
'en': 'Control panel',
'de': 'Führungspanel'
}
})
And in $stateChangeStart reload the title:
$rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams) {
if (toState.title) {
$rootScope.title = toState.title[$rootScope.cultureLang];
}
});
In index.html:
<title>{{title}}</title>
I think we can use $rootScope for this purpose. Please see below.
html template
<body ng-app="myApp" >
{{viewTitle}}
<div ui-view=""></div>
</div>
</body>
js file
myApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/',
template: '<h1>From nested view </h1>',
controller: function($rootScope)
{
$rootScope.viewTitle = "home";
}
});
});
Hope it helps

AngularJS: Nested named views from different modules

I'm using angular-ui-router to load nested named views.
In the index.html file I have an unnamed view and a named one.
Index.html:
<div ui-view="header"></div>
<div ui-view=""></div>
I load header.html to named view header. The header view has two named views contactsSearch and countries.
Header.html:
<div ui-view="contactsSearch"></div>
<div ui-view="countries"></div>
In the unnamed view of the index.html file I want to load contacts.html.
Contacts.html:
Contacts List
I use three modules: myApp, countries and contacts. I've configured the routes for each module.
MyApp module:
angular.module('myApp', ['ui.state', 'contacts', 'countries'])
.config(['$stateProvider', '$routeProvider',
function ($stateProvider, $routeProvider) {
$stateProvider
.state("home",
{
url: "/home",
abstract: true,
views: {
'header': {
template: "<div class ='row' ui-view ='countriesList'></div><div class ='row' ui-view ='contactsSearch'></div>"
},
"": {
template: "<div ui-view></div>"
}
}
});
}]);
Countries module:
angular.module('countries', ['ui.state'])
.config(['$stateProvider', '$routeProvider',
function ($stateProvider, $routeProvider) {
$stateProvider
.state("home.countries", {
url: "/countries",
views: {
'countriesList': {
template: "<p>Countries</p>"
}
}
});
}])
.run(['$rootScope', '$state', '$stateParams', function ($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
$state.transitionTo('home.countries');
}]);
Contacts module:
angular.module('contacts', ['ui.state'])
.config(['$stateProvider', '$routeProvider',
function ($stateProvider, $routeProvider) {
$stateProvider
.state("home.contacts", {//should be loaded to the unnamed view in index.html
url: "",
views: {
'contactsList': {
template: "<p>Contacts List</p>"
}
}
})
.state("home.contactsSearch", {
url: "/contactsSearch",
views: {
'contactsSearch': {
template: "<p>Contacts Search</p>"
}
}
});
}])
.run(['$rootScope', '$state', '$stateParams', function ($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
$state.transitionTo('home.contactsSearch');
}]);
My code is not correct because nothing is being displayed and I cannot figure out why. After some investigation, I've found out that a parent can have only one state, but I need home.contacts, home.contactsSearch and home.countries to have the same parent: home.
Can someone please help me with this?
I've created a jsfiddle for more details: https://jsfiddle.net/cjtnmbjw/3/
Thank you

Simple way to display $state data using ui-router

I've seen all the other answers for similar questions but I think this is different.
I have a state defined as such:
.state('2col.flight-log', {
url: 'flight-log',
templateUrl: 'components/2col-pages/flight-log/flight-log.html',
data : { pageTitle: 'Flight Log' }
})
Within flight-log.html I'd like to do something like {{$state.current.data.pageTitle}} or {{$state.data.pageTitle}}. However, this doesn't work. Am I doing something wrong?
I understand the state change issue inherent with this approach but this is fine for now. If I have to create a directive I will, but it really seems like overkill. Should the way I've outlined work?
Here's how I got it working:
app.run([ '$rootScope', '$state', '$stateParams',
function ($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
}])
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
app.state('2col.flight-log', {
url: 'flight-log',
templateUrl: 'components/2col-pages/flight-log/flight-log.html',
data : { pageTitle: 'Flight Log' }
})
and in flight-log.html I put {{$state.current.data.pageTitle}} wherever I needed it.
What's important about this is the app.run block. From the documentation "A run block is the code which needs to run to kickstart the application. It is executed after all of the service have been configured and the injector has been created."
This is how I do it:
Set at $rootScope a ref to $state in app.run
var app = angular.module('app', ['ui.router']);
app.run(['$rootScope', '$state', '$stateParams',
function($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
}
]);
app.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$urlRouterProvider
.otherwise('/');
$stateProvider
.state("home", {
url: "/",
template: 'HELLO WORLD',
data: {
myData: "Working!"
}
});
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
<script src="https://cdn.jsdelivr.net/angular.ui-router/0.2.10/angular-ui-router.js"></script>
<pre ng-app="app" id="uiRouterInfo">
$state = {{$state.current.name}}
$stateParams = {{$stateParams}}
$state full url = {{ $state.$current.url.source }}
$state my data = {{ $state.$current.data.myData }}
</pre>

Angular UI Router Set Scope/Variable

I have an Angular app using the Ui Router for routing purposes. Each time I change the router, I would like to change the header of the page, and it seems like the $stateProvider would be the easiest way to do that. I have something like this for the $stateProvider:
$stateProvider
.state('index', {
url: "/",
views: {
"rightContainer": { templateUrl: "viewA.html" },
},
controller: function ($scope) {
$scope.data.header = "Header 1"
}
})
.state('details', {
url: "/details",
views: {
"rightContainer": { templateUrl: "ViewB.html" },
},
controller: function ($scope) {
$scope.data.header = "Header 2"
}
});
I then want to have the header:
<div data-ng-controller="mainCtrl">
<div class='bg'>{{data.header}}</div>
</div>
You can use data https://github.com/angular-ui/ui-router/wiki#attach-custom-data-to-state-objects
or just an other approach
.run(function ($state,$rootScope$filter,WindowUtils) {
$rootScope.$state = $state;
$rootScope.$on('$stateChangeSuccess', function(event, toState) {
var stateName = toState.name;
//switch
WindowUtils.setTitle(stateName);
});
})
.factory('WindowUtils', function($window) {
return {
setTitle:function(title){
var sep = ' - ';
var current = $window.document.title.split(sep)[0];
$window.document.title = current + sep + title;
}
};
})
The .state object has a data property for exactly what your trying to achieve. Just add data: {header: "Header 1"} to .state like so:
$stateProvider
.state('index', {
url: "/",
views: {
"rightContainer": { templateUrl: "viewA.html" },
},
data: {header: "Header 1"}
})
Edit/Update
To access that data for page titles etc, its best if you use one controller for the index.html <head>, and use $scope.$on to push changes to a $scope.header on route change events. I would recommend having a look at the https://github.com/ngbp/ngbp project boilerplate for a working example.
HTML
https://github.com/ngbp/ngbp/blob/v0.3.2-release/src/index.html
<html ng-app="myApp" ng-controller="AppCtrl">
<head>
<title ng-bind="header"></title>
...
</head>
app.js
https://github.com/ngbp/ngbp/blob/v0.3.2-release/src/app/app.js
.controller( 'AppCtrl', function AppCtrl ( $scope, $location ) {
$scope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){
if ( angular.isDefined( toState.data.header ) ) {
$scope.header = toState.data.header;
}
});

Resources