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

add $locationProvider.baseHref() #2805

Closed

Description

@geddski

Running an Angular app in a subdirectory is painful. All your routes, resources, locations, etc etc have to be manually prefixed with the application context. Example:

$routeProvider.when(root + 'path', {templateUrl: root +'path/file.html', controller: 'SomeCtrl'});

//and

$location.path(root + 'somepath');

//and

return $resource(root + 'some/resource/:id', {id: '@id'});

It's annoying and also error prone if your development env runs in a subdirectory (pretty common).

One current solution is to add a <base href="/myroot/"> tag to the document. This solves the problems from the Angular perspective but causes many issues of its own, especially for third-party libs/widgets that use anchors.

The ideal would be to make $location configurable with a base path, much like Backbone router's root config.

$locationProvider.baseHref = "/myroot/";

$location.path('/awesome'); // goes to /myroot/awesome

$routeProvider.when('/mypath', ...); //matched at /myroot/mypath

$resource('/some/resource'); //maps to /myroot/some/resource

This change would make running Angular in different contexts much easier.

Activity

  1. 0x-r4bbit commented on May 27, 2013

    @0x-r4bbit
    Contributor

    👍 yeap!

  2. oztune commented on May 27, 2013

    @oztune

    Would simplify my life and save us quite a few lines of code. +1

  3. laurelnaiad commented on May 27, 2013

    @laurelnaiad

    👍

  4. lgalfaso commented on May 30, 2013

    @lgalfaso
    Contributor

    You know you can add

    <base href="/myroot/" target="_blank"/>

    to <head> and it will be picked?

  5. laurelnaiad commented on May 30, 2013

    @laurelnaiad

    that reference was in error, please ignore

  6. greglockwood commented on Jun 14, 2013

    @greglockwood

    A workaround I found for this was to redefine the behaviour of the $browser.baseHref() function in the application module's run() function like so:

    // override the $browser.baseHref() method so it returns "/" without needing to use a <base href="/"> element
    // in the head of the document (which causes problems with SVG patterns amongst other things)
    $browser.baseHref = function() { return "/" };
  7. laurelnaiad commented on Jun 14, 2013

    @laurelnaiad

    @greglockwood I like that solution for setting base href asssuming you can get angular loaded with a correct path first ;) I'm hoping to put that to use tomorrow!

    Correct me if I'm wrong -- is this issue about making angular apps that don't need to be tweaked when their actual root path changes? I'm still really looking forward to some sort of solution to being able to deploy apps in subdirectories without modifying their code.

  8. greglockwood commented on Jun 14, 2013

    @greglockwood

    @stu-salsbury I don't believe you are right in saying that this issue is about having Angular apps working in subdirectories without modifying lines of code. This issue is about being able to specify in code what is currently pulled from the <base href="..."> tag in the <head> of the document, as that <base> tag introduces other, unwanted problems. Regardless of those other problems, though, if you want to deploy an Angular app to http://server/directory, you are going to need to change the "base URL", which is a code change either way (either updating the <base> tag in the HTML or, if this feature gets added, in the JS code).

    One way I have come up with in the past to get around an application being able to be deployed in a subdirectory or not and still work is to determine the base URL from the full URL, since you can subtract any known relative path from the whole URL. You could combine that trick with either my workaround above, or if this feature gets added, with the official function call to have this kind of "deploy anywhere" functionality.

    Let me illustrate what I meant above in more concrete terms. Let's say I have all my application routes starting with /app, and I want it to work if deployed at either http://localhost:9000/ or http://sub.domain.com/my/new/angular-app/ or anywhere. What I can do when I start up in my Angular app is examine the current full URL, subtract everything from the last /app onwards, and then subtract the server and port and be left with the correct base URL. Then I could combine that with my workaround above to override the $browser.baseHref() function so it returns that base URL. Then, as far as I know, Angular will correctly prepend that base URL to the URL for all requests and everything should just work. Note: I haven't tested this.

  9. wmertens commented on Jun 25, 2013

    @wmertens

    The html still needs to reference js, images etc with relative paths, and if the base href in the file is incorrect, then those references won't work.

    Making the references be absolute makes putting apps in subdirs broken again.

    So I think this can't be solved with something added to $locationProvider, since Angular starts sometime after the document is loaded.

    Right?

  10. geddski commented on Jun 26, 2013

    @geddski
    ContributorAuthor

    @wmertens correct. For asset paths in HTML files (paths in CSS are ok, they're loaded relative to the CSS file) you'd still need to prefix your paths with the root if you have a variable root.

  11. IgorMinar commented on Jun 27, 2013

    @IgorMinar
    Contributor

    we dove into this yesterday with @geddski and we have a plan to implement ngAppRoot directive which will take in a string that represents url prefix that should be used internally for $location, $http and $route urls.

    with this and some sort of serverside templating (signified by [[ ]] in example below) you'll be able to do this:

    <html ng-app="myApp" ng-app-root="[[ appContext]]">
      <head>
        <script src="[[ appContext ]]/myApp.js"></script>
        <link rel="stylesheet" href="[[ appContext ]]/myApp.css">
      </head>
      <body>
        <a href="[[ appContext ]]/cats">
          <img src="[[ appContext ]]/cats.jpg">
        </a>
      </body>
    </html>
    

    All of your urls in javascript will then remain absolute-root urls (e.g. /cats).

  12. petebacondarwin commented on Jun 28, 2013

    @petebacondarwin
    Contributor

    Would ngAppBase not be more consistent and less confusing given we already have $rootScope and root element concepts?

  13. geddski commented on Jun 28, 2013

    @geddski
    ContributorAuthor

    Thought about base, but don't want to mislead people into thinking it
    behaves like <base href=
    On Jun 28, 2013 7:41 AM, "Pete Bacon Darwin" [email protected]
    wrote:

    Would ngAppBase not be more consistent and less confusing given we
    already have $rootScope and root element concepts?

    —
    Reply to this email directly or view it on GitHubhttps://github.com//issues/2805#issuecomment-20188585
    .

  14. geddski commented on Jul 1, 2013

    @geddski
    ContributorAuthor

    closing in favor of #3102

  15. IgorMinar commented on Jul 1, 2013

    @IgorMinar
    Contributor

    correct. the resolution rules for base[href] and "root" are very different, so we want to make the difference clear.

    for example if base[href]="/foo/bar" and url is "/baz" then the final url is still "/baz". however if root is "/foo/bar" then the final url is "/foo/bar/baz".

  16. agray commented on Nov 25, 2015

    @agray

    ..So is this resolved?

    For those of trying to make sense of this, it would be helpful if someone provided an example of what we are supposed to do. Currently it is clear as mud.

    Thanks in advance

  17. joshribakoff commented on Jan 13, 2016

    @joshribakoff

    The problem I'm having is I need to give the users a "share" button, which should generate a full URL to one of my routes:

    if the app is running in a subdirectory

    https://example.com/my-angular-app-root/index.html#/my/route?foo=bar
    

    or if the app has its own domain

    https://example.com/index.html#/my/route?foo=bar
    

    So to attempt to construct this dynamically, I try this:

    var url = $location.protocol() + '://' + $location.host() + subpath +  '/my/route.html';
    

    The problem is, how do I know if angular is running in a subpath? Where can I get the value for that from? It'd be nice to just be able to do something like

    var url = $location.baseHref() + '#/my/route';
    

    Then I could easily generate URLs for things like "share buttons".

  18. bes1002t commented on Feb 5, 2018

    @bes1002t

    For those who still search for a solution, you can use $window.location.pathname.
    I don't know why '$location.path()' returns not the same as '$window.location.pathName()', but it works for me.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions