Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

IE9 error with ng-click and no href #7721

Closed
zachsnow opened this issue Jun 6, 2014 · 8 comments
Closed

IE9 error with ng-click and no href #7721

zachsnow opened this issue Jun 6, 2014 · 8 comments

Comments

@zachsnow
Copy link
Contributor

zachsnow commented Jun 6, 2014

In IE9, with hashbang mode enabled, and having injected the $location service (not just configured the provider), an anchor with an ng-click but no href causes an exception when clicked:

Unable to get the value of the property 'indexOf': object is null or undefined

To reproduce, put this in a file named ie9 and run python -m SimpleHTTPServer 5000, then visit http://localhost:5000/ie9/.

<!DOCTYPE html>
<html ng-app="app">

  <head>
    <base href="/ie9/" />
    <script src="https://code.angularjs.org/1.3.0-beta.10/angular.js"></script>
  </head>

  <script>
    var app = angular.module('app', []);

    app.config([
      '$locationProvider',
      function($locationProvider){
        $locationProvider.html5Mode(true);
        $locationProvider.hashPrefix('!');
      }
    ]);

    app.controller('ctrl', [
      '$scope',
      '$location', // Note that we inject $location here!
      function($scope, $location){
        $scope.alert = function(s){ window.alert(s); };
      }
    ]);
  </script>

  <body ng-controller="ctrl">
    <a ng-click="alert('hi!')">
      <span>Click me!</span>
    </a>
  </body>

</html>

Note that you must inject $location to see the issue; the offending line is in $location and is only run when the service is instantiated.

There are several ways to "solve" the problem, but I'm not sure which is best. It seems that the implementation of the a (anchor) directive could stopPropagation as well as preventing default, or we could simply check for empty/undefined href attributes at that point in $location.

@zachsnow
Copy link
Contributor Author

I ended up checking that href is a string at the relevant point in $location and it "worked", but as I don't quite understand the goal of the code I'm hesitant to submit the change. Can anyone chime in?

@btford
Copy link
Contributor

btford commented Jul 22, 2014

Would you mind putting the example into a plnkr.co or jsfiddle and check that this is still an issue on 1.2.20?

@btford btford added this to the Backlog milestone Jul 22, 2014
@zachsnow
Copy link
Contributor Author

Sure thing.

@zachsnow
Copy link
Contributor Author

Apparently plnkr.co doesn't support IE9, and I couldn't get JSFiddle to do what I wanted; apologies. I tried 1.2.20 and 1.3.0-beta.16, both showed the issue. Updated example to not need to muck around with <base>; simply put this in index.html, serve the directory however you like, and visit localhost.

<!DOCTYPE html>
<html ng-app="app">
  <head>
    <script src="https://code.angularjs.org/1.2.20/angular.js"></script>
  </head>

  <script>
    var app = angular.module('app', []);

    app.config([
      '$locationProvider',
      function($locationProvider){
        $locationProvider.html5Mode(true);
        $locationProvider.hashPrefix('!');
      }
    ]);

    app.controller('ctrl', [
      '$scope',
      '$location', // Note that we inject $location here! Removing this hides the issue.
      function($scope, $location){
        $scope.alert = function(s){ window.alert(s); };
      }
    ]);
  </script>

  <body ng-controller="ctrl">
    <a ng-click="alert('hi!')">
      <span>Click me!</span>
    </a>
  </body>
</html>

@vandycknick
Copy link
Contributor

Maybe I can provide a little more info, just tested this IE8, IE9, they both have this problem.

Angular is trying here to make relative links work in HTML5 mode for legacy browsers and is flipping over the following lines of code:

      // Make relative links work in HTML5 mode for legacy browsers (or at least IE8 & 9)
      // The href should be a regular url e.g. /link/somewhere or link/somewhere or ../somewhere or
      // somewhere#anchor or http://example.com/somewhere
      if (LocationMode === LocationHashbangInHtml5Url) {
        // get the actual href attribute - see
        // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
        var href = elm.attr('href') || elm.attr('xlink:href');

        if (href.indexOf('://') < 0) {         // Ignore absolute URLs
          var prefix = '#' + hashPrefix;

This is in the $location#$locationChangeSuccess (somewhere around line 9751)
So when it's trying to get the "href" of the element it's returning undefined and combined with indexOf this raises the error.

I think the preferred way here is to use $event.preventDefault or stopPropagation because you don't want the URL to change and don't want the $locationChangeStart, $locationChangeSuccess events to fire.

Maybe this helps to get more insight.

@vandycknick
Copy link
Contributor

Or maybe angular should give you a better warning when trying this entanglement.

@jsanders
Copy link

I'm running into this too. Adding $event.stopPropagation() at the end of every ng-click handler solves it, but it's pretty tedious. I'd love to see a better fix.

@allenmoatallen
Copy link

I add jsanders's workaround which cleared the issue in Chrome and IE10 for me.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.