[Seaside] Rendering Callbacks during an Ajax callback

jtuchel at objektfabrik.de jtuchel at objektfabrik.de
Sat Feb 11 09:28:14 UTC 2017


Hi Johan,

okay, food for thought and experimenting. Thanks a lot. I'll be 
attempting to process this, expect me to not ask questions on this for a 
while ;-))))

Anyways, thanks a lot for these explanations and sample code. I'll have 
to chew on that for a while ;-)

Joachim




Am 11.02.17 um 10:19 schrieb Johan Brichau:
> 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/#%21/%7EJohanBrichau/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 
>> <mailto: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 Tuchelmailto:jtuchel at objektfabrik.de
>>>> Fliederweg 1http://www.objektfabrik.de
>>>> D-71640 Ludwigsburghttp://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
>>>
>>>
>>>
>>> _______________________________________________
>>> seaside mailing list
>>> seaside at lists.squeakfoundation.org
>>> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
>>
>>
>> -- 
>> -----------------------------------------------------------------------
>> Objektfabrik Joachim Tuchelmailto:jtuchel at objektfabrik.de
>> Fliederweg 1http://www.objektfabrik.de
>> D-71640 Ludwigsburghttp://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
>
>
>
> _______________________________________________
> seaside mailing list
> seaside at lists.squeakfoundation.org
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside


-- 
-----------------------------------------------------------------------
Objektfabrik Joachim Tuchel          mailto:jtuchel at objektfabrik.de
Fliederweg 1                         http://www.objektfabrik.de
D-71640 Ludwigsburg                  http://joachimtuchel.wordpress.com
Telefon: +49 7141 56 10 86 0         Fax: +49 7141 56 10 86 1

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


More information about the seaside mailing list