Angularjs - one route two possible views - angularjs

I want to be able to use one single route for two different views.
For example right now, I have two routes.
One is /home which is the main page when someone can register/login
And the other one /feed, this is when the user is logged in.
What I want to do is having a single route like twitter for example :
twitter.com/
first they ask you to login
twitter.com/
Than we can see our feed wall. And it's still the same "/". Hope I'm clear :)
This is my code so far:
$stateProvider
.state('index', {
url: '/',
controller: function($state, $auth) {
$auth.validateUser()
.then(function(resp) {
$state.go('feed');
})
.catch(function(resp) {
$state.go('home');
});
}
})
.state('home', {
url: '/home',
templateUrl: 'home.html'
})
.state('feed', {
url: '/feed',
templateUrl: 'feed.html'
})

As far as I remember ui-router doesn't support such feature so you have to do it yourself.
What you can do is to define only a single state as you did in 'index' and instead of performing the $auth logic in the controller do it in a the "resolve" section.
then you can use "ng-if" and "ng-include" to define which .html file and controller you'd like to load, something like this:
app.js
$stateProvider
.state('index', {
url: '/',
resolve: {
isAuthenticated: function() {
return $auth.validateUser().then(function(res) {
return true;
}, function(error) {
return false;
});
}
},
controller: function($scope, isAuthenticated) {
$scope.isAuthenticated = isAuthenticated;
},
templateUrl: 'index.html'
})
index.html
<div ng-if="isAuthenticated">
<div ng-include="'feed.html'"></div>
</div>
<div ng-if="!isAuthenticated">
<div ng-include="'login.html'"></div>
</div>

Related

trying to go from one form to another in angularjs

I am making a project on my own to practice what I've learned about MEAN stack. In the project I want the user to fill in a form and after it is saved in the database the system to take a use to a second form to fill it in etc. I am angularjs for the front end, and within it I am using ui.route. For some reason my program doesn't go to the second program. I already read about other people with the same problem and I can't find what is wrong with my algorithm. Every form works well by itself or when I Make a call from the toolbar.
Frontend.js
angular
.module('authApp',['auth0', 'angular-storage', 'angular-jwt', 'ngMaterial', 'ui.router',
'AdminUser', 'appProfile', 'appToolbar', 'Mod-Company', 'ModShow'])
.config(function($provide, authProvider, $urlRouterProvider, $stateProvider, $httpProvider, jwtInterceptorProvider,$mdThemingProvider){
/* $mdThemingProvider.theme('docs-dark'); */
$mdThemingProvider.theme('default')
.dark();
$mdThemingProvider.alwaysWatchTheme(true);
authProvider.init({
domain: 'workflowjobs.auth0.com',
clientID: 'SjzgRRh3w4ZEFRGLdglpJYvCPCkM189w'
});
jwtInterceptorProvider.tokenGetter = function(store) {
return store.get('id_token');
}
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'components/home/home.html'
})
.state('company', {
url: '/company',
templateUrl: 'components/company/company.html'
})
.state('singlecompany', {
url: '/singlecompany',
templateUrl: 'components/singlecompany/singlecompany.html'
})
.state('show', {
url: '/show',
templateUrl: 'components/show/show-form.html'
})
.state('ticket', {
url: '/ticket',
templateUrl: 'components/ticket/ticket.html'
})
.state('useradmin', {
url: '/useradmin',
templateUrl: 'components/useradmin/useradmin.html'
})
.state('user', {
url: '/user',
templateUrl: 'components/user/user.html'
})
.state('profile', {
url: '/profile',
templateUrl: 'components/profile/profile.html',
controller: 'profileController',
controllerAs: 'user'
});
From the form I use the controller I need, display the form to be filled in by the user and then I call addcompany() after the user click on the button to save the document on the mongodb database.
<section class="table" ng-controller="CompanyCtrl">
<form name="CompanyForm">
...
<input class="form-control" ng-model="company.name" size="40">
...
<p><md-button class="md-raised md-primary md-hue-1" ng-click="addcompany()" aria-label="next">
Now in this code is where I have the problem. the $location.path('/adminuser') doesn't work:
var app = angular.module('Mod-Company', []);
app.controller('CompanyCtrl', ['$scope', '$http',
function($scope,$http){
var refresh = function() {
$http.get('http://localhost:3001/api/company').success(function(response){
$scope.companylist = response;
$scope.company = "";
});
};
refresh();
$scope.addcompany = function(){
$http.post('http://localhost:3001/api/company', $scope.company).success(function(response) {
refresh();
$location.path('/useradmin');
});
$location.path('/useradmin');
};
Instead of using $location.path('/useradmin'); try $state.go('useradmin');.
If it is still not working, it will be easier to help you if you could share your code in a https://jsbin.com or https://plnkr.co

controller undefined in named views

Following works perfect.
In my application file app.js, i have states like
.state('nna.home',
{
url: '/home',
views: {
templateUrl: 'views/home.html'
}
})
//home.html is like
<script src="../controllers/home.js"></script>
<div class="container cf" ng-controller="home">
// my home.js is included correctly in all cases have code like
alert(2); // works
app.controller('home', function ($scope) {
alert(2); // works
});
But as soon as I try to use named views like following. It stops routing
.state('nna.home', {
url: '/home',
views: {
'v1' : {
templateUrl: 'home.html',
controller: 'home',
resolve: {
deps: function ($ocLazyLoad) {
return $ocLazyLoad.load('homecontroller.js');
}
}
},
}
// my home.js is included correctly in all cases have code like
alert(2); // works
app.controller('home', function ($scope) {
alert(2); // Does not work
});
Plunker
I can use them fine as long as i load all controller files in index but i want to load controllers only with views not all the way in index
Probably the issue is with my understanding about named views, but i am stuck to know the reason that why the home is undefined even when i can show with alert that file had been successfully added
Try this:
.state('nna.home',
{
url: '/home',
views: {
'v1': {
templateUrl: 'views/home.html',
controller: 'home'
}
}
})
There is a working plunker
These could be the states:
.state('nna', {
template: '<div ui-view="v1"></div>',
})
.state('nna.home', {
url: '/home',
views: {
'v1' : {
templateUrl: 'views/home.html',
controller: 'home',
},
}
});
And these links are working now:
<a href="#/home">
<a ui-sref="nna.home">
Check it in action here

StateParams are empty on page refresh using the ui-router

I use angular's ui-router and nested routes in a project and I'm faced by the problem that everything works like a charm when I use links (ui-sref) to navigate to the user's detail page with the userId as part of the url. When I refresh the page, state params are missing.
So I've taken a look at the angular demo: http://angular-ui.github.io/ui-router/sample/#/contacts/1/item/b and couldn't reproduce this behaviour, however nested states are not part of this demo in contrast to my application.
$stateProvider
.state('base', {
abstract: true
})
.state('home', {
parent: 'base',
url: '/',
views: {
'content#': {
templateUrl: 'app/index/index.view.html',
controller: 'IndexController',
controllerAs: 'home'
}
}
})
.state('users', {
url: '/users',
parent: 'base',
abstract: true
})
.state('users.list', {
url: '/list',
views: {
'content#': {
templateUrl: 'app/users/users.list.html',
controller: 'UsersController',
controllerAs: 'users'
}
},
permissions: {
authorizedRoles: UserRoles.ALL_ROLES
}
})
.state('users.details', {
url: '/:userId/details',
views: {
'content#': {
templateUrl: 'app/users/user.details.html',
controller: 'UserDetailsController',
controllerAs: 'userDetails'
}
},
resolve: {
logSomeParams: ['$stateParams', '$state', function ($stateParams, $state) {
console.log($stateParams);
console.log(this);
console.log($state);
}]
}
})
When refreshing the page the url immediately changes to http://localhost:3000/#/users//details and console output (resolve function) shows that params are missing.
html5Mode (LocationProvider) is not enabled. I already found "solutions" like redirecting back to the list if the the userId is missing on page refresh, but I just can't believe that there isn't a better way to solve this.
This is how I linked the details page in the overview (and it is working):
<div class="panel-body" ui-sref="users.details({userId: user.siloUserId})">
As expected, my problem had nothing to do with the ui-router. The URLMatcher works as expected, even if you refresh the page (everything else would have been a huge dissapointment).
However, I have a $stateChangeStart listener which checks if the SAML authentication session (cookie) is still valid and waits for the result.
function(event, toState, toParams, fromState, fromParams){
if(!authenticationService.isInitialized()) {
event.preventDefault();
authenticationService.getDeferred().then(() => {
$state.go(toState);
});
} else {
//check authorization
if ( authenticationService.protectedState(toState) && !authenticationService.isAuthorized(toState.permissions.authorizedRoles)) {
authenticationService.denyAccess();
event.preventDefault();
}
}
}
No idea how this could happen, but I forgot to pass the parameters to the go method of the stateProvider. So all I had to change was to add the params:
$state.go(toState, toParams);

How to hide content in the parent view when the user goes to a nested state and show it again when the user backs to the parent one?

I use ui-router and have two nested views.
I’d like to hide some html-content in the parent view when the user goes to child state and show it again when the user backs to parent one.
Could anybody give an advice how to achieve that?
It’s easy to do that using root scope and state change events but it looks like a dirty way, doesn’t it?
app.js
'use strict';
var myApp = angular.module('myApp', ['ui.router']);
myApp.controller('ParentCtrl', function ($scope) {
$scope.hideIt = false;
});
myApp.controller('ChildCtrl', function ( $scope) {
$scope.$parent.hideIt = true;
});
myApp.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('parent', {
url: '/parent',
templateUrl: 'parent.html',
controller: 'ParentCtrl'
})
.state('parent.child', {
url: '/child',
template: '<h2>Child view</h2>',
controller: 'ChildCtrl'
});
});
parent.html
<h2>Parent view</h2>
<div ng-hide="hideIt">
<p>This text should be hidden when the user goes to the nested state.</p>
</div>
<a ui-sref="parent.child">Go to the nested view</a>
<div ui-view></div>
One simple solution is to fill ui-view tag in the parent template with the content that you want gone when child state is loaded.
<ui-view>
<h2>Parent view</h2>
<div ng-hide="hideIt">
<p>This text should be hidden when the user goes to the nested state.</p>
<a ui-sref="parent.child">Go to the nested view</a>
</ui-view>
You should check out named views for this. That would probably be the best way to go. https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views
Also, there's another thread that answered this question over here: https://stackoverflow.com/a/19050828/1078450
Here's the working code for nested named views, taken from that thread:
angular.module('myApp', ['ui.state'])
.config(['$stateProvider', '$routeProvider',
function($stateProvider, $routeProvider) {
$stateProvider
.state('test', {
abstract: true,
url: '/test',
views: {
'main': {
template: '<h1>Hello!!!</h1>' +
'<div ui-view="view1"></div>' +
'<div ui-view="view2"></div>'
}
}
})
.state('test.subs', {
url: '',
views: {
'view1#test': {
template: "Im View1"
},
'view2#test': {
template: "Im View2"
}
}
});
}
])
.run(['$state', function($state) {
$state.transitionTo('test.subs');
}]);
http://jsfiddle.net/thardy/eD3MU/
Edit:
Adding some thoughts re the angular-breadcrumbs comment. I haven't used it myself, but at first glance it seems like subroutes shouldn't break the breadcrumbs. I'm just looking at the source code of their demo, around line 62. I'd have to spin it all up to really go about testing it, but it looks like they're doing almost the same thing with specifying views, and it works there: https://github.com/ncuillery/angular-breadcrumb/blob/master/sample/app.js#L62
.state('room', {
url: '/room',
templateUrl: 'views/room_list.html',
controller: 'RoomListCtrl',
ncyBreadcrumb: {
label: 'Rooms',
parent: 'sample'
}
})
.state('room.new', {
url: '/new',
views: {
"#" : {
templateUrl: 'views/room_form.html',
controller: 'RoomDetailCtrl'
}
},
ncyBreadcrumb: {
label: 'New room'
}
})
.state('room.detail', {
url: '/{roomId}?from',
views: {
"#" : {
templateUrl: 'views/room_detail.html',
controller: 'RoomDetailCtrl'
}
},
ncyBreadcrumb: {
label: 'Room {{room.roomNumber}}',
parent: function ($scope) {
return $scope.from || 'room';
}
}
})
Edit2:
This solution will not combine routes into one crumb
See the official demo
re: But I use angular-breadcrumb and in your solution they will be combined into one crum.

How To Autoload ui-view on nested views?

I have code like this
<a ui-sref="nested.something">something</a>
<div ui-view="nested.something"></div>
how to load ui-view without click ui-sref ?
EXTEND - related to this plunker provided by OP in the comments above
The state definition is:
.state('store', {
views: {
'store': {
templateUrl: 'store.html'
}
}
})
.state('store.detail', {
views: {
'store_detail': {
templateUrl: 'store_detail.html'
}
}
})
Then in this updated plunker we can see that this would do the job
//$urlRouterProvider.otherwise('/store');
$urlRouterProvider.otherwise(function($injector, $location){
var state = $injector.get('$state');
state.go('store.detail');
return $location.path();
});
Reason? states do not have defined url. Which is a bit weird. So, I would honestly rather suggested to do it like this (the link to such plunker):
$urlRouterProvider.otherwise('/store/detail');
//$urlRouterProvider.otherwise(function($injector, $location){
// var state = $injector.get('$state');
// state.go('store.detail');
// return $location.path();
//});
$stateProvider
.state('store', {
url: '/store',
views: {
'store': {
templateUrl: 'store.html'
}
}
})
.state('store.detail', {
url: '/detail',
views: {
'store_detail': {
templateUrl: 'store_detail.html'
}
}
})
There is a working plunker
ORIGINAL
We can use the .otherwise(rule) of $urlRouterProvider, documented here
$urlRouterProvider.otherwise('/parent/child');
As the doc says:
otherwise(rule)
Defines a path that is used when an invalid route is requested.
So, this could be used for some default - start up "redirection"
The .otherwise() could be even a function, like shown here:
How not to change url when show 404 error page with ui-router
which takes '$injector', '$location' and can do even much more magic (on invalid or startup path)
$urlRouterProvider.otherwise(function($injector, $location){
var state = $injector.get('$state');
state.go('404');
return $location.path();
});
ALSO, if we want to fill in some more details into some nested viesw, we can do it by defining multi-named views:
.state('parent.child', {
url: "/child",
views: {
'' : {
templateUrl: 'tpl.child.html',
controller: 'ChildCtrl',
},
'nested.something#parent.child' : {
templateUrl: 'tpl.something.html',
},
}
})
So, if the tpl.child.html will have this anchor/target:
<i>place for nested something:</i>
<div ui-view="nested.something"></div>
it will be filled with the tpl.something.html content
Check it in action here

Resources