[Seaside] Rendering Callbacks during an Ajax callback

Johan Brichau johan at inceptive.be
Sat Feb 11 09:19:16 UTC 2017


Hey Joachim,

You can use a normal seaside callback and register it to capture delegated events.
No magic ;)

html orderedList
	script: (html jQuery this 
			on: ‘click’
			selector: ‘.mylistItemClass’ 
			do: ((html jQuery ajax
					callback: [:listitemId |  … ]
					value: (((html javascript alias: ‘event’) access: ‘target’) access: ‘id’))
				asFunction: #(event))

This registers the callback on the list to capture clicks on the items below it, while passing the id of the element on which the click happened to the callback.
If you register passengers on each of the listitems, it’s more intuitive:

html orderedList
	script: (html jQuery this 
			on: ‘click’
			selector: ‘.mylistItemClass’ 
			do: ((html jQuery ajax
					callback: [:passenger |  … ]
					passengers: ((html javascript alias: ‘event’) access: ‘target’)
				asFunction: #(event))

Obviously, this does not render anything yet. So, we need to add that functionality to the callback:

| idToReRender |
html orderedList
	script: (html jQuery this 
			on: ‘click’
			selector: ‘.mylistItemClass’ 
			do: ((html jQuery ajax
					callback: [:listitemId |  … idToReRender := listitemId ... ]
					value: (((html javascript alias: ‘event’) access: ‘target’) access: ‘id’));
					script: [:s | s << ((s jQuery id: idToReRender) html: [:h | self renderMyRowWithId: idToReRender ]) ]
				asFunction: #(event))

This adds a script callback that will produce a response that re-renders the list item. Although this is a rough implementation that passes id’s everywhere, it does require to keep a mapping between id and the ‘row item component’ you need to render somewhere in your app. Seaside provides such a mapping via passengers, but depending on your use case this might not scale either. So, how this mapping is done depends a bit on you.

For more examples that use event delegation, take a look at this repo from the tutorial I gave at ESUG Edinburgh: http://smalltalkhub.com/#!/~JohanBrichau/Seaside-Playground <http://smalltalkhub.com/#!/~JohanBrichau/Seaside-Playground>
The renderTodosOn: method has some exciting callback combinations to look at.

Hope this helps
Johan

> On 11 Feb 2017, at 09:32, jtuchel at objektfabrik.de wrote:
> 
> Hi Johan,
> 
> first of all: thanks for your time!
> 
> 
> > I’m a bit confused why you are rendering in this way in your callback method. 
> 
> Maybe the answer wouldn't really be something I'd like to hear ;-)
> 
> 
> The method doesn't have a parameter, because the ajax call is initiated by hand-written javascript code. One reason is that the list can be very long (up to 2000 list items) and I only want to install one click handler on the document using 
> 
> $(document).on("click",".mylistItemClass", function() { ... $.ajax() ...}).done();
> 
> etc. etc.
> 
> So I register only one callback in updateRoot: and store the number in an instVar
> 
> updateRoot:
>     checkboxenCallback := html context callbacks store: (JSAjaxCallback on: [self einOderAusblendenCheckbox]).
> 
> then, in renderContentOn; I do: 
> 
> 
> renderContentOn:
> 	html document addLoadScript: (
>         '$(document).on("change", ".ein-aus", function(evt) {
>                     evt.preventDefault(); 
> 	            var target = $(evt.target);
>                     var row = target.parents(".row"); 
>                     $.ajax({
>                         url:  %1+"&pk="+ rahmenId ,
>                         })
>                         .fail(function(res) {alert(res.responseText)})
>                         .done(function(result) {
>                                         row.replaceWith(result); }});
>                 })'
>             bindWith: (html actionUrl copy addField: checkboxenCallback) asString sstAsQuotedString)
> 
> 
> So I guess you are asking the right question: why do I build up a new context/builder... ? I never tried, but maybe I should just register a one argument-block as callback and hope for some Seaside magic?
> 
> I will try that immediately (just occured to me while typing this message...)
> 
> 
> Joachim
> 
>  
> 
> 
> 
> 
> 
> Am 11.02.17 um 09:11 schrieb Johan Brichau:
>> Hi Joachim,
>> 
>> I’m a bit confused why you are rendering in this way in your callback method. 
>> Why are you doing this differently than in any other Seaside rendering method?
>> 
>> Since you are instantiating a new builder, it is going to create it’s own rendercontext, hence it’s own registry for callbacks.
>> I have not deeply investigated the result of your code snippet, but this seems to me why you are seeing that callback numbers are restarted.
>> 
>> Now, if you re-render list-item with a callback on it, Seaside will indeed need to register a new callback. The memory overhead should be limited to the registry dictionary entry and a WASeasideCallback instance, however, since the block and it’s lexical context object will already exist before rendering. So… I would not worry about memory overhead.
>> 
>> If you are doing this because you are doing hand-written ajax calls: what I tend to do is generate a jQuery-Seaside ajax callback and assign this to a Javascript variable, which I can use from the hand-written JS. Of course, there’s variations on this other than global-variable assignment but that’s all Javascript fiddling.
>> 
>> So, before I try to dig deeper in your problem: why is this method not called: "changeSomeStuffOnTheServerAndRedrawOn: html” :) ?
>> 
>> Johan
>> 
>> 
>>> On 10 Feb 2017, at 17:26, jtuchel at objektfabrik.de <mailto:jtuchel at objektfabrik.de> wrote:
>>> 
>>> Dear Seasiders,
>>> I must bee overlooking something obvious. 
>>> I want to redraw a listItem in and unorderedList (it is a boostrap .list-item .row, but that doesn't really matter) in an Ajax callback. 
>>> This listItem contains normal anchors with callbacks. 
>>> The ajax call is initiated in a javascript function, not rendered by Seaside. This call to ajax does the following;
>>> 
>>> 
>>> $.ajax( ... ).done(function(result) {
>>>         row.replaceWith(result);});
>>> 
>>>     
>>> where row is a jquery that contains the listItem. The rerendering works very well and all seems good.
>>> 
>>> Except for one little detail: the callbacks rendered in the AJax callback are re-numbered from 1 and once you click on oneof the re-rendered link it is a nice surprise what method might get called on the server. I guess I am messing with the _s and _k parameters in my caööback method.
>>> 
>>> So here is my callback method which answers the re-rendered listItem/row:
>>> 
>>> 
>>> changeSomeStuffOnTheServerAndRedraw
>>> 
>>>     | rahmenElementId fields req betrag planElement conv wrapper ctx contKey row resp |
>>> 
>>> 
>>>         ctx := self requestContext.
>>>         req := ctx request.
>>>         resp := ctx response.
>>>         fields := req fields.
>>> 
>>>         "Some boring business stuff which works like a charm, including finding the right business objects, changing them, commits in Glorp and whatnot"
>>>         "Re-render the row"
>>>         row := self findTheListItemComponentForRerendering.
>>> 
>>>         resp
>>>             status: 200;
>>>             contentType: (WAMimeType textHtml charset: ctx handler charSet);
>>>             nextPutAll: (
>>>                 (self rendererClass builder)
>>> "**->"              actionUrl: (ctx session actionUrlForKey: contKey);   "I also tried leaving this out --> even worse"
>>>                     fullDocument: false;
>>>                     render: [:html |
>>>                         html render: row ])
>>> 
>>> I think the problem is either the fact that I shouldn't be using the requestContext of the Ajax callback, or the actionUrl: part is wrong.
>>> The rows not re-rendered still work like a charm.
>>> 
>>> 
>>> You can see in the attached picture that both a not-re-rendered row and the re-rendered row point to the same 's anchors point to the same url with identical _s and _k parameters, but thesecond one is the re-rendered and its callback number is 1 instead of 51, which it had before re-rendering:
>>> 
>>> <ifioakbcdojcdbmm.png>
>>> 
>>> If I use the URL and replace the 1 with 51, The correct callback is being called, the initial callback is still registered. 
>>> I wouldn't mind if the re-render registered another Callback, even if that means I waste memory, but it seems I am registering the new callbacks in some registry that's new for the ajax callback.... (I am confused)
>>> 
>>> Any hints? Ideas? How can I make sure the anchors in that redrawn listItem find their callback blocks on the server?
>>> 
>>> 
>>> Thank you in advance
>>> 
>>> Joachim 
>>>  
>>> 
>>> 
>>> 
>>> -- 
>>> -----------------------------------------------------------------------
>>> Objektfabrik Joachim Tuchel          mailto:jtuchel at objektfabrik.de <mailto:jtuchel at objektfabrik.de>
>>> Fliederweg 1                         http://www.objektfabrik.de <http://www.objektfabrik.de/>
>>> D-71640 Ludwigsburg                  http://joachimtuchel.wordpress.com <http://joachimtuchel.wordpress.com/>
>>> Telefon: +49 7141 56 10 86 0         Fax: +49 7141 56 10 86 1
>>> 
>>> _______________________________________________
>>> seaside mailing list
>>> seaside at lists.squeakfoundation.org <mailto:seaside at lists.squeakfoundation.org>
>>> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside <http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside>
>> 
>> 
>> 
>> _______________________________________________
>> seaside mailing list
>> seaside at lists.squeakfoundation.org <mailto:seaside at lists.squeakfoundation.org>
>> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside <http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside>
> 
> 
> -- 
> -----------------------------------------------------------------------
> Objektfabrik Joachim Tuchel          mailto:jtuchel at objektfabrik.de <mailto:jtuchel at objektfabrik.de>
> Fliederweg 1                         http://www.objektfabrik.de <http://www.objektfabrik.de/>
> D-71640 Ludwigsburg                  http://joachimtuchel.wordpress.com <http://joachimtuchel.wordpress.com/>
> Telefon: +49 7141 56 10 86 0         Fax: +49 7141 56 10 86 1
> 
> _______________________________________________
> seaside mailing list
> seaside at lists.squeakfoundation.org
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/seaside/attachments/20170211/8deb7e3c/attachment-0001.html>


More information about the seaside mailing list