10 Replies Latest reply on Jul 24, 2007 3:15 PM by dkane

    rerendering a4j component from plain Javascript code

    dkane

      Hello

      I have a a4j:mediaOutput component and some plain JS functions that handles various page events.

      "createContent" method of mediaOutput is a method of Seam component.

      Before some JS functions returns, I need to assign some properties to this Seam component (from JavaScript variables) and rerender the mediaOutput image.
      Is it possible ?

      Thank you in advance for help.

        • 1. Re: rerendering a4j component from plain Javascript code
          dkane

          I have solved the first part of task with Seam Remoting.
          Now method is being called well from Javascript, but I need to rerender image after that.
          I can obtain Javascript element , rendered via mediaOutput, with getElementById(...). But there are no "refresh()" or "reload()" or anything like that. Please advice.

          • 2. Re: rerendering a4j component from plain Javascript code
            tcavaleiro

            I'm not an expert, but I think it's impossible because the JSF have a life cycle..etc.. and Seam Remoting don't have.



            Please read a good article on that http://www.ibm.com/developerworks/java/library/j-seam3/

            "(...) Seam Remoting uses a custom, non-JSF life cycle to allow the browser to communicate with the server-side components. Only the Seam container and its components are restored during these requests. (...)"

            • 3. Re: rerendering a4j component from plain Javascript code
              dkane

               

              "tcavaleiro" wrote:
              I'm not an expert, but I think it's impossible because the JSF have a life cycle..etc.. and Seam Remoting don't have.


              In other words, when we need stateful context we have to keep to JSF and Ajax4jsf . And there are no bridges between plain Javascript and context.
              Sounds reasonable. But is it possible to implement the following logic with Seam, at all :

              Web application is interactive map. As said above, I am using mediOutput to produce map picture dynamically. Stateful Seam component keeps current scale and margins, executes navigation actions and serves as graphics producer for mediaOutput. Navigation links "up, down, left, right, zoom" are implemented as s:link and works perfectly.

              But then I need to make image interactive : user should be able to select a rectangular frame for zooming by mouse. Since there is no Ajax4Jsf support for that, I have written a number of plain JS functions that draws the rectangle , calculates new scale and margins, etc. But finally I need to update corresponding properties of Seam component and rerender the map.

              Any ideas ?

              • 4. Re: rerendering a4j component from plain Javascript code
                tcavaleiro

                With Seam Remoting you have access to stateful contexts.
                Because if you can access Seam components that aren't stateful you can access Seam components thar are stateful.

                (I've not used it yet)


                I think that from Seam Remoting you can't access a ajax4jsf component and force the reRender of it.
                As it says:
                "(...) Only the Seam container and its components are restored during these requests. (...)"


                I've read your idea, but I can't help you (don't know how!).
                As I said It's possible to update the Seam component properties through Seam Remoting, but I don't know how to force the reRender.

                Wait for an expert.

                • 5. Re: rerendering a4j component from plain Javascript code
                  dkane

                  Thank you for participation and ideas, anyway !

                  • 6. Re: rerendering a4j component from plain Javascript code
                    tcavaleiro

                    I again,

                    Don't know if you already resolved your problem, but here it goes:

                    I think that what you want is something like this

                    http://livedemo.exadel.com/a4j-jsFunction/

                    The source code is available here
                    http://labs.jboss.com/jbossajax4jsf/demo/index.html


                    "a4j-jsFunction - A demonstration of a new feature in Ajax4jsf 1.1, the a4j:jsFunction component. a4j:jsFunction is similar to a4j:support, except it allows invoking the AJAX transaction from Javascript code. Additionally, a4j:jsFunction allows using the JSON format for the data return back with the AJAX response. You can call any Javascript function with this data as a parameter."


                    I'm going to experiment it too!


                    Regards,
                    Tiago.

                    • 7. Re: rerendering a4j component from plain Javascript code
                      dkane

                      tcavaleiro,

                      thank you for the link.

                      Trying that, so far without success.

                      XHTML fragment :

                      <a4j:form>
                      
                      <a4j:jsFunction name="frameZoom" actionListener="#{map.frameZoom}" reRender="a4map">
                       <a4j:actionparam name="heightPercent" assignTo="#{map.heightPercent}"></a4j:actionparam>
                       <a4j:actionparam name="widthPercent" assignTo="#{map.widthPercent}"></a4j:actionparam>
                       <a4j:actionparam name="xLeftPercent" assignTo="#{map.xleftPercent}"></a4j:actionparam>
                       <a4j:actionparam name="yTopPercent" assignTo="#{map.ytopPercent}"></a4j:actionparam>
                       </a4j:jsFunction>
                      
                       ........
                      
                       <a4j:mediaOutput id="a4map"
                       element="img"
                       cacheable="false"
                       createContent="#{map.drawImage}"
                       mimeType="image/gif"
                       onmousedown="mapStartZoom(event)"
                       onmousemove="mapMouseMove(event)"
                       onmouseup="mapStopZoom(event)"
                       />
                      </a4j:form>
                      



                      mapStopZoom function :

                      function mapStopZoom(evt)
                       {
                       ... some calculation ...
                      
                       frameZoom(heightPercent,widthPercent,xLeftPercent,yTopPercent);
                       console.log(" heightPercent="+heightPercent+
                       " widthPercent="+widthPercent+
                       " xLeftPercent="+xLeftPercent+
                       " yTopPercent="+yTopPercent);
                       }


                      Firebug console shows that this function is being called , with correct values.

                      Seam component (important fragments only):

                      @Stateful
                      @Name("map")
                      @Scope(ScopeType.SESSION)
                      @SuppressWarnings("unchecked")
                      
                      public class MapImageA4JAction implements MapImageA4J, Serializable
                      {
                       .......
                       private double xleftPercent;
                       private double ytopPercent;
                       private double widthPercent;
                       private double heightPercent;
                      
                       //---------------------------------------------------------------------------------
                       //
                       public void drawImage(OutputStream out, Object data) throws Exception
                       {
                       ... some code ...
                       System.out.println("Image redrawn: XC="+xc+" YC="+yc+" Scale="+scale);
                       }
                      
                      //---------------------------------------------------------------------------------
                      //
                       public void frameZoom()
                       {
                       double xleftNew = xleft + (xright-xleft)*xleftPercent ;
                       double ytopNew = ytop - (ytop-ybottom)*ytopPercent ;
                       double widthNew = Math.abs((xright-xleft)*widthPercent);
                       double heightNew = Math.abs((ybottom-ytop)*heightPercent) ;
                      
                      
                       int scaleNew ;
                       if (widthPercent<heightPercent) scaleNew = (int)(scale/widthPercent);
                       else scaleNew = (int)(scale/heightPercent);
                      
                       int xcNew=(int)(xleftNew+widthNew/2);
                       int ycNew=(int)(ytopNew-heightNew/2);
                      
                       setXc(xcNew);
                       setYc(ycNew);
                       setScale(scaleNew);
                      
                       System.out.println("Framezoom called : XC="+xc+" YC="+yc+" Scale="+scale);
                      
                       }
                      
                      }
                      
                      



                      Debug messages says that frameZoom a4j:jsFunction is being called correctly, it invokes frameZoom() method and assigns all 4 parameters correctly, too.

                      The problem is , that reRender="a4map" attribute does not work.
                      I must see debug messages "Framezoom called" and after that "Image redrawn" , but I only see "Framezoom called".




                      • 8. Re: rerendering a4j component from plain Javascript code
                        dkane

                        I roughly solved the problem by replacing a4j:mediaoutput with h:graphicImage with "url" attribute linked to dynamically created url .
                        For this h:graphicImage , reRender is working fine. Still interested why it doesn't work for a4j:mediaOutput .


                        • 9. Re: rerendering a4j component from plain Javascript code
                          tcavaleiro

                          For what I saw you didn't used the <a4j:mediaOutput ... value="#{...}" />.

                          I don't know if it's mandatory to use the value attribute or not!

                          I'm thinking that way, because if it's mandatory, then it's possible that when rendering the a4j:mediaOutput the method binding on createContent don't get called.


                          For testing try getting the data from the data parameter on (public void drawImage(OutputStream out, Object data)) and use another EL binding expression on the value attribute when you declare the a4j:mediaOutput.


                          PS: I'm assuming that you read the demonstrations here -> http://livedemo.exadel.com/a4j-mediaOutput/


                          • 10. Re: rerendering a4j component from plain Javascript code
                            dkane

                             

                            "tcavaleiro" wrote:

                            I'm thinking that way, because if it's mandatory, then it's possible that when rendering the a4j:mediaOutput the method binding on createContent don't get called.


                            As I understand, value class is intended to pass some variable parameters to drawing provider. I do not need that - my provider bean is stateful (unlike PaintBean in demonstration) and contains all necessary data. "createContent" definitely gets called when invoked from other, non-Ajax controls (s:link, etc.) on the same page.

                            But your version deserves testing of course - thank you, I will try that a bit later. Now I have working solution with h:graphicImage and have to go ahead with other tasks of the project.

                            Probably a4j fathers will open our eyes in the meantime :)