Seaside + Scriptaculous: Question on SUAjax onLoad, onComplete, etc.

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Seaside + Scriptaculous: Question on SUAjax onLoad, onComplete, etc.

Leandro Pérez
Hello, first of all, please forgive me for this extensive post, i didn't know how to explain my problem

I need to achieve the following:
When clicking a submit button, some server side actions must be performed and meanwhile those actions are being executed the user must see in different places of the web page different things, i.e. animated gifs showing progress, information text etc.. all this without refreshing the whole page, using ajax.  After the server side actions are executed, all those things that depended on the actions must be again refreshed according to the new model state in the server, using ajax.
e.g.
in a web messenger different images showing some contact's information
a button that when clicked launches some changes on the model (sever side)
when the button is clicked each image shows an animated gif meaning something is being done
when the server side action is finalized the images are refreshed showing the contact's new state

currently i'm doing something like this..

(html div)
    id:'some_div'
    with:'Some information'.

(html submitButton)
    onClick: ((html evaluator)
        callback: [:script | self performSomeServerSideActions.
                                 "THIS TAKES A WHILE"];
        onLoading: (html evaluator callback:
             [:script |
              (script element)
                 id: 'some_div';
                 render: [:r | self renderWorkingStatusOn: r
                                 "THIS GENERATES HTML DEPENDING ON THE MODEL STATE ON THE SERVER"]]));
        onComplete: (html evaluator callback:
             [:script |
              (script element)
                 id: 'reels';
                 render: [:r | self renderNewStatusOn: r
                                 "THIS GENERATES HTML DEPENDING ON THE MODEL STATE ON THE SERVER"]]));
    text: 'Spin'.


The problem of this is that the onLoading actions are not executed before the callback, but after, and because the onComplete actions are executed after the onLoading actions, the "working status" or the progress is not shown.

I also did this...using element instead of evaluator

(html submitButton)
    onClick: ((html evaluator)
        callback: [:script | self performSomeServerSideActions];
        onLoading: ((html element)
                 id: 'some_div';
                 render: [:r | self renderWorkingStatusOn: r
                                  "THIS GENERATES HTML DEPENDING ON THE MODEL STATE ON THE SERVER"]]));
        onComplete: (html evaluator callback:
             [:script |
              (script element)
                 id: 'reels';
                 render: [:r | self renderNewStatusOn: r
                                 "THIS GENERATES HTML DEPENDING ON THE MODEL STATE ON THE SERVER"]]));
    text: 'Spin'.

This partially works, i mean that it shows the progress and working stuff but with some inconsistences. The problem is that the code inside the first render block ([:r | self renderNewStatusOn: r]) is executed when the onLoading message is sent and the results are part of the generated js, this causes that the generated html that will be shown when the actions are executed is not consistent with the real model state, but with the former state (the one existing at the time the page was rendered and the js generated)

does anybody knows how to make this work or how to do it in a better way?

I don´t really know if the way i'm trying to do this is right, so if anyone has a better idea it will be great!


i'm currently using
        VisualWorks NonCommercial, 7.5
        Seaside2.7b1
        Scriptaculous2.6-mb.8

Thanks,
Leandro
Reply | Threaded
Open this post in threaded view
|

Re: Seaside + Scriptaculous: Question on SUAjax onLoad, onComplete, etc.

Lukas Renggli
> does anybody knows how to make this work or how to do it in a better way?

Seaside only processes one request per session at a time. It makes a
lot of code much simpler, as you don't have to worry about
concurrency. In your case it blocks the event handlers however, until
the main request has been processes.

> I don´t really know if the way i'm trying to do this is right, so if anyone
> has a better idea it will be great!

In general it doesn't make much sense to shoot off new requests from
AJAX events. Most web browsers don't allow one to have more than 2
concurrent requests anyway. To keep the responsiveness AJAX events
should only evaluate relatively fast JavaScript that doesn't do
anything asynchronous.

Lukas

--
Lukas Renggli
http://www.lukas-renggli.ch
_______________________________________________
Seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Seaside + Scriptaculous: Question on SUAjax onLoad, onComplete, etc.

Niklaus Lutz
hy

Maybe I've done something similar some time ago: After a file-upload,
the file had to be processed, that took up to several minutes....

My Solution:
In the callback of the upload button i forked a new thread that
processed the file:

#import
 [
self threadRunning: true.
  self processFile.
self threadRunning: false.
]   forkAt: Processor userBackgroundPriority named: 'Monitor import'


Render some information (duration) while the import is running, during
this time poll to see if the thread has finished:

#renderProgressBarOn: html
        html div
                id: 'divProgressbar';
                with: [
                        html text: #pleaseWaitTillImportHasFinished translate ] .
                               
#renderValidationOn: html
        self renderProgressBarOn: html.
        html div
                script: (
                    html periodical
                        evalScripts: true;
                        frequency: 1;
                        callback: [ :r |
                                self isThreadRunning:
                                        ifFalse: [
                                                r script:'updater.stop();$('divProgressbar'').setStyle({display:
''none''});'.
                                                super  renderValidationOn: r ]
                                        ifTrue: [
                                                r render: self elapsedTime duration ]];
                        assignTo: 'updater');
                with: [ ].


so instead of hiding the progress-bar, you could do another full-request....


hope it helps

/nik

2007/6/26, Lukas Renggli <[hidden email]>:

> > does anybody knows how to make this work or how to do it in a better way?
>
> Seaside only processes one request per session at a time. It makes a
> lot of code much simpler, as you don't have to worry about
> concurrency. In your case it blocks the event handlers however, until
> the main request has been processes.
>
> > I don´t really know if the way i'm trying to do this is right, so if anyone
> > has a better idea it will be great!
>
> In general it doesn't make much sense to shoot off new requests from
> AJAX events. Most web browsers don't allow one to have more than 2
> concurrent requests anyway. To keep the responsiveness AJAX events
> should only evaluate relatively fast JavaScript that doesn't do
> anything asynchronous.
>
> Lukas
>
> --
> Lukas Renggli
> http://www.lukas-renggli.ch
> _______________________________________________
> Seaside mailing list
> [hidden email]
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
>
_______________________________________________
Seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Seaside + Scriptaculous: Question on SUAjax onLoad, onComplete, etc.

Leandro Pérez
First of all, thanks a lot Lukas and Niklaus!!!
Niklaus Lutz wrote
hy

Maybe I've done something similar some time ago: After a file-upload,
the file had to be processed, that took up to several minutes....

My Solution:
In the callback of the upload button i forked a new thread that
processed the file:

#import
 [
self threadRunning: true.
  self processFile.
self threadRunning: false.
]   forkAt: Processor userBackgroundPriority named: 'Monitor import'


Render some information (duration) while the import is running, during
this time poll to see if the thread has finished:

#renderProgressBarOn: html
        html div
                id: 'divProgressbar';
                with: [
                        html text: #pleaseWaitTillImportHasFinished translate ] .
                               
#renderValidationOn: html
        self renderProgressBarOn: html.
        html div
                script: (
                    html periodical
                        evalScripts: true;
                        frequency: 1;
                        callback: [ :r |
                                self isThreadRunning:
                                        ifFalse: [
                                                r script:'updater.stop();$('divProgressbar'').setStyle({display:
''none''});'.
                                                super  renderValidationOn: r ]
                                        ifTrue: [
                                                r render: self elapsedTime duration ]];
                        assignTo: 'updater');
                with: [ ].


so instead of hiding the progress-bar, you could do another full-request....
I did basically what you say here, besides I used a high decay as stated in a post by Ramon Leon on Ajax Live Updates and other..

http://www.nabble.com/Ajax-live-updates-tf1922480.html#a5263907
http://www.nabble.com/Displaying-progress-on-a-web-page-tf2115321.html#a5853986

It is working fine, but another problem came up now, it is something i simply don't understand. Please
Look at the code below, at the part "LOOK HERE PLEASE!!!"


MyComponent>>renderContentOn:html
html div id:'div' with:'some content'.
(html submitButton)
        onClick: (html evaluator callback: [:script |
                [(Delay forSeconds:10)"Simulate long running process".
                self setWorkFinished] fork
                self update: 'div'
                whenTrue: [self isWorkFinished]
                rendering: [:h |  h submitButton  "this works fine"
                                      "h checkbox....when doing this, poll doesn't stop"]"LOOK HERE PLEASE!!!"
                on: script]);
        text: 'Spin'.


MyComponent>>update: elementId whenTrue: aBlock rendering: renderBlock on: script
        (script element)
        id: elementId;
        render:[:r | r div
                     with: [:h | renderBlock value: h]
                     waitForCondition: aBlock
                     thenRender: [:h  | renderBlock value: h]]
       
WATagBrush >> with: initialRenderBlock waitForCondition: aBlock thenRender: aRenderBlock
        self
            script: ((canvas periodical)
                  id: (self attributes at: #id);
                  decay: 1000;
                  asynchronous: true;
                  evalScripts: true;
                  frequency: 1 seconds;
                  callback:
                        [:r |
                        aBlock value
                            ifFalse:[initialRenderBlock value: r.
                                     r hiddenInput text: r nextId    "This is to keep decay low...generates different responses"]
                            ifTrue: [aRenderBlock value: r]]);
            with: initialRenderBlock



If in the line "LOOK HERE PLEASE!!!" I render an anchor, simple text, a submit button, a textInput etc.. it works just fine and nothing weird happens, but If I try to render a checkbox, a non-stopping poll mechanism starts and I end up with a post every 1 second.
It is weird because it only happens when I render a checkbox



any ideas????
Reply | Threaded
Open this post in threaded view
|

Re: Seaside + Scriptaculous: Question on SUAjax onLoad, onComplete, etc.

Leandro Pérez
I forgot to mention another thing..
rendering: [:h |  h submitButton  "this works fine"
                                      "h checkbox....when doing this, poll doesn't stop"]"LOOK HERE PLEASE!!!"
rendering: [:h |  h submitButton ]
This works fine

rendering: [:h |  h checkbox]
Problem: Non stopping poll
 
besides this, the same happens if I try to render something like this...


rendering: [:h |  (html submitButton)
                onClick: (html evaluator callback: [:script | "Do something"]);
                text: 'submit something']

Thanks again, help will be appreciated :)

Leandro