Angular JS - UI-Router: Reload state on click - angularjs

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

Related

Angular upgrade - How to navigate to a state defined in Angularjs from Angular template?

Currently i am upgrading an Angularjs 1.6 app into Angular 7. As part of this migration i have to navigate to a state defined in Angularjs from Angular template. How can i achieve this?
I have tried angular-hybrid router approach, but it didn't help.
This is the state defined under recipes module in Angularjs
$stateProvider.state('recipes', {
url: '/recipes',
component: 'recipes',
onEnter: ['$state', 'authService', ($state, authService) => {
if(!authService.isLoggedIn()){
$state.go('login')
}
}]
})
And i want to navigate to above state from Angular 7 template as shown below using angular-hybrid-router
<a class="list-group-item"
style="cursor: pointer;"
ui-sref="recipes"
*ngFor="let recipe of recipes; let i = index;">
{{recipe.name}}
</a>
</ul>
Expected is to navigate to /recipes url. But it doesn't and even doesn't thrown any error.
I am unfamiliar with angular-hybrid; though from a cursory glance, it is probable the routing module registering the state was not imported in a module that is chained to the app's root module. uiSref directive can only resolve a registered state, IIRC ui-sref wont give an error if your ui-sref value is 'invalid'(read: unregistered).

Angularjs UI-Router, no state change on hash change

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>

Angularjs $location.url or path do not update the view in ng-view

I am trying to use $location.url or path to update a view in ng-view, but unsuccessfully.
The controller is:
eventsApp.controller('MenuController',
function($scope, $location) {
$scope.createEvent = function(){
$location.url('/newEvent');
};
}
);
The function is simply called in a ngClick event located within the controller:
<li>Create Event</li>
And the routing is:
angular.module('eventsApp', ['ngResource', 'ngRoute'])
.config(function($routeProvider) {
$routeProvider.when('/newEvent',
{
templateUrl:'templates/NewEvent.html',
controller: 'EditEventController'
});
});
Of course, if i use the href of the anchor tag, it works fine; but if I want to do something more complex in the called function, I can't.
I looked in the Network section of the browser tools and I could see that the template has been fetched. But the neither the url in the address bar is updated, or the view is updated (it actually becomes blank).
I am using Apache as a web server, if this thing could be useful in understanding the cause of this issue.
I suspect it is reloading the page due to the href="#". If you need to stick with an anchor tag even though you're not using href, try removing the # like so:
<li>Create Event</li>
However, there could be some fallback if you need to support IE users. If that is the case, you could switch out the anchor tag for a button.
<li>
<button type="button" ng-click="createEvent()">Create Event</button>
</li>

AngularUI Router - scroll to element on state change

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.

Angular - How to Prevent Destroying Scope w/ State Change

Disclaimer I am not looking for a simple parent/child ui-router relationship
I am looking for a solution where I am on one page and I can change to any arbitrary state without removing the contents/listeners of the previous state.
Use Case:
User is on a splash page
clicks on login modal
Url changes from /splash to /login
New modal opens up, the splash page contents in the background do not disappear
The idea is that I wouldn't need to be on any specific child state to have this work.
You can do this with UI-Router Extras "Sticky States".
Here is the UI-Router Extras modal demo: http://christopherthielen.github.io/ui-router-extras/example/stickymodal/#/
Add UI-Router Extras:
<script src="https://rawgit.com/christopherthielen/ui-router-extras/0.0.10/release/ct-ui-router-extras.js"></script>
var app = angular.module('plunker', ['ui.router', 'ct.ui.router.extras', 'ui.bootstrap']);
Add a named ui-view for the app and one for the modal
<body>
<div ui-view="app"></div>
<div ui-view="modal"></div>
</body>
Mark your app state as sticky. The effect is that you can navigate from any app.* state to the modal state... instead of exiting that state, it will only "inactivate" it, and it remains in the DOM.
$stateProvider
.state("app", {
template: "<div ui-view></div>",
sticky: true,
You can't be on many states at once. Modals have their own scope, to which you can pass your own stuff and usually modals are not associated with a state switch.
Reconsider that a modal should require a state switch
Modals have their own scope, destroying which doesn't affect the scope of the place from where they were called in any way.

Resources