I have a nested state structure in my angular app using ui-router and I have this problem:
My state changes but the URL does not get updated to the child's state URL.
Previously, I had forgotten to include the <div ui-view></div> on the parent view and the URL got updated, but my child controller was not called.
Now that I have included the missing ui-view, the URL does not change, but everything else seems to work great (apart from the back/forward navigation on the browser of course...).
I have tried using { location: true } :
$state.go('parent.child', $stateParams, { location: true });
..but it didn't help.
Any ideas anybody?
Related
We have an accordion on the page which sets hashes for the topics, to allow deep linking. The page runs on UI-Router in HTML5Mode. When clicking on the topics, Ui-Router reloads the resolves.
How can I stop this??
I tried:
reloadOnsearch = false in the state definition, which works great on search params but still reloads on hash change
if( $transition$.$to().name == $transition$.$from().name) {
$transition$.abort() // or return false; // or preventDefault()
}
Which works, but doesn't put the hash into the address, which is obviously needed.
How can I stop UI-Router from reloading the resolves and firing its state change events?
Update with more info:
I tried both,
<a ng-click="toggle();">
with $location.hash("value")
and
<a href="#value">
with preventDefault() in the controller, which (as expected) didn't made a difference.
Solution (hopefully)
This seems to work, in case someone faces the same problem:
$transitions.onBefore({}, function( transition ) {
if(transition.to().name == transition.from().name) {
const paramsCopy = Object.assign({}, transition.params());
const stateService = transition.router.stateService;
return stateService.target(transition.from(), paramsCopy);
}
})
What I understand from your question is you have a accordian with angular Js and the UI router reloads the page when you try to click on the accordian tabs.
Try replacing href attribute from data-target
<li><a data-target="#switchTabs" data-toggle="tab">Tabs</a></li>
I'am using Angular JS with UI-Router,
I want to reload state, when we click on the state link from the same state.
I fixed it with the following code,
<a ui-sref="page1" ui-sref-opts="{reload: true}">Page 1</a>
But it is tedious to add ui-sref-opts="{reload: true}" in all the links.
So I want a configuration or settings or code in angular js( or ui-router) to manage this globally. That is if we click on state link from the same state, the state should get reloaded.
Please help me to find a solution.
The way to go here is to adjust $state.go implementation, e.g. like this:
Changing the default behavior of $state.go() in ui.router to reload by default
In general we will use decorator to get control over $state behaviour
.config(function ($provide) {
$provide.decorator('$state', function ($delegate) {
// let's locally use 'state' name
var state = $delegate;
...
see that in action here
Why that should work is described here:
Difference between ui-sref and $state.go in AngularJS UI-Router
I have a simple form that can be used to initiate a forecast request. I created this as a parent state requests (Initiate Forecast).
Desired behavior
When a request is submitted, that immediate request is shown in a child state (View Status) as most recent request. This View Status state will also hold a grid of all past requests, meaning I will be refreshing the grid with data every time this state is invoked.
Both parent and child states are navigable from a sidebar menu.
So, if a user clicks on parent (Initiate Forecast), he should be able to see only the form to submit a request. If a user directly clicks on the 'View Status'(child), then he should be able to see both the form and the grid of requests.
app.js
function statesCallback($stateProvider) {
$stateProvider
.state('requests', {
url: '',
views: {
'header': {
templateUrl: 'initiateforecasting.html',
controller: 'requestsInitiateController'
},
'content': {
template: '<div ui-view></div>'
}
},
params: {
fcId: null,
fcIndex: null
}
})
.state('requests.viewStatus', {
url: '/ViewStatus',
templateUrl: 'viewstatus.html',
controller: 'requestsStatusController'
});
}
var requestsApp = angular.module('requestsApp', ['ui.router']);
requestsApp.config(['$stateProvider', statesCallback]);
requestsApp.run(['$state', function($state) {
$state.go('requests');
}]);
Plunker of my attempts so far.
This is all working for me as shown in the plunker, but I am doing it by not setting a URL to the parent. Having no URL for the parent state is allowing me to see both states. If I add a URL to parent state, then clicking on View Status link is not going anywhere (it stays on Initiate).
How do I change this so that I can have a URL for parent state and still retain the behaviour I need from the parent and child states as described above?
Note: I am fine without the URL for parent state in standalone sample code, but when I integrate this piece with backend code, having no URL fragment on the parent state is making an unnecessary request to the server. This is visible when I navigate to the child state and then go to the parent state. It effectively gives the impression of reloading the page which I think is unnecessary and can be avoided if a URL can be set to the parent state.
You shall not directly write url when using ui.router, try like this:
<a ui-sref="requests.viewStatus">View Status</a>
You are writing state name in ui-sref directive and it automatically resolves url. It's very comfortable because you can change urls any time and it will not break navigation.
I have searched on StackOverflow for the last five hours and none of the related answers quite solve my problem. I have an UI-Router state that loads a long list of messages generated from a custom directive. This page is linked too in many places pointing to a different message. I want to scroll to the currently selected message.
I can get this to work using $anchorScroll if I surround the call with a $timeout. $timeout(function(){$anchorScroll()};) but if the $timeout is not there a call to $anchorScroll does nothing since the View has not completely loaded.
Here is most of the relevant code.
<message id='message{{message.id}}'
ng-repeat='message in messages'
message='message'
ng-class="{'current':current == 'message{{message.id}}'}" >
</message>
In the controller I set current to $scope.current = $location.hash(). This all works.
If I load the page like #/messages#message100 directly the page will correctly scroll. However, if from a different view I use the a link such as this:
<button ui-sref="message-state({'#':'message{{message.id}}'})>
Go To Message {{message.id}}
</button>
The page will not automatically scroll to the correct anchor since the message list has not been made yet. But by putting the call to $anchorScroll() in a $timeout I can make the page scroll.
I don't like using $timeout for this purpose. I know I am not supposed to manipulate the DOM in a controller like this.
I have tried registering the call to $anchorScroll() with many of the $stateProvider events such as:
$state.$on('$viewContentLoaded', function(event) {
$anchorScroll();
});
But even at the time the $viewContentLoaded fires the message list does not exist in the DOM and the page does not scroll.
IWhat is the best way to make the UI-Router scroll based on the $location.hash().
Even I was facing a similar situation and after days of try and error, I came up with this.
In ui router add an id parameter to the state on which you want to enable the scroll.
$stateProvider.state('index', {
url: '/',
params: {
id: null
}
})
Then in the html use ui-sref
<li><a ui-sref="index({id: 'about-us'})" >About Us</a></li>
At last in the app.run module detect the state change using
$rootScope.$on('$viewContentLoaded', function(event){
if ($state.current.name == 'index') {
if($stateParams.id) {
$anchorScroll.yOffset = 150;
$location.hash($stateParams.id);
$timeout(function(){$anchorScroll()}, 1000);
}
}
});
Hope this helps. Would do a plunkr if needed.
I've been playing with UI-Router since ngRoute doesn't quite cover what I needed based on my different layouts requiring multiple nested views. What I can't figure out in UI-Router is how to load default nested views without having to click a link. I created a crude example of what I'm mean in a plunker
Essentially there are two main route within each there is a container which hosts nested views. I want to load a default view into them without have to click a ui-sref.
<h1>Auth Panel</h1> <-- main route 1
Just a container for login/forgot/reset
<hr/>
<a ui-sref="auth.login">Show Login</a><br> <-- can click to load nested view, but want to autoload
How to show automatically /login within the panel <br>
without having to click show login?
<div ui-view></div> <-- child to autoload with /login
Thanks
On your parent state add a param
.state('parentState', {
//...
params: {
autoActivateChild: 'parentState.childState'
}
//...
})
And add this somewhere
$rootScope.$on('$stateChangeSuccess', function(event, toState){
var aac;
if(aac = toState && toState.params && toState.params.autoActivateChild){
$state.go(aac);
}
});
If you wanted to navigate automatically to a default child state when the parent loads, you could trigger a click on that particular ui-sref in your controller.
angular.element("#childElementId").trigger('click');