Forums

Find answers, ask questions, and connect with our
community all around the world.

Home Forum Omnis General Forum jsProgressBar Control – not really controlling progress…

  • jsProgressBar Control – not really controlling progress…

    Posted by Uwe Smidt on October 4, 2024 at 10:21 pm

    Dear $all,

    I have some tasks (e.g. doing a few thousand REST API calls) that take an awful long time to finish.

    So in order to see if the process is still alive, I thought it would be a good idea to implement a window showing the progress of my task. So I had a look at the sample ‘JS Progress’.

    While the sample works as is, my attempt to link the progress bar to the time-consuming task did not work.

    In the original sample, the counter (Calculate <b style=”font-family: inherit; font-size: inherit; color: var(–bb-body-text-color);”>iValue as <b style=”font-family: inherit; font-size: inherit; color: var(–bb-body-text-color);”>iValue+5) takes place WITHIN the CarryOn event:

    On evCarryOn

    If not(iCancelled)

    Calculate iValue as iValue+5

    Do $cinst.$objs.ProgressBar.$::value.$assign(iValue)

    If iValue<100

    Do $cinst.$objs.ProgressBar.$sendcarryon.$assign(kTrue)

    Else

    Do $cinst.$clientcommand("lockui",row()) ## unlock ui

    End If

    End If

    To me, this makes no sense, since the progress bar is supposed to display the progress of some other method, i.e. OUTSIDE of the CarryOn event. So I call that method (<b style=”font-family: inherit; font-size: inherit; color: var(–bb-body-text-color);”>$doSomethingMassive) from the event of the Start button:

    On evClick

    Do $cinst.$clientcommand("lockui",row(kTrue))

    Calculate iCancelled as kFalse

    Calculate iValue as 1

    Do $cinst.$objs.ProgressBar.$sendcarryon.$assign(kTrue)

    Do method $doSomethingMassive

    and that method (<b style=”font-family: inherit; font-size: inherit; color: var(–bb-body-text-color);”>$doSomethingMassive) is – here – quite simple:

    For iValue from 1 to 100

    Do $cinst.$objs.ProgressBar.$sendcarryon.$assign(kTrue)

    Do sleep(50)

    End For

    I would have assumed that raising that CarryOn event from within <b style=”font-family: inherit; font-size: inherit; color: var(–bb-body-text-color);”>$doSomethingMassive would update my progress bar DURING the execution of <b style=”font-family: inherit; font-size: inherit; color: var(–bb-body-text-color);”>$doSomethingMassive – but only AFTER the execution the bar goes to 100 at once.

    So what good is a progress bar that is really only a finish bar 😉 ?

    But I suppose I am doing something wrong, as usual…

    Any ideas?

    Best regards

    Uwe

    PS: I have attached the slightly modified sample ‘JS Progress’

    Andreas Pfeiffer replied 8 months, 3 weeks ago 4 Members · 19 Replies
  • 19 Replies
  • Diego Mendoza Muñoz

    Member
    October 8, 2024 at 4:33 am

    $sendcarryon.$assign(kTrue) is a async method the loop have to be inside the event

    aa.png is the “next” method

    captura is the progress $event method

    • Uwe Smidt

      Member
      October 9, 2024 at 3:03 pm

      Dear Diego,
      Thank you for your reply!

  • Andreas Pfeiffer

    Administrator
    October 8, 2024 at 9:53 am

    Hi Uwe,

    You would need to do the assignment of the progress bar in a client side method. The solution is to start with a client side method and then calling the server method that would execute the REST call. Just make sure you do not run the worker on a background thread. So use $run.

    Then implement a client side method that has the very same name as the server method but an extension “_return”. This method can then set the value of the progress bar and again trigger the server method. Omnis will automatically call the client method after the server method has been finished if the client method has the same name as the server method with that extension and the original call came from the client. So make sure the buttons $event is also set to client. See also the documentation here: https://www.omnis.net/developers/resources/onlinedocs/WebDev/02jsremoteforms.html#return-methods

    I will attach a simple example that demonstrates this.

    Hope this helps.

    Best,

    Andreas

    • Uwe Smidt

      Member
      October 9, 2024 at 3:05 pm

      Hi Andreas,
      Yeah, I think this is hinting in the right direction.

      I’ll try to adapt it in my setting, and come back to this forum with my approach or new questions ;-)!

      Thank you!
      Uwe

    • Uwe Smidt

      Member
      October 19, 2024 at 10:15 am

      Dear Andreas,
      dear $all,

      I tried to adapt it to my needs, but what I want does not work since it is in a nested loop:

      method ‘$doAPIStuff’:

      For Loop1 from 1 to 10
      Do API call 'A'
      For Loop2 from 1 to 100
      Do API call 'B' ## using input from API call ''A'
      For Loop3 from 1 to 1000
      Do API call 'C' ## using input from API call ''B'
      Do Method $updateProgressWindow
      End For ##Loop3
      End For ##Loop2
      End For ##Loop1

      As I understand now, this Loop structure is unsuitable to update a client window. Is that right? Do I REALLY need to break up my ‘wonderful’ loop structure and let the iteration be handled by daisy-chaining ‘$doAPIStuff’ with ‘$updateProgressWindow’ and ‘$updateProgressWindow_return’, i.e. calling ‘$doAPIStuff’ not just once, but (here) 1 million times?

      Another question in this regard: I would like to start the action (the API calls) from a main form (rfMain) with, say with a button ‘doApiStuff’, but show the progress in a modal window ‘jsProgress’ called by subformdialogshow. While I can reference rfMain from rfProgress by $cinst.$container, how do I reference the subformdialog from rfMain?

      Thanks in advance

      Uwe

      • Andreas Pfeiffer

        Administrator
        October 22, 2024 at 7:39 am

        Uwe,

        I haven’t tried this yet but you might be able to push a call to the client.

        In theory that could do the trick.

        Best,

        Andreas

      • Uwe Smidt

        Member
        October 22, 2024 at 8:40 pm

        Allright….,
        I got it all set up, but what a pain to do such a seemingly simple task…

        The process is started and runs in jsMain, while the progress is being shown in the jsProgressDialog evoked by clientcommand…subformdialogshow.

        I can interrupt the process by hitting escape (via the form’s cancelkeyobject), but not by clicking the Stop-button, despite being the alwaysenabledobject. Is that a bug, or a feature?

        I enclose the lib in the next post, for anyone interested in my struggle… 😉

        • Uwe Smidt

          Member
          October 22, 2024 at 8:42 pm

          The progress bar library – please feel free to use, comment or improve

          • Obonye

            Member
            October 23, 2024 at 6:10 am

            Thank you for the generosity. I wish you would be kind enough to share same lib in version 10.22

            • Uwe Smidt

              Member
              October 23, 2024 at 9:04 am

              You’re welcome!
              I’m afraid I don’t even know how to convert it to 10.22.

              But your general solution might be to get an up-to-date community edition to look into libs newer than your Omnis version.

              Best regards

              Uwe

          • Andreas Pfeiffer

            Administrator
            October 23, 2024 at 8:29 am

            Uwe,

            The reason why you are not able to stop the loop might be because Omnis is busy running the loop and you try to interfere this from the outside.

            I would like to recommend a different approach. Let the loop run outside of the remote task, i.e. using a worker, a different thread (if in multithreaded mode) or even on a different Omnis instance. So the task will run completely in the background. This has the advantage that the user can continue working in your application.

            Once the task has finished you could then send a push to the client, i.e. making a red button become visible so that the user knows that the task is done and by clicking the button making the result visible.

            What do you think?

            Best,

            Andreas

            • Uwe Smidt

              Member
              October 23, 2024 at 9:25 am

              Hi Andreas,
              Thank you for your thoughts!

              As for Omnis being busy: Yes, that’s the logical explanation, but I thought that ‘alwaysenabled…’ was helping that. And it is not too busy to react to hitting the escape key, but too busy to register a click on the Stop button…

              And it was not to busy to register a click on the Stop button while I still had the progress bars in jsMains – so maybe the modal property of invoking jsProgressDialog with

              Do $cinst.$clientcommand('subformdialogshow',row('jsProgressDialog',lcParams,'Work in Progress',475,340))

              makes it even more busy…

              And yes, putting lengthy processes in the background so the user can continue working is the way to go! And yet, being able to control the lengthy process with the progress bars is just what they are meant for, aren’t they 😉

              However, installing an Omnis REST server to manage push messages seems to me like using a sledgehammer to crack a nut…

              But anyway, this ‘little’ problem brought me closer to understanding the asynchronicity of client methods and server methods, and what it implies…

              Thank you for your help along the way!

              Best regards
              Uwe

            • Andreas Pfeiffer

              Administrator
              October 23, 2024 at 9:37 am

              Uwe,

              You are welcome.

              To make it clear. You do not need to have an Omnis REST server to make a push message to the client. There are two steps to send a push message.

              1. the remote form instance that will receive the push should open its channel. You can do this in the $construct of the form:

              Do $cinst.$openpush()

              2. When you want to push you need a reference to that remote form instance. Then you can send a push like this:

              Do $itasks.theOtherTask.$iremoteforms.myForm.$pushdata(row(‘something’))

              or – if you want to send it to the same task instance as you are in:

              Do $iremoteforms.myForm.$pushdata(row(‘something’))

              or – if your code is already in that instance:

              Do $cinst.$pushdata(row(‘something’))

              3. The form that will receive the push (i.e. myForm) has a $pushed method that you would need to override. This method needs to be client executed and will receive the row from the $pushdata.

              So for example if you have a busy loop running on the server you could do a push to the client by executing $pushdata to that instance. However there is still no way to interrupt that loop I am afraid since Omnis is busy running this loop.

              Best,

              Andreas

            • Uwe Smidt

              Member
              October 23, 2024 at 10:09 am

              Hi Andreas,
              Thanx again!
              I’m afraid I was misled by the online documentation (https://www.omnis.net/developers/resources/onlinedocs/WebDev/02jsremoteforms.html#push-connections) where I had the impression that a REST service is prerequisite to using push messages.

              But the is another online source that gives a great introduction to using push messages:

              Your ‘Full Course: Develop a Mobile App for a restaurant in 5 lessons’ at https://www.omnis.net/developers/academy/online/


              So I’ll have another look into that – thank you!

          • Obonye

            Member
            November 9, 2024 at 4:40 pm

            Hi, Uwe. How is the progress bar object able to show the progress without the property $events set to evCarryOn ? Martin.

            • Obonye

              Member
              November 9, 2024 at 7:42 pm

              Also, what do the methods $updateProgressBar and $updateProgressBar_return in jsProgressDialog do? I do notice that the suffix “return”. I have no idea why you name them that way and running on the client.

            • Andreas Pfeiffer

              Administrator
              November 10, 2024 at 12:40 pm

              Martin,

              A client-side method can call a server side method. There is an automated approach. When you have another client-side method with the suffix return, it will automatically be called after the server side method with the same basic name has been finished. See also here https://www.omnis.net/developers/resources/onlinedocs/WebDev/02jsremoteforms.html#return-methods

            • Obonye

              Member
              November 10, 2024 at 10:23 pm

              Thank you @ for the explanation. You taught me this client-side method call in one of classes. Q: Why is it that I cannot run methods in an object reference on the client? The SMTP worker send sample library has an object and I wish to run the methods on the client to use together with the jsProgress sample library. Is this a way around this? – Martin.

            • Andreas Pfeiffer

              Administrator
              November 11, 2024 at 7:59 am

              Hi Martin,

              You can run code on the client that is in remote object classes. However you cannot run code that needs to run on a server. For example all the worker objects can run on the server only because this code cannot be translated into JavaScript code. Or to look this from the other side: The worker objects are not available on the client. It would need to be JavaScript only.

              Best,

              Andreas

Log in to reply.