rgrempel / elm-route-url

Router for single-page-apps in Elm
http://package.elm-lang.org/packages/rgrempel/elm-route-url/latest
MIT License
196 stars 16 forks source link

How to do page jump when clicking a button inside a partial page? #14

Closed LeonLiuY closed 8 years ago

LeonLiuY commented 8 years ago

In the example, there are event handlers in the TOC which changes "currentPage" in the model of the root page. This leads to a page jump.

However, inside a partial page, it seems not possible to update the model of the root page. Then how to do a page jump in a partial page.

I have tried 2 ways:

  1. Use <a> tag and specify the href attribute.

    This really works well, but the limitation is that I have to use <a> tags. Sometimes page jump is required on other user events instead of link clicks.

  2. Make an Action in event handlers, and return Effects using History.setHash

    This works, but I found a strange problem that occasionally the page jump will finally return to the current page. (There is a flash)

    I'm not quite sure why this happens. But I guess location2action or delta2update has been triggered multiple times in this scenario. Since the Effects need an Action type stand-by and I have to set it to NoOp and do nothing with it. But will this NoOp action trigger a new delta2update ?

I'm confused with this behavior, and want to ask what is the best way to make page jump in a partial page.

rgrempel commented 8 years ago

Yes, I suppose that the NoOp would trigger a new delta2update, since it would push another model through the signal graph. Of course, it's the same model (as you say, you do nothing with it), but I'm not sure we can test for that (in the general case), since we don't know what's in your model, and it might not work with Elm's equality test (which is partial). I suppose that we could ask for a (perhaps optional) equality-testing function in the configuration, and use it if supplied.

Now, your delta2update function is supplied with both the old and new model, so I suppose you could do the testing for equality yourself (if your model is suited to it) and return Nothing if they are the same. It's possible that might help your case.

In any event, if it's happening occasionally, then it sounds like a race condition. There must be two async things happening here, which normally happen in the desired order, but sometimes not. If I recall correctly, History.setHash is implemented inside a setTimeout, so it's async. So, normally you'd expect it to happen after the NoOp is processed. However, sending actions to addresses is also inherently async, so perhaps occasionally the delta2update triggered by the NoOp happens after the History.setHash? It must be something of that kind, at any rate.

Of course, elm-route-hash isn't aware of your explicit use of History.setHash, so it's not straightforward to special-case it.

All that being said, the general philosophy behind elm-route-hash is that ideally you shouldn't go through the hash in order to change your model -- you should just change your model in the ordinary way, and let the hash follow along. (That is, the url handling should sit alongside your normal state transformations, rather than being an essential part of them).

So, ideally the best way to attack your problem would be by figuring out how to deal with this:

However, inside a partial page, it seems not possible to update the model of the root page.

Now this, it seems to me, is an example of the general question of "How does a sub-component trigger a change in a parent's model?" And that, in turn, is a common question of general interest.

In principle, there are only two possible answers:

Which, generally speaking, means modifying the standard signature of the child's update function to either:

I did a little googling around children updating parent's state in Elm, and got this (amongst other things), which suggests one plausible approach:

https://www.reddit.com/r/elm/comments/3plxaw/child_component_changing_state_on_parent/

Of course, I may have misunderstood your needs, but I think figuring out how to get children to update their parent's state might be helpful in your situation.