13

I'm getting the above error when trying to use html5Mode with ui-router. Can anyone point me to what I'm doing wrong?

TypeError: Cannot read property 'replace' of undefined
    at bd (angular.js:10555)
    at Object.<anonymous> (angular.js:11403)
    at l.$get.l.$digest (angular.js:14222)
    at l.$get.l.$apply (angular.js:14493)
    at angular.js:1449
    at Object.e [as invoke] (angular.js:4182)
    at d (angular.js:1447)
    at sc (angular.js:1467)
    at Jd (angular.js:1361)
    at HTMLDocument.<anonymous> (angular.js:26086)

That segment in angular.js is:

10554 function trimEmptyHash(url) {
10555   return url.replace(/(#.+)|#$/, '$1');
10556 }

The routing file:

(function(){

    'use strict';

    angular
        .module('app')
        .config(routes);

        routes.$inject = ['$stateProvider', '$locationProvider'];

        function routes($stateProvider, $locationProvider) {

            // Configure app states
            $stateProvider

                .state('app', {
                    abstract: true, 
                    templateUrl: 'modules/app/app.html',                
                    controller: 'AppController'
                })

                .state('app.home', {
                    url: '/',
                    templateUrl: 'modules/home/index.html'
                });

            $locationProvider.html5Mode(true);
        }
})();

I've set the base url in the html:

<base href="/app/" />
babbaggeii
  • 7,577
  • 20
  • 64
  • 118
  • http://stackoverflow.com/questions/28859276/locationprovider-html5modetrue-issues and http://stackoverflow.com/questions/21863670/case-insensitivity-with-angularjs-ui-router – Sergiu Paraschiv Mar 25 '15 at 17:08
  • Those solutions don't seem to work. All my URLs are in lower case anyway, so I'm not sure that's applicable. – babbaggeii Mar 25 '15 at 17:14
  • 1
    So `url` is undefined. Look down the stack trace and see who's calling `trimEmptyHash`. Find the code that's supposed to set it and see why it's undefined. – Sergiu Paraschiv Mar 25 '15 at 17:18
  • did you concat and minified your js file? make sure you reprocessing them. @alexkb answer already solve this kind of problem. – Adi Prasetyo Jul 10 '16 at 03:43

5 Answers5

11

I ran into the same issue, and in my case the undefined "url" argument being passed to trimEmptyHash() was ultimately coming from the fact that $$absUrl propery on $location was not getting initialized. Digging in further, it appears that $$absUrl normally gets initialized in the $$compose() method, which typically gets called from $$parse() which typically gets called form the $$parseLinkUrl() method. Here is $$parseLinkUrl() (looking at Angular 1.4.1):

this.$$parseLinkUrl = function(url, relHref) {
  if (relHref && relHref[0] === '#') {
    // special case for links to hash fragments:
    // keep the old url and only replace the hash fragment
    this.hash(relHref.slice(1));
    return true;
  }
  var appUrl, prevAppUrl;
  var rewrittenUrl;

  if ((appUrl = beginsWith(appBase, url)) !== undefined) {
    prevAppUrl = appUrl;
    if ((appUrl = beginsWith(basePrefix, appUrl)) !== undefined) {
      rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
    } else {
      rewrittenUrl = appBase + prevAppUrl;
    }
  } else if ((appUrl = beginsWith(appBaseNoFile, url)) !== undefined) {
    rewrittenUrl = appBaseNoFile + appUrl;
  } else if (appBaseNoFile == url + '/') {
    rewrittenUrl = appBaseNoFile;
  }
  if (rewrittenUrl) {
    this.$$parse(rewrittenUrl);
  }
  return !!rewrittenUrl;
};

In my case, the final "if" clause was not triggering the call to $$parse, because "rewrittenUrl" never got a value, because none of the if/else if clauses in the middle resolved to true. In my case, it was because the url I was using to serve the app (CompanyName/admin.html) was actually above the base Href that I set for the app (CompanyName/admin/), so none of the conditionals resolved to true. As soon as I changed my base Href to just CompanyName/, I no longer ran into this issue.

Alternatively, you could initialize $$absUrl on the location prototype, or wait for some kind of fix from Angular - watch this issue, and see the workaround proposed by joelmdev on March 30th.

Sean
  • 498
  • 1
  • 5
  • 13
  • 2
    I can't believe the Angular team did that. This all but disallows HTML5 mode on sites with anything more than simple routing, for example Rails or ASP.NET sites where the public folder isn't even in the same place as the routing files. – trysis Jul 14 '15 at 20:45
  • Sorry, I was not correct on my last comment. It is possible to use Rails, etc. with Angular's HTML5 mode, but it makes it harder for beginning teams and testing, as they will not have their routes set up and must use the old API. Then again, customers will probably not see these, and hopefully the teams will have their routes set up by the time they do. – trysis Sep 01 '15 at 15:40
6

I was seeing this exact same TypeError: Cannot read property 'replace' of undefined error when using html5mode too, until I changed:

<base href="app/" />

to

<base href="/app/" />

Note, the missed preceding slash. Hope this can help someone.

alexkb
  • 3,216
  • 2
  • 30
  • 30
  • 5
    I double checked this, and mine had the / before as the / after, but what caused my problem, was that it is case sensitive! Make sure its all lowercase, that fixed my problem – Gillardo May 13 '16 at 10:08
0

Your state 'app' have no url key defined.

MrE
  • 19,584
  • 12
  • 87
  • 105
0

What you should do is described here: ui-router on GitHub Once you configure server side routing, everything should work fine as long as you avoid opening you site with url like this: http://localhost/app-base#/

Enethion
  • 1,199
  • 9
  • 9
-5

you have to remove this from html file

<base href="/app/" />

and this from app.js code

$locationProvider.html5Mode(true);