vaadin / flow

Vaadin Flow is a Java framework binding Vaadin web components to Java. This is part of Vaadin 10+.
Apache License 2.0
618 stars 167 forks source link

<a href="#anchor"> does not link to <a name="anchor> in same page #1215

Open marlonrichert opened 7 years ago

marlonrichert commented 7 years ago

Normally, when I create <a href="#anchor"> in an HTML page, this will cause there to be link pointing to <a name="anchor"> in that same page. So, for example, if you're on https://localhost:8080/my-page, then clicking the link will take you to https://localhost:8080/my-page/#anchor.

However, in ~Hummingbird~ (now known as Flow), when you create <a href="#anchor"> on https://localhost:8080/my-page, clicking the link will take you to the root of the site instead, to https://localhost:8080/#anchor. This is not expected behavior.

Please make it behave like on a normal site.

Legioth commented 7 years ago

This happens because there's a <base href="[site root]"> on the page. It affects how all relative URLs are resolved, including URLs like #anchor.

Which is better?

marlonrichert commented 7 years ago

I just did a quick search in our HTML files for "<base", but I couldn't find it anywhere.

Where does this <base> tag come from and how do I change it?

marlonrichert commented 7 years ago

Also, if I need to write my-page#anchor, but I do not know what page I'm on (because I'm in a dynamically populated template that is used on multiple pages), how do I find out the correct value for my-page?

Legioth commented 7 years ago

The <base> tag is added by the framework, row 336 in BootstrapHandler.java. Removing it would probably break framework internals that are currently implemented based on the assumption that relative URLs are relative to the site root.

Assuming we keep it there in the future as well, it would indeed be good to provide some built-in feature for getting the URL of the current page.

Right not it can be handled manually by populating the template model from the server with UI.getInternal().getActiveViewLocation() or through JS with something like <a [href.attr]="window.location.pathname + '#anchor'">.

Artur- commented 7 years ago

So to clarify, you can either create navigation links as href="my/page" or you can create anchor links using href="#anchor". With the current approach, you do not have to include ../ or / before the page/navigation link but do have to include the page link in anchor hrefs.

Legioth commented 7 years ago

So to clarify

It's not only about navigation links, it also affects anything else that is referenced by URLs, e.g. stylesheets, scripts and HTML imports.

vlukashov commented 7 years ago

Right now #anchor links do not work in Flow-managed pages. I do not think this is acceptable:

Supporting navigation links is a valid use case but there are ways to implement it without introducing the <base> tag (that is, without breaking #anchor links).

Please consider custom URL resolution logic for links with the router-link attribute. They are anyway handled differently (do not trigger a page reload), so they do not have to follow the <base> URL. In this scenario there would be no <base> URL on the page (unless the developer explicitly adds it), #anchor links would keep working as they always have been, and in-app links would work as well since they would implicitly resolve relative to the application root regardless of the current page route.

Legioth commented 7 years ago

Internal navigation links should also work e.g. when opening the link in a new tab, so custom logic in the internal navigation handling wouldn't be enough for that case either. We would instead have to do custom URL resolving for the RouterLink component and require that anyone creating their own custom anchor elements with router-link e.g. from a template would manually resolve any URLs they put there.

<base> is also used for other dependencies, so that you can use e.g. @HtmlImport("foo/bar.html") regardless of from which route the annotated component is used (although it's still recommended to use e.g. frontend://foo/bar.html or context://foo/bar.html that would work in either case)

denis-anisimov commented 7 years ago

I see two main aspects of using <base> in our tests at least:

So the first item introduce an issue when a view should handle all URIs which starts with view URI. E.g. view URI is: http://localhost/path/MyView. In our tests the same view handles any URI like http://localhost/path/MyView/a/b/c/.... For such URIs properly set <base href> allows to handle relative URIs correctly. So e.g. link to webcomponents-loader.js resolves correctly in any case. Without <base href> it doesn't resolve so we cannot proceed at all since we need polyfill.

The second issue is also related to handling different URIs by the same view. If the view URI is: http://localhost/path/MyView and there is router link to http://localhost/path/MyView/x/y which is handled by the same view then this link also presents in this view with the same relative URI. But view now has a different URI ( http://localhost/path/MyView/x/y now , was http://localhost/path/MyView). It means that now (without <base href>) this router-link will be resolved to a different URI than the same router-link in the original view with original URI.

So <base href> allows to use router links with consistent behavior regardless of view URI. Without this one has to care about view URI somehow.

Also worth to mention that in our tests there are many places where HistoryStateChangeHandler is replaced to a custom one. And they works in some unexpected way without having <base href E.g. RouterLinkUI defines a custom HistoryStateChangeHandler which allows to stay on the same view for all relative router links. So there is a relative router link "foo" which resolves to http://localhost/run/foo and there is no any view mapped to this URI (not RouterLinkUI view). Such HistoryStateChangeHandler allows to handle this URI in the same view. But this URI won't work if page is reloaded. So I would say this is incorrect usage.

However the API of HistoryStateChangeHandler should also be taken into account in regard to <base href question: the HistoryStateChangeEvent that it receives will contain some another data than having <base href as now.

samie commented 7 years ago

I feel that mixing Flow navigation in here is overkill. Developers are looking a quick way to let users navigate within the current page/view.

Code like this should work just like it works in browsers (without any Flow navigation/events happening):

Link link = new Link("View feedback","#feedback");
myView.add(link); 
pleku commented 6 years ago

Yes, it should be easy to create inside-page hash-based links from that just work, either in a template or from Java.

No timeline for this enhancement currently though, would require some +1s

gianluca-valentini commented 4 years ago

I follow the issue as it is creating problem to our application

vaadin-miki commented 4 years ago

Following the issue as well, as it renders my current project basically unusable.

bsutton commented 1 year ago

Gentlefolk, I'm current wedged by this bug.

Its marked as Done/Pending Release (as of May 2021) do we known when this is going to be released and/or the details of what the solution was?

I think the issue #822 that I raised relates t this.

Legioth commented 1 year ago

I cannot find anything indicating that any changes were done to address this issue. I wasn't there 1.5 years ago when it was marked as closed, but I would assume that this was unintentional since it was closed by the original reporter rather than a development team member.