How can I act on a hashchange event in AngularJs

Ben picture Ben · Nov 12, 2013 · Viewed 7k times · Source

I'm a newbie to AngularJs. What I'm trying to do is update the page on hashchange events.

What I currently do (and know is not the "right" way to go) is:

<!DOCTYPE html>
<html>
<head>
<style>
    #hashdrop {
      display:block;
      border: 1px solid gray;
      width: 500px;
      overflow: auto;
      background-color: rgb(241,241,241);
      border-radius: 4px;
      text-align: center;
      vertical-align: middle;
      line-height: 100px;
      font-size: large;
      height: 100px;
    }
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script>
    var example = function($scope) {
      $scope.lastHash = location.hash.slice(1);
      $(window).on('hashchange', function (event) {
        $scope.lashHash = location.hash.slice(1);
        $scope.$apply();
      });
    };
</script>
<meta charset=utf-8 />
</head>
<body ng-app ng-controller="example">
  <div id="hashdrop" >
    {{lastHash}}
  </div>
</body>
</html>

(This can be copy-pasted into a blank html file and run. jsbin didn't detect the haschange correctly, for me.)

This doesn't really work. for some reason the value is not updated and I would assume there is a 'right' way to this in angularjs.
I would to understand how to do this right and more specifically how to correct the code in this example to work the "angular way".

Thanks!

UPDATE 1 Okay, After reading the comment about $location, I found some information and change my app to this:

<!DOCTYPE html>
<html>
<head>
<style>
    #hashdrop {
      display:block;
      border: 1px solid gray;
      width: 500px;
      overflow: auto;
      background-color: rgb(241,241,241);
      border-radius: 4px;
      text-align: center;
      vertical-align: middle;
      line-height: 100px;
      font-size: large;
      height: 100px;
    }
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script>
    angular.module('example',[]).config(function($locationProvider, $routeProvider) {
      $locationProvider.html5Mode(true);
    });
    var example = function($scope, $location) {


    };
</script>
<meta charset=utf-8 />
</head>
<body ng-app="example" ng-controller="example">
  <div id="hashdrop" >
    Hash = {{$location.hash()}}
  </div>
</body>
</html>

Still doesn't work. Nothing shows in output..

Answer

Erik Honn picture Erik Honn · Nov 12, 2013

AngularJs uses hashes in urls for all normal routing, it's the default way of navigating the page. You use the routeProvider to define url-schemas much like you would in back end MVC frameworks like Django, and the routeProvider will listen for changes in the hash and load new content accordingly.

I suggest doing the tutorial. It is fairly good (even if it misses a lot of stuff). Routes are demonstrated in step 7.

Just warning. Angular assumes that you use hashes as your main way to handle urls and routing, so routeParams will not let you change only part of a page when changing the hash part of the url. To do that you would either switch to using get parameters or use something like ui-router which is more flexible.