[Seaside] Updating browser history from an ajax response

Esteban Maringolo emaringolo at gmail.com
Fri Apr 12 19:56:02 UTC 2019


Hi Johan,

Hi reply below.

On Fri, Apr 12, 2019 at 12:23 PM Johan Brichau <johan at inceptive.be> wrote:
>
> Hi Esteban,
>
> I’m interested in this too.
> We have the same kind of application (I guess… using mostly Ajax updates, I mean) but I have just been postponing a retry to address the inconsistency with ajax, server state and the back button for years….

I've been postponing this for a while but will need it sooner than later :)

> Within a callback, you can get at the #actionUrl on the renderer.
> Is that what you want?

I can't tell really, the actionUrl now, only has something like this
`/?_s=...&_k=...`, so certainly it doesnt.

> I’m trying to dive into what would be required here… trying to understand what you need:
> Ajax requests always update the same continuation state in Seaside (i.e. they do not create a new continuation)… so if you push that url to the history after each ajax update, the back button will essentially request the same but updated continuation from Seaside, meaning you should see the state as it is in on the server, and not how it was before you made the ajax request (which is what happens now).

I have a tree of nested component, which where working without using
AJAX, and had all the "#updateUrl:" methods in place, so if for
instance, I had a root component and opened a project ABCD, I added
the `/project/ABCD' to the URL. So when the user came back later for
that URL, I could lookup for that project and initialize the proper
"tree" of components to show it (or show an error if not found, etc.).

I then moved to everything as AJAX to make things faster and simplify
the state management... and lost this capability.

I drive most AJAX interactions by means of "script" AJAX responses, so
my idea is to change the component tree structure at the server side
(as I'm doing now), and at the end of some "top level" loading/reload
push the URL that would have been generated by means of a regular
visitor transversal to browser history stack.

Let's suppose we have a common CRUD like UI very much like the ones
used by REST APIs, so we have the following components

UsersComponent -> 'users'
UserComponent -> 'admin'
UserSectionComponent -> 'settings'

So if the app is showing aUsersComponent as its main component (I call
it `bodyComponent`) then the url would be `/users`, when some user is
selected, the bodyComponent (aUsersComponent) "shows" (#show:)
aUserComponent, this adds the userId component to the URL, and if
within that component I access a particular section of the user (e.g.
'settings' or 'preferences'), then that gets added to the URL as well.

I want that when I call `scriptReplaceOn: aScript` of a particular one
of these components they do something like this:

`UserComponent>>scriptReplaceOn: aScript

  aScript << ((aScript jQuery id: self ajaxId) replaceWith: [:h | self
renderContentOn: h]).
  aScript << ((JSStream on: 'window.history') call: 'pushState' with:
self historyState).

And  `historyState` would have this "resolved" WAUrl instance, that I
guess would be initialized using a WAUpdateUrlVisitor from current
component (e.g. UserSectionComponent) to the root (although in the
inverse order).

> Does that correspond to what you are trying to fix?

I guess it does. But I'm not sure whether I'm using the states and
continuations the canonical way.
Things work, causing a full page reload shows the exact same content
as it was before, but backbutton does nothing (it behaves as a full
page reload).

I feel like I have not answered your question, but since there is no
"recommended" way to work with components with AJAX (e.g. replacing
the instVar, using show/call/answer, etc.), I don't know whether a
"suitable" solution might be found.


Esteban A. Maringolo


More information about the seaside mailing list