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

add $locationProvider.baseHref() #2805

Closed
geddski opened this issue May 27, 2013 · 18 comments
Closed

add $locationProvider.baseHref() #2805

geddski opened this issue May 27, 2013 · 18 comments

Comments

@geddski
Copy link
Contributor

geddski commented May 27, 2013

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.

@0x-r4bbit
Copy link
Contributor

👍 yeap!

@oztune
Copy link

oztune commented May 27, 2013

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

@laurelnaiad
Copy link

👍

@lgalfaso
Copy link
Contributor

You know you can add

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

to <head> and it will be picked?

@laurelnaiad
Copy link

that reference was in error, please ignore

@greglockwood
Copy link

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 "/" };

@laurelnaiad
Copy link

@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.

@greglockwood
Copy link

@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.

@wmertens
Copy link

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?

@geddski
Copy link
Contributor Author

geddski commented Jun 26, 2013

@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.

@IgorMinar
Copy link
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).

@petebacondarwin
Copy link
Contributor

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

@geddski
Copy link
Contributor Author

geddski commented Jun 28, 2013

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" notifications@github.com
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
.

@geddski
Copy link
Contributor Author

geddski commented Jul 1, 2013

closing in favor of #3102

@IgorMinar
Copy link
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".

@agray
Copy link

agray commented Nov 25, 2015

..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

@joshribakoff
Copy link

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".

@bes1002t
Copy link

bes1002t commented Feb 5, 2018

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 subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests