49

I use routeProvider to define controlers and templates for my urls.

When I click on the link, which has the same url as is the actual location, nothing happens. I would like the reload() method to be called if a user clicks on such a link even if the location hasn't changed. In other words, if I set the location to the same value, I would like it to behave the same as if I would set it to different value.

Is there a way to configure routeProvider or locationProvider to do it automatically? Or what is the right approach to do this? This is stadard behaviour in round trip applications, but how to do it in angularjs?

I've asked it on google groups as well.

UPDATE:

This question is getting lots of views, so I will try to explain how I solved my problem.

I created a custom directive for linking in my app as Renan Tomal Fernandes suggested in comments.

angular.module('core.directives').directive('diHref', ['$location', '$route',
        function($location, $route) {
    return function(scope, element, attrs) {
        scope.$watch('diHref', function() {
            if(attrs.diHref) {
                element.attr('href', attrs.diHref);
                element.bind('click', function(event) {
                    scope.$apply(function(){
                        if($location.path() == attrs.diHref) $route.reload();
                    });
                });
            }
        });
    }
}]);

The directive is then used for all links in my app I want to have this functionality.

<a di-href="/home/">Home</a>

What this directive does is that it sets the href attribute for you based on di-href attribute so angular can handle it like always and you can see the url when you hover over the link. Furthermore when user clicks on it and the link's path is the same as the current path it reloads the route.

davekr
  • 2,266
  • 1
  • 26
  • 32
  • @public0821's answer is much better than the selected answer – Nachshon Schwartz Apr 10 '14 at 07:34
  • 2
    Please be careful with the code sample posted above because it causes memory leaks. The `$watch()` contains this instruction `element.bind('click', function(event) { ... });` which means that it will create a click event handler for every run of the watcher, without ever releasing the previous click handler. – Kayhadrin May 20 '15 at 03:27

10 Answers10

77

Add a / (slash) to the defined url in the route configuration

I met a similar problem today, I have a link in my web page and when I click it, I want the ng-view reload each time, so that I can refresh data from server. But if the url location doesn't change, angular doesn't reload the ng-view.

Finally, i found a solution to this problem. In my web page, I set the link href to:

  • <a href="#/test">test</a>

But in the route config, I set:

  • $routeProvider.when('/test/', { controller: MyController, templateUrl:'/static/test.html' });

The different is the last slash in url. When I click href="#/test" for the first time, angular redirect the url to #/test/, and load ng-view. when i click it second time, because the current url is #/test/, it's not equal to the url in the link (href="#/test") I clicked, so Angular triggers the location change method and reloads the ng-view, in addition Angular redirects the url to #/test/ again. next time i click the url, angular does the same thing again. Which is exactly what I wanted.

Hope this was useful for you.

Nachshon Schwartz
  • 15,289
  • 20
  • 59
  • 98
public0821
  • 771
  • 1
  • 5
  • 2
65

You can add a _target='_self' on the link to forces the page to reload.

e.g.

<a href="/Customer/Edit/{{customer.id}}" target="_self">{{customer.Name}}</a>

Tested with version 1.0.5 and 1.2.15 on IE and Firefox.

Here's more information from AngularJS site :

Html link rewriting

When you use HTML5 history API mode, you will need different links in different browsers, but all you have to do is specify regular URL links, such as:

<a href="/some?foo=bar">link</a>

When a user clicks on this link,

  • In a legacy browser, the URL changes to /index.html#!/some?foo=bar
  • In a modern browser, the URL changes to /some?foo=bar

In cases like the following, links are not rewritten; instead, the browser will perform a full page reload to the original link.

  • Links that contain target element Example: <a href="/ext/link?a=b" target="_self">link</a>

  • Absolute links that go to a different domain Example: <a href="http://angularjs.org/">link</a>

  • Links starting with '/' that lead to a different base path when base is defined Example: <a href="/not-my-base/link">link</a>

Andy
  • 5,287
  • 2
  • 41
  • 45
  • 1
    Well this will reload the whole page, better would be to just call the `reload()` method e.g. in the directive. – davekr Jul 30 '13 at 11:08
  • 2
    But I don't want the whole page to reload, just the angular routing mechanism. If you reload whole page it's kind of inconsistent with the rest of the app. This is the kind of "better" I had in my mind. – davekr Aug 05 '13 at 17:51
  • 1
    This is actually a pretty nice trick, when you want page to reload on some links... – Szczups Dec 11 '14 at 03:10
  • target="_self" was the perfect solution for me. I had a landing page in my app if certain GET variables were not passed. This landing page allowed you to set them and then load the current page with these GET variables. I had certain server logic based on these GET variables and didn't want to duplicate the logic in Angular. – Craig Mar 30 '16 at 16:43
21

you should use $route.reload() to force the reload.

I don't know if is there a 'automatic' way to do this, but you can use ng-click on these links

Renan Tomal Fernandes
  • 10,978
  • 4
  • 48
  • 31
  • 2
    That's not very generic solution. If I would like to have this behaviour in my whole app, I would have to add ng-click to every link. – davekr Jul 02 '12 at 09:12
  • 5
    maybe you can create a directive for the 'a' tag that verify if the dest url is the same of the link and reload the $route... this is a very generic and good way, I think – Renan Tomal Fernandes Jul 04 '12 at 17:23
8

For people who are using AngularUI Router. You can use something like this:

<a data-ui-sref="some.state" data-ui-sref-opts="{reload: true}">State</a>

Notice the reload option.

Found the answer here: https://stackoverflow.com/a/29384813/426840

Community
  • 1
  • 1
Robin van der Knaap
  • 4,060
  • 2
  • 33
  • 48
6

From @Renan Tomal Fernandes answer. following is an example

HTML

<a href="#/something" my-refresh></a>

JS

angular.module("myModule",[]).
directive('myRefresh',function($location,$route){
    return function(scope, element, attrs) {
        element.bind('click',function(){
            if(element[0] && element[0].href && element[0].href === $location.absUrl()){
                $route.reload();
            }
        });
    }   
});
Community
  • 1
  • 1
Wittaya
  • 111
  • 1
  • 4
  • 3
    Not absolutely sure, but naming this directive as "href" will force all the links to act properly without any changes in markup. – Lisio Nov 06 '13 at 20:41
  • @Lisio - Just tested your suggestion and it works perfect. Very good solution. – Fizzix Apr 13 '16 at 06:10
  • found out this will not work if you are using ui-router instead of the default route module – Muhia NJoroge Aug 16 '16 at 01:18
  • if you are using ui-router, you can replace $route.reload with `$state.transitionTo($state.current, $stateParams, { reload: true, inherit: false, notify: true }); ` – Muhia NJoroge Aug 16 '16 at 01:25
1

I think it's a simpler approach.

.directive ('a', function ($route, $location) {
    var d = {};
    d.restrict = 'E';
    d.link = function (scope, elem, attrs) {

        // has target
        if ('target' in attrs) return;

        // doesn't have href
        if (!('href' in attrs)) return;

        // href is not the current path
        var href = elem [0].href;
        elem.bind ('click', function () {
            if (href !== $location.absUrl ()) return;
            $route.reload ();
        });
    };
    return d;
});

Assuming You want to make all basic <a> links (without target attribute) reload on click and You use relative links in the href attribute (e.g. /home instead of http://example.com/home) You don't have to add any special markup to your HTML (comes handy when updating a site with HTML already written).

Márton Tamás
  • 2,759
  • 1
  • 15
  • 19
0

In my case if the url is same, nothing worked including $route.reload(), $location.path(), $state.transitonTo() etc.

So my approach was Using Dummy Page as follows,

if( oldLocation === newLocation ) {
   // nothing worked ------------
   // window.location.reload(); it refresh the whole page
   // $route.reload();
   // $state.go($state.$current, null, { reload: true });
   // $state.transitionTo($state.current, $stateParams, {reload:true, inherit: false, notify: false } );
   // except this one
   $location.path('/dummy'); 
   $location.path($location.path());
   $scope.$apply(); 
}

You need to make '/dummy' module somewhere, the module doesn't do anything, it only change url so that next $location.path() can be applied. Don't miss $scope.$apply()

Elie Kim
  • 171
  • 1
  • 1
  • 4
0

I ran into this issue a moment ago, except for it was the home page '/'. I wanted a simple solution with less code. I just took advantage of the .otherwise method in the $routProvider

So in the html link looks like:

<a href="#/home">Home</a>

since there is no '/home' page specified in the routProvider it will redirect to '/' via the 'otherwise' method. page with this set up:

.otherwise({
redirectTo: '/'
});

Hope it helps someone

0

I tried Wittaya's solution above using directive approach. Somehow the directive keeps throwing error. I end up with this solution

HTML

<a href="javascript:void(0)" data-ng-click="stateGo('devices')">Devices</a>

Controller

    $scope.stateGo = function (stateName) {
        if ($state.$current.name === stateName) {
            $state.reload();
        } else {
            $state.go(stateName);
        }
    }
Jeson Martajaya
  • 6,996
  • 7
  • 54
  • 56
-3

Just tried adding this

$(window).on('popstate', function(event) {
//refresh server data
});

and it works fine

sib
  • 1