How can I get the ui router in angular to resolve to the correct state?
I'm trying to run an angular application inside a subdirectory of my site but can't get the app.route.js to properly route the request. I set the "otherwise" directive to "dang" so that it's obvious to me if it misses.
I'm trying to reach the application at a URL like:
example.us/search
I'm landing at the proper directory in the url because I get routed to example.us/search/#!/dang
The file location for the content (ie app/partials/search.html) is a subfolder of the search folder, which is inside the root folder.
angular.module('example.usApp')
.config(function($stateProvider, $urlRouterProvider,$locationProvider) {
$urlRouterProvider.otherwise('dang');
$stateProvider
.state('home', {
url: '/',
templateUrl: 'app/partials/search.html',
controller: 'searchController',
resolve: {
deps: ['$ocLazyLoad', function($ocLazyLoad) {
return $ocLazyLoad.load({
insertBefore: '#ng_load_plugins_before',
files: [
'app/services/searchService.js',
'app/controllers/searchController.js',
'css/home.css'
]
});
}]
}
})...
EDIT:
The files[] array above does not get loaded obviously because the url doesn't match. I'm having hard time loading any change because the browser thinks I'm trying to angular route and is not reloading the page at the URL I specify. When I type a change in the url bar and hit enter the URL is rewritten without making a request to the server.
EDIT2:
In answer to a question, yes oclazyload.js is loaded. From the developer tools you can see that all of the following are loaded in this order:
search/
bootstrap.min.css
style.css
angular.min.js
angular-ui-router.min.js
angular-local-storage.min.js
ocLazyLoad.min.js
angular-cookies.min.js
jquery.easing.1.3.js
angular-payments.min.js
app.js
app.constants.js
LoginService.js
app.route.js
bootstrap.min.js
app.constants.js
LoginService.js
app.route.js
bootstrap.min.js
This state is abstract so you will never hit it. I am assuming your main single page is Index.html right? If so change to this:
angular.module('example.usApp')
.config(function($stateProvider, $urlRouterProvider,$locationProvider) {
$urlRouterProvider.otherwise('dang');
$stateProvider
.state('home', {
url: '/search',
templateUrl: 'app/partials/search.html',
controller: 'searchController',
resolve: {
deps: ['$ocLazyLoad', function($ocLazyLoad) {
return $ocLazyLoad.load({
insertBefore: '#ng_load_plugins_before',
files: [
'app/services/HomeService.js',
'app/controllers/HomeMainController.js',
'css/home.css'
]
});
}]
}
})...
The url should be example.us/#/search.
By default jHipster generated entities are accessable for ROLE_USER.
I would like to create entity which can be accessible even for unregistred/unauthorized users.
Let's call the entity: Company
What I've done is removal of ROLE_USER from authorities array in every state in company.js. I can enter the entity (companys) page by going to http://localhost:3000/#/companys (I can see it for a second) but angular automatically redirects to login view (http://localhost:3000/#/login).
I believe the behaviour of this routing is somewhere defined in jHipster however I cannot find it. Any hints for angular newbie? :)
UPDATED
Here is piece of config where I removed authorities:
angular.module('testApp')
.config(function ($stateProvider) {
$stateProvider
.state('company', {
parent: 'entity',
url: '/companys',
data: {
authorities: [], <---- here I removed 'ROLE_USER'
pageTitle: 'testApp.company.home.title'
},
views: {
'content#': {
templateUrl: 'scripts/app/entities/company/companys.html',
controller: 'CompanyController'
}
},
resolve: {
translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) {
$translatePartialLoader.addPart('company');
$translatePartialLoader.addPart('companyType');
$translatePartialLoader.addPart('global');
return $translate.refresh();
}]
}
})
Try this way at the com.company.config.SecurityConfiguration because this will permit all including the unregistered:
.disable()
.and()
.authorizeRequests()
.antMatchers("/company/**").permitAll() // <<<<< ADD THIS
I have made yoman angular fullstack app setup.
I am making use of ui.router in application.
I have defined state parameters as
.state('tour', {
url: '/tour',
templateUrl: 'app/tour/tour.html',
controller: 'tourCtrl',
params : {tourName: null, },
})
I am able to pass parameter to this state within application.
when my application goes to external link.
I want to get back to one of the state of my angular application with some parameter. so how can i do that??
Please Help me to do that .. Thanks
you can pass parameters and maintain states using stateParams, and then maintaining them in the URL. For your understanding, I have added a plunk:
http://plnkr.co/edit/SDOcGS?p=preview
Observe the console whenever you navigate to Route1 tab, and then observe the code:
.state('route1', {
url: "/route1/:place",
params: {
place: null
},
views: {
"viewA": {
template: "route1.viewA"
},
"viewB": {
template: "route1.viewB"
}
},
resolve :{
place: function($stateParams){
console.log($stateParams);
console.log("url", window.location);
return $stateParams.place;
}
}
})
Try this on localhost. It would work the same way on localhost, or any place where its hosted.
I'm making a single page application (SPA). I made a controller called InitialControler to load the data from the server at this url (local.app/init).
I want this url to be opened before any other url. I'm using ui-router, I did a $state.go('init') in the .run() function but it still load the requested page before the 'init' page
First create state called app
$stateProvider.state('app', {
abstract: true,
templateUrl: "assets/partials/container.html",
controller: 'AppCtrl',
resolve: {
init: function(MyFactory) {
return MyFactory.resolver();
}
}
});
Now, any new state you create should be child state of app state. This is also good because it become sort of your root scope. And state will not process unless your factory resolves.
This is how you create your factory
app.factory('MyFactory', function($http){
var items = [];
return {
resolver: function(){
return $http.get('my/api').success(function(data){
items = data;
})
},
get() {
return items;
}
}
});
Now in any other state
$stateProvider.state('app.items', {
url: '/items',
templateUrl: "assets/partials/items.html",
controller: function($scope, MyFactory){
$scope.items = MyFactory.get();
}
});
More on sate resolve
https://github.com/angular-ui/ui-router/wiki#resolve
If you are using ui-router then you could resolve this using nested states. For example:
$stateProvider
.state("main", {
url: "/",
template: '<div ui-view></div>',
controller: 'InitController'
})
.state("main.landing", {
url: "landing",
templateUrl: "modules/home/views/landing.html",
controller: 'LandingPageController'
})
.state("main.profile", {
url: "profile",
templateUrl: "modules/home/views/profile.html",
controller: 'ProfileController'
});
In this example you have defined 3 routes: "/", "/landing", "/profile"
So, InitController (related to "/" route) gets called always, even if the user enters directly at /landing or /profile
Important: Don't forget to include <div ui-view></div> to enable the child states controller load on this section
One way to do is, in config declare only 'init' state. And in InitialController, after data is loaded(resolve function of service call), configure other states. But in this approach, whenever you refresh the page, the url will change to local.app.init.
To stay in that particular state even after reloading, the solution I found is to have a StartUp app in which I loaded the required data and after that I bootstraped the main app manually by angular.bootstrap.
Currently our project is using default $routeProvider, and I am using this "hack", to change url without reloading page:
services.service('$locationEx', ['$location', '$route', '$rootScope', function($location, $route, $rootScope) {
$location.skipReload = function () {
var lastRoute = $route.current;
var un = $rootScope.$on('$locationChangeSuccess', function () {
$route.current = lastRoute;
un();
});
return $location;
};
return $location;
}]);
and in controller
$locationEx.skipReload().path("/category/" + $scope.model.id).replace();
I am thinking of replacing routeProvider with ui-router for nesting routes, but cant find this in ui-router.
Is it possible - do the same with angular-ui-router?
Why do I need this?
Let me explain with an example :
Route for creating new category is /category/new
after clicking on SAVE I show success-alert and I want to change route /category/new to /caterogy/23 (23 - is id of new item stored in db)
Simply you can use $state.transitionTo instead of $state.go . $state.go calls $state.transitionTo internally but automatically sets options to { location: true, inherit: true, relative: $state.$current, notify: true } . You can call $state.transitionTo and set notify: false . For example:
$state.go('.detail', {id: newId})
can be replaced by
$state.transitionTo('.detail', {id: newId}, {
location: true,
inherit: true,
relative: $state.$current,
notify: false
})
Edit: As suggested by fracz it can simply be:
$state.go('.detail', {id: newId}, {notify: false})
Ok, solved :)
Angular UI Router has this new method, $urlRouterProvider.deferIntercept()
https://github.com/angular-ui/ui-router/issues/64
basically it comes down to this:
angular.module('myApp', [ui.router])
.config(['$urlRouterProvider', function ($urlRouterProvider) {
$urlRouterProvider.deferIntercept();
}])
// then define the interception
.run(['$rootScope', '$urlRouter', '$location', '$state', function ($rootScope, $urlRouter, $location, $state) {
$rootScope.$on('$locationChangeSuccess', function(e, newUrl, oldUrl) {
// Prevent $urlRouter's default handler from firing
e.preventDefault();
/**
* provide conditions on when to
* sync change in $location.path() with state reload.
* I use $location and $state as examples, but
* You can do any logic
* before syncing OR stop syncing all together.
*/
if ($state.current.name !== 'main.exampleState' || newUrl === 'http://some.url' || oldUrl !=='https://another.url') {
// your stuff
$urlRouter.sync();
} else {
// don't sync
}
});
// Configures $urlRouter's listener *after* your custom listener
$urlRouter.listen();
}]);
I think this method is currently only included in the master version of angular ui router, the one with optional parameters (which are nice too, btw). It needs to be cloned and built from source with
grunt build
The docs are accessible from the source as well, through
grunt ngdocs
(they get built into the /site directory) // more info in README.MD
There seems to be another way to do this, by dynamic parameters (which I haven't used).
Many credits to nateabele.
As a sidenote, here are optional parameters in Angular UI Router's $stateProvider, which I used in combination with the above:
angular.module('myApp').config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('main.doorsList', {
url: 'doors',
controller: DoorsListCtrl,
resolve: DoorsListCtrl.resolve,
templateUrl: '/modules/doors/doors-list.html'
})
.state('main.doorsSingle', {
url: 'doors/:doorsSingle/:doorsDetail',
params: {
// as of today, it was unclear how to define a required parameter (more below)
doorsSingle: {value: null},
doorsDetail: {value: null}
},
controller: DoorsSingleCtrl,
resolve: DoorsSingleCtrl.resolve,
templateUrl: '/modules/doors/doors-single.html'
});
}]);
what that does is it allows to resolve a state, even if one of the params is missing.
SEO is one purpose, readability another.
In the example above, I wanted doorsSingle to be a required parameter. It is not clear how to define those. It works ok with multiple optional parameters though, so not really a problem. The discussion is here https://github.com/angular-ui/ui-router/pull/1032#issuecomment-49196090
After spending a lot of time with this issue, Here is what I got working
$state.go('stateName',params,{
// prevent the events onStart and onSuccess from firing
notify:false,
// prevent reload of the current state
reload:false,
// replace the last record when changing the params so you don't hit the back button and get old params
location:'replace',
// inherit the current params on the url
inherit:true
});
Calling
$state.go($state.current, {myParam: newValue}, {notify: false});
will still reload the controller, meaning you will lose state data.
To avoid it, simply declare the parameter as dynamic:
$stateProvider.state({
name: 'myState',
url: '/my_state?myParam',
params: {
myParam: {
dynamic: true, // <----------
}
},
...
});
Then you don't even need the notify, just calling
$state.go($state.current, {myParam: newValue})
suffices. Neato!
From the documentation:
When dynamic is true, changes to the parameter value will
not cause the state to be entered/exited. The resolves will not be
re-fetched, nor will views be reloaded.
This can be useful to build
UI where the component updates itself when the param values change.
This setup solved following issues for me:
The training controller is not called twice when updating the url from .../ to .../123
The training controller is not getting invoked again when navigating to another state
State configuration
state('training', {
abstract: true,
url: '/training',
templateUrl: 'partials/training.html',
controller: 'TrainingController'
}).
state('training.edit', {
url: '/:trainingId'
}).
state('training.new', {
url: '/{trainingId}',
// Optional Parameter
params: {
trainingId: null
}
})
Invoking the states (from any other controller)
$scope.editTraining = function (training) {
$state.go('training.edit', { trainingId: training.id });
};
$scope.newTraining = function () {
$state.go('training.new', { });
};
Training Controller
var newTraining;
if (!!!$state.params.trainingId) {
// new
newTraining = // create new training ...
// Update the URL without reloading the controller
$state.go('training.edit',
{
trainingId : newTraining.id
},
{
location: 'replace', // update url and replace
inherit: false,
notify: false
});
} else {
// edit
// load existing training ...
}
If you need only change url but prevent change state:
Change location with (add .replace if you want to replace in history):
this.$location.path([Your path]).replace();
Prevent redirect to your state:
$transitions.onBefore({}, function($transition$) {
if ($transition$.$to().name === '[state name]') {
return false;
}
});
i did this but long ago in version: v0.2.10 of UI-router like something like this::
$stateProvider
.state(
'home', {
url: '/home',
views: {
'': {
templateUrl: Url.resolveTemplateUrl('shared/partial/main.html'),
controller: 'mainCtrl'
},
}
})
.state('home.login', {
url: '/login',
templateUrl: Url.resolveTemplateUrl('authentication/partial/login.html'),
controller: 'authenticationCtrl'
})
.state('home.logout', {
url: '/logout/:state',
controller: 'authenticationCtrl'
})
.state('home.reservationChart', {
url: '/reservations/?vw',
views: {
'': {
templateUrl: Url.resolveTemplateUrl('reservationChart/partial/reservationChartContainer.html'),
controller: 'reservationChartCtrl',
reloadOnSearch: false
},
'viewVoucher#home.reservationChart': {
templateUrl: Url.resolveTemplateUrl('voucher/partial/viewVoucherContainer.html'),
controller: 'viewVoucherCtrl',
reloadOnSearch: false
},
'addEditVoucher#home.reservationChart': {
templateUrl: Url.resolveTemplateUrl('voucher/partial/voucherContainer.html'),
controller: 'voucherCtrl',
reloadOnSearch: false
}
},
reloadOnSearch: false
})
Try something like this
$state.go($state.$current.name, {... $state.params, 'key': newValue}, {notify: false})
In Angular 2, the accepted answer from RezKesh translates to the following:
this.uiRouter.stateService.go(
"home.myRouteState",
{
"param1": this.myParam1,
"param2": this.myParam2
},
{ notify: false }
);
Assuming you have injected UIRouter into your component's constructor as follows:
constructor(
private uiRouter: UIRouter
) { }
I don't think you need ui-router at all for this. The documentation available for the $location service says in the first paragraph, "...changes to $location are reflected into the browser address bar." It continues on later to say, "What does it not do? It does not cause a full page reload when the browser URL is changed."
So, with that in mind, why not simply change the $location.path (as the method is both a getter and setter) with something like the following:
var newPath = IdFromService;
$location.path(newPath);
The documentation notes that the path should always begin with a forward slash, but this will add it if it's missing.