You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by "Dmitry Gusev (JIRA)" <ji...@apache.org> on 2014/11/17 10:12:34 UTC

[jira] [Commented] (TAP5-2416) Client-side publish/subscribe mechanism

    [ https://issues.apache.org/jira/browse/TAP5-2416?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14214438#comment-14214438 ] 

Dmitry Gusev commented on TAP5-2416:
------------------------------------

I will try to summarize what you're suggesting, so correct me if I wrong.
Also I'm not familiar with T5.4 JS model, so I'll base my thoughts on T5.3 branch.

So your suggestion is to add the ability to trigger events server-side, but implement the handling of these events client-side.

Particularly you're talking about a server-side event named {{message}} that would be somehow delivered to client-side and then re-triggered there, and there will be default client-side handler implemented for zones -- {{refreshOnMessage}} -- that would do a zone refresh on this event if it matches some criteria.

If that's the case, then I'd generalize this API so it could be used in other places too.
For example here's how your use-case may be implemented:

{code}
ajaxResponseRenderer.publishEvent("tapestry.zoneRefresh").with(new JSONObject("{ 'message': 'personAdded' }"));
{code}

This will deliver server-side event {{tapestry.zoneRefresh}} to client-side with some optional JSON specification.
This JSON specification will be specific for the event, so, for example {{refreshOnMessage}} would expect a {{message}} parameter from {{tapestry.zoneRefresh}} event.

Then your TML would look the same (maybe we can even provide comma-separated list of messages here):

{code}
<t:zone ... refreshOnMessage="personAdded" />
{code}

Now we need to implement a zone refresh handler that would subscribe to the {{tapestry.zoneRefresh}} event and refresh this zone if the {{message}} parameter matches the value from event's specification.

To refresh a zone we could reuse logic from the ZoneRefresh mixin, so if a zone has {{refreshOnMessage}} parameter bounded it would invoke the same initializer call as ZoneRefresh mixin passing all information necessary for correct zone refresh.

Or even better, instead of this new {{refreshOnMessage}} parameter for Zone component we can improve ZoneRefresh mixin by making {{period}} parameter optional (and/or use some magic constance like 0 to disable periodic updates), and adding {{refreshOnMessage}} as a new parameter to this mixin.

--

It'd also be nice if we implement public client-side API that would allow developers to declare custom client-side handlers for such events.

This way you can do some custom/complex DOM manipulations using JSON data from the server-side event.

> Client-side publish/subscribe mechanism
> ---------------------------------------
>
>                 Key: TAP5-2416
>                 URL: https://issues.apache.org/jira/browse/TAP5-2416
>             Project: Tapestry 5
>          Issue Type: New Feature
>          Components: tapestry-core
>    Affects Versions: 5.4
>            Reporter: Geoff Callender
>            Priority: Minor
>
> In some cases, a component may want to respond to an AJAX event in another component. For example a component that display a user's name would want to know when a user-editing component in the same page has successfully updated the user via AJAX.
> In simple pages it can be handled this way: the server-side event handler bubbles up a "user changed" event up to its container, and the container can call down to any interested component it contains and the component could use AjaxResponseRenderer#addRender(...). The container could also bubble up the event, and so it repeats right up to the page level.
> However, in more complex pages this gets clunky and problematic. It would be nice to use a publish/subscribe mechanism. But should the mechanism be server-side, or client-side?
> **Server-side** has a fundamental stumbling block: the server-side is usually stateless. An AJAX request can contain enough info to tell its server-side component what state is required, but typically it would be only enough for that component. The server-side component could publish its success, but the subscribing components may not have enough information to correctly reproduce their client-side's current state and therefore they would be unable to respond usefully. This has been discussed extensively in TAP5-2383 .
> In contrast, the **client-side** knows exactly the state of every component, so it is the ideal place to do the publish/subscribe.
> Quoting from TAP5-2383...
> How about a mechanism along these lines:  
> - give the Zone component a "refreshOnMessage" parameter, specifying a message string; and
> - give AjaxResponseRenderer a publishMessage(String s) method; and
> Tapestry could do the rest, client-side: it receives the message string, identifies all the zone instances that asked to be refreshed when that string appears, and triggers a refresh of each one.
> For example:
> - In onSuccessFromPersonForm(), do ajaxResponseRenderer.publishMessage("personAdded");
> - client-side, Tapestry would identify each subscriber, ie. each zone in the DOM that was created with refreshOnMessage="personAdded"; and trigger refresh on that zone. It would be a second request, but so what? Asynch is the rule these days, not the exception.
> The most likely use of this mechanism would be for something that shows a count of persons to update itself: Persons (27), just as in the example that prompted this JIRA: http://apache-tapestry-mailing-list-archives.1045711.n5.nabble.com/Different-Zone-Update-s-tt5728186.html .
> If there's a need for a context, e.g. personId, then I think we could handle it. Perhaps ajaxResponseRenderer.publishMessage("personAdded").with(personId). However, I haven't thought through how to handle it in the subscribing zones.
> More thoughts please!



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)