Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using $location.hash() #510

Closed
acroca opened this issue Oct 17, 2013 · 37 comments
Closed

Using $location.hash() #510

acroca opened this issue Oct 17, 2013 · 37 comments

Comments

@acroca
Copy link
Contributor

acroca commented Oct 17, 2013

Hi everyone,

First of all, thanks for this great project!

Is there any way of sending $location.hash() to a state?

I've checked the code and the default options.location when going to a new state is true, so it rewrites the location getting rid of the hash. Also I tried to create a state with a url like /:id#:section but didn't work.

In case this is still not supported what do you think it's the best approach to define a state with hashes in the url?

Thanks

@nateabele
Copy link
Contributor

This is a good question. I've just tested UrlMatcher, and it has no problem with generating URLs containing hashes. Maybe try doing it by calling $location.url() directly and seeing if that works?

@acroca
Copy link
Contributor Author

acroca commented Oct 18, 2013

I tried a url with a hash, something like this:

state("a", {url: "/posts/:id})
.state("a.b", {url: "#:section"})

seems to generate the right url when I do a ui-sref="a.b({id: 1, section: 'something'}), but when I go to the a.b state it redirects back to the state a.
The redirect happens on the following code:

        // Update $location
        var toNav = to.navigable;
        if (options.location && toNav) {
          $location.url(toNav.url.format(toNav.locals.globals.$stateParams));
        }

For now I'm using query string but would like to use the location hash instead.

@blambeau
Copy link

👍 for supporting hash.

I've tried calling $location.url("/foo/bar#my-section") directly but it does not work. The location seems to be immediately overridden by the router and ends-up being "/foo/bar" without hash.

@nateabele
Copy link
Contributor

@acroca Do you have HTML5 mode enabled or no?

@blambeau
Copy link

HTML5 mode enabled for me.

@nateabele I've had a look at the code. It amounts at making UrlMatcher() and UrlMatcher.prototype.format compatible with hash tags, isn't? I'm not used to ui-router's code, but I can try something if it helps.

@acroca
Copy link
Contributor Author

acroca commented Oct 24, 2013

I tried with and without HTML5, no difference.


Albert Callarisa Roca

Sent from my iPhone

On 24 Oct, 2013, at 12:05 am, Bernard Lambeau notifications@github.com wrote:

HTML5 mode enabled for me.

@nateabele I've had a look at the code. It amounts at making UrlMatcher() and UrlMatcher.prototype.format compatible with hash tags, isn't? I'm not used to ui-router's code, but I can try something if it helps.


Reply to this email directly or view it on GitHub.

@nateabele
Copy link
Contributor

@blambeau Nope. See above.

@acroca
Copy link
Contributor Author

acroca commented Oct 24, 2013

@nateabele the generated url is right, the problem is when accessing the url, the location gets replaced to the url without the hash.

@blambeau
Copy link

@nateabele I see. I tried /users/:id?query#fragment and /users/:id?query#:fragment. Do not seem supported so far.

@blambeau
Copy link

blambeau commented Nov 4, 2013

@nateabele I think I've got a kind of "root cause" for this. At https://github.com/angular-ui/ui-router/blob/0.2.0/src/urlRouter.js#L60, when a rule is checked against the current location, the hashtag is stripped in the process.

I've tried hardcoding path = path + '#' + $location.hash() there and it works actually fine. However, some refactoring all seems necessary over the place to support the feature in a sound way. WDYT?

@shaunrader
Copy link

I think I'm going about it wrong but these changes seemed to work for my use case: shaunrader/ui-router@master...location_hash. It does not work with query parameters AND a hash fragment at the same time though.

These types of url matching seem to work:
/users/:id#:hash
/users/:id#key=:value&key2=:value2

I'm thinking some changes will need to be made here to allow it to work with query parameters.

Also if I have equals signs in my hash when not explicitly matching the key/values (like /users/3#key=value with a url of /users/:id#:hash) there's an infinite loop unless I remove the encodeURIComponent here.

+1 for official $location.hash() support!

@beyang
Copy link
Contributor

beyang commented Nov 27, 2013

The above pull request will make it so the hash fragment is preserved on new page loads (won't get erased).

It doesn't go as far as having the hash value be part of the state params. Not sure what the right relationship between the URL hash and state should be – maybe it's better to have the hash not be part of the state, since the traditional usage is just to indicate a position on a page, and not change the overall content, but I could see arguments both ways.

Anyway, the change above would at least preserve the hash on page loads/reloads so it can be accessed elsewhere (e.g., by $anchorScroll).

Thoughts?

@rutger-dijkstra
Copy link

I second beyang's pull request.

I definitely would not want my scope to be torn down upon change of fragment, so I'd want to keep it out of the state params.

It would, however, be incomplete without the ability to specify the fragment on $state.go and in a ui-sref.

@nateabele
Copy link
Contributor

I definitely would not want my scope to be torn down upon change of fragment, so I'd want to keep it out of the state params.

@rutger-dijkstra A recent PR introduced dynamic parameters via reloadOnSearch, so changes no longer mean a reload.

@timkindberg
Copy link
Contributor

@nateabele am I right in the following assumptions?

  • Devs could use reloadOnSearch: false when they wanted to use hashes that didn't trigger a state reload.
  • If they did want to trigger a reload on hash change then they could put the hash into the state url (assuming we implement the feature proposed in this thread).

Man, I rewrote this post like 5 times... trying to ask two pointed questions and I think I finally did it.

@nateabele
Copy link
Contributor

@timkindberg Theoretically, yes. In practice I have no idea. Never tried.

@nateabele
Copy link
Contributor

@timkindberg Also, to be clear, reloadOnSearch is per-parameter, not per-URL.

@timkindberg
Copy link
Contributor

I'm not sure what that means or if that is accurate...

@rutger-dijkstra
Copy link

It is not. reloadOnSearch is boolean property of a state definition. Setting it to false will suppress a state transition for any change of state parameters, not just those in the $location.search(), as the name suggests. The use cases for that strike me as rare.

@nateabele
Copy link
Contributor

Okay, then I have no idea what I'm talking about. Yet another reason to implement typed parameters. Anybody wanna help me start a Kickstarter for it? 😄

@timkindberg
Copy link
Contributor

@nateabele was wrong....???? world asplodes

@rutger-dijkstra use cases for using reloadOnSearch in general, or for using it with params other than search params?

@timkindberg
Copy link
Contributor

@nateabele if you ever want to pair program over some beers let me know!

@nateabele
Copy link
Contributor

@timkindberg Haha, well, I honestly didn't look too closely at the patch that implemented it, beyond reviewing it to make sure the code was sane and the tests looked reasonable.

@rutger-dijkstra
Copy link

@timkindberg use cases for the option to suppress reload on any change of state parameter. It means there is no place to put the parameters that should trigger a reload because they identify the resource/page you're on. I'd vote for:
reload on change of a path parameter: always
reload on change of a search parameter: governed by reloadOnChange
reload on change of hash: never

@timkindberg
Copy link
Contributor

I'd vote for:
reload on change of a path parameter: always
reload on change of a search parameter: governed by reloadOnChange
reload on change of hash: never

I concur.

@gigablox
Copy link

gigablox commented Jan 3, 2014

I've run into a use case where I need to update the location path parameters without reloading the view.

A detailed explanation can be found here:
#562 (comment)

@timkindberg
Copy link
Contributor

@gigablox that's not possible unfortunately, at least not without manual modification of the ui-router code. Perhaps that will make it in with typed params when they land (which won't be soon).

@gigablox
Copy link

gigablox commented Jan 4, 2014

@timkindberg Thanks for taking a look, I moved that question into #562 (comment) because I felt like there might be a sliver of hope haha!

Can you reference an issue for typed params so I can stay on top of it?

@timkindberg
Copy link
Contributor

@gigablox also check out this comment, it may get you really close to what you are trying to do. Its just not officially supported territory. You'd be stepping out on your own. #125 (comment)

@timkindberg
Copy link
Contributor

@gigablox and here is typed params WIP: #454

@akarelas
Copy link

akarelas commented Jun 6, 2014

👍 Please do it!..

@mrn-aglic
Copy link

states still don't support having hashes in the url?

@rmunch
Copy link

rmunch commented Dec 13, 2014

I have a use case where I do need the URL hash/fragment portion to trigger a state when the hash changes. I'd like to launch a modal when a certain hash is present in the URL. This lightbox has no server-side equivalent (on purpose), but I need to set it up so that if a user returns to the URL with the hash, the lightbox will launch again.

I wonder if there should be a new config similar to reloadOnSearch for the hash (reloadOnHash) that defaults to false (so as not to interfere with existing anchor links), but would support this use case when needed.

It looks like hash-based states do work when you click a link that uses ui-sref, but don't work with regular hrefs or if you just navigate to a hash-based URL in a browser.

If this doesn't sound like a common use case, I wonder if there's a workaround that I could configure (e.g. watch the hash, and trigger a state reload manually)?

@eddiemonge
Copy link
Contributor

https://gist.github.com/eddiemonge/f6a58169c2846731a1eb

@mssalnikov
Copy link

mssalnikov commented Aug 24, 2016

As per note, I'm commenting to say I'm still affected by this issue, since I need to match urls like /{param1:[0-9]+}/{param2:#?[0-9]+}

@richfergus
Copy link

richfergus commented Oct 30, 2016

@mssalnikov, and anyone else stumbling upon this:
I got $state with $resource to work in this:

    $scope.flightHours = function() {
        $state.go('app.ops.main',{'#':'red'});
     };

With this anchor tag on the ops.main template:

    <div class="row" id="red">

@mssalnikov
Copy link

mssalnikov commented Nov 21, 2016

@richfergus Hey!

Yes, I'm aware of that solution, yet it only works from withing angular, when you change the state manually. My case is this: users have to be able to access url https://domain.com/3456/#1234, and $state does not match this to a /{param1:[0-9]+}/{param2:#?[0-9]+}. My workaround is therefore ugly AF:

.state('catch', {
        url: '/{param1:[0-9]+}/',
        onEnter: /* @ngInject */ ($state) => {

        if (location.hash) {
            $state.go('state', {param1: $state.params.param1, param2: location.hash})
        }
    }
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests