MyFaces Core
  1. MyFaces Core
  2. MYFACES-2640

(JSF.js) Ajax Render component problem, replace with whole fragment not one element.

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Invalid
    • Affects Version/s: 2.0.0-beta-3
    • Fix Version/s: 2.0.1
    • Component/s: JSR-314
    • Labels:
      None
    • Environment:
      tomcat 6.0.20 java (mac os x )

      Description

      after ajax submit, jsf.js will re-render some element depending on jsf.ajax.request(

      {render:" some elements "}

      );
      but this js code will cause some problem.

      jsf.js:

      myfaces._impl._util._Utils.replaceHtmlItem = function (request, context, itemIdToReplace, newTag, form)

      { ...... var fragment = range.createContextualFragment(newTag); evalNode = item.parentNode.replaceChild(fragment, item) ..... }

      sometime fragment will has more than one childNodes, or the childNode not has clientId, but the childNode of childNode has clientId.

      this will cause html unstable.

      Please fix it.

      this is my suggestion:

      myfaces._impl._util._Utils.replaceHtmlItem = function (request, context, itemIdToReplace, newTag, form)

      { ............. Orginal: var fragment = range.createContextualFragment(newTag); evalNode = item.parentNode.replaceChild(fragment, item) fix: var fragment = range.createContextualFragment(newTag); var replaceItem = myfaces._impl._util._Utils.findHtmlItemFromFragment(fragment, itemIdToReplace); if(replaceItem == null)replaceItem = fragment; evalNode = item.parentNode.replaceChild(replaceItem, item) .................. }

      myfaces._impl._util._Utils.findHtmlItemFromFragment = function(fragment, itemId){
      if(fragment.childNodes == null)
      return null;
      for(var i = 0; i < fragment.childNodes.length ; i++ )

      { var c = fragment.childNodes[i]; if(c.id == itemId) return c; }

      for(var i = 0; i < fragment.childNodes.length ; i++ )

      { var c = fragment.childNodes[i]; var item = myfaces._impl._util._Utils.findHtmlItemFromFragment(c, itemId); if(item != null) return item; }

      return null;
      };

        Activity

        Hide
        Werner Punz added a comment - - edited

        Ok I will look at it next week, I have to do some testing, this probably was a bug on my side, since I assumed a fragment usually is just one node, (which in most cases it is I will fix that after the weekend)

        Thing is, that usually the update edit and insert, works exactly on one element per block, hence usually the fragment replacement also has an outer element, which is exactly one root node.

        What you do is recursively search the fragment for an item which has the identifier for the replacement.

        I am not quite sure if we have really a usecase where this is necessary since
        update, insert, delete work exactly on the items and should deliver them back with one root node with the exact replacement element and its childnodes.
        The only way I can see that the current mechanism is a problem is if you trigger the update insert etc.. directly and have some content in which normally would not be rendered by the normal PPR Response.
        (Some kind of decorating html which then is omitted)

        Can you give me an exact usecase where you ran into this problem, so that I get a cleaner picture?

        Show
        Werner Punz added a comment - - edited Ok I will look at it next week, I have to do some testing, this probably was a bug on my side, since I assumed a fragment usually is just one node, (which in most cases it is I will fix that after the weekend) Thing is, that usually the update edit and insert, works exactly on one element per block, hence usually the fragment replacement also has an outer element, which is exactly one root node. What you do is recursively search the fragment for an item which has the identifier for the replacement. I am not quite sure if we have really a usecase where this is necessary since update, insert, delete work exactly on the items and should deliver them back with one root node with the exact replacement element and its childnodes. The only way I can see that the current mechanism is a problem is if you trigger the update insert etc.. directly and have some content in which normally would not be rendered by the normal PPR Response. (Some kind of decorating html which then is omitted) Can you give me an exact usecase where you ran into this problem, so that I get a cleaner picture?
        Hide
        Mark Li added a comment - - edited

        sorry for the late reply, I were on the chinese Qingming festival.

        ok, I give some examples. just like i extend h:inputtext and add some prefix or suffix symbols enclosing the orginal inputtext codes. or extend h:form to a jquery dialog. and etc.

        if fragment must have only one root which must have the clientid, it will make the components extension very difficult.

        And yes, i dont like recursively method too. before I find out a better search fragment method or you fix it , i will use these codes. I just want my work to move on.

        thx

        Mark

        Show
        Mark Li added a comment - - edited sorry for the late reply, I were on the chinese Qingming festival. ok, I give some examples. just like i extend h:inputtext and add some prefix or suffix symbols enclosing the orginal inputtext codes. or extend h:form to a jquery dialog. and etc. if fragment must have only one root which must have the clientid, it will make the components extension very difficult. And yes, i dont like recursively method too. before I find out a better search fragment method or you fix it , i will use these codes. I just want my work to move on. thx Mark
        Hide
        Werner Punz added a comment - - edited

        Ok this usecase can happen on component level.

        Ok lets sum this up, if you have a component renderer and it renders multiple nodes we have to deal with them,
        The fault clearly is at the javascript side, on our javascript side here.

        The obvious solution would be to have insert the replace + add the sibling nodes, but this does not work out entirely. Running recursively over all nodes also can fail in some cases (if the subnodes
        are not existing yet)

        I am not sure how to resolve this in a proper and clean manner yet.. I have some testing to do, give me a few days for a proper fix.

        The workaround for now is, to always use a root element on the code side where you have your main element and your decorations in, I probably have to work with that construct as well, for the dom manipulation to have a clean handling of this case (For now this seems the only viable option to me to handle this properly)

        Show
        Werner Punz added a comment - - edited Ok this usecase can happen on component level. Ok lets sum this up, if you have a component renderer and it renders multiple nodes we have to deal with them, The fault clearly is at the javascript side, on our javascript side here. The obvious solution would be to have insert the replace + add the sibling nodes, but this does not work out entirely. Running recursively over all nodes also can fail in some cases (if the subnodes are not existing yet) I am not sure how to resolve this in a proper and clean manner yet.. I have some testing to do, give me a few days for a proper fix. The workaround for now is, to always use a root element on the code side where you have your main element and your decorations in, I probably have to work with that construct as well, for the dom manipulation to have a clean handling of this case (For now this seems the only viable option to me to handle this properly)
        Hide
        Werner Punz added a comment -

        Also the question is, does Mojarra handle this usecase or does it not. I will run some tests the following days, expect a fix by the end of the week one way or the other.
        In the meantime please use the workaround of wrapping your entire output into a single node or just update a complete region which has the component embedded instead.

        Werner

        Show
        Werner Punz added a comment - Also the question is, does Mojarra handle this usecase or does it not. I will run some tests the following days, expect a fix by the end of the week one way or the other. In the meantime please use the workaround of wrapping your entire output into a single node or just update a complete region which has the component embedded instead. Werner
        Hide
        Werner Punz added a comment - - edited

        Ok I wrote myself a small testcase and ran it against myfaces and Mojarra to make sure to get the picture right:
        what happens is:

        super.encodeBegin(context, component);

        ResponseWriter writer = context.getResponseWriter();
        writer.startElement("div", component);
        writer.writeAttribute("id",component.getClientId(context), null );
        writer.write("hello world"+Math.random());
        writer.endElement("div");

        writer = context.getResponseWriter();
        writer.startElement("div", component);
        writer.writeAttribute("id",component.getClientId(context)+":_second", null );
        writer.write("hello world"+Math.random());
        writer.endElement("div");

        MyFaces id wrong here it constantly adds more or less the div at refresh because of the insert code, but what happens in Mojarra is following:
        it cherry pics the writer.startElement("div", component);
        writer.writeAttribute("id",component.getClientId(context), null );
        writer.write("hello world"+Math.random());
        writer.endElement("div");

        and omits the second part:

        writer = context.getResponseWriter();
        writer.startElement("div", component);
        writer.writeAttribute("id",component.getClientId(context)+":_second", null );
        writer.write("hello world"+Math.random());
        writer.endElement("div");

        hence only the first element in my testcase is updated.

        I am willing to follow this approach, but I am not sure it is the correct one, I am not even sure if you can get it right, in either way, the fix for me is simply to follow mojarras approach of cherry picking the correct element with the same identifier (recursively) to get the same behavior over both implementations.

        So Mark you approach is basically the one Mojarra does and in this case I will gladly use your code.

        Werner

        Show
        Werner Punz added a comment - - edited Ok I wrote myself a small testcase and ran it against myfaces and Mojarra to make sure to get the picture right: what happens is: super.encodeBegin(context, component); ResponseWriter writer = context.getResponseWriter(); writer.startElement("div", component); writer.writeAttribute("id",component.getClientId(context), null ); writer.write("hello world"+Math.random()); writer.endElement("div"); writer = context.getResponseWriter(); writer.startElement("div", component); writer.writeAttribute("id",component.getClientId(context)+":_second", null ); writer.write("hello world"+Math.random()); writer.endElement("div"); MyFaces id wrong here it constantly adds more or less the div at refresh because of the insert code, but what happens in Mojarra is following: it cherry pics the writer.startElement("div", component); writer.writeAttribute("id",component.getClientId(context), null ); writer.write("hello world"+Math.random()); writer.endElement("div"); and omits the second part: writer = context.getResponseWriter(); writer.startElement("div", component); writer.writeAttribute("id",component.getClientId(context)+":_second", null ); writer.write("hello world"+Math.random()); writer.endElement("div"); hence only the first element in my testcase is updated. I am willing to follow this approach, but I am not sure it is the correct one, I am not even sure if you can get it right, in either way, the fix for me is simply to follow mojarras approach of cherry picking the correct element with the same identifier (recursively) to get the same behavior over both implementations. So Mark you approach is basically the one Mojarra does and in this case I will gladly use your code. Werner
        Hide
        Werner Punz added a comment -

        Ok further mojarra testing has revealed the entire issue is a mess, because the mojarra code while working as described with newer browsers fails as myfaces does in ie6 and 7 because it omits the cherry picking.

        Show
        Werner Punz added a comment - Ok further mojarra testing has revealed the entire issue is a mess, because the mojarra code while working as described with newer browsers fails as myfaces does in ie6 and 7 because it omits the cherry picking.
        Hide
        Werner Punz added a comment -

        Ok I now have the code working in the same manner as Mojarras compliant browsers behavior, I also have fixed the code to behave the same in non compliant browsers (unlike Mojarra which produces an inconsistent result)
        I also fixed up the body replacement code.
        Give it a try, it now should be have as mojarra in w3c compliant browsers!
        (I also added a comment on the jsr-open list so the behavior might change within the next days again)

        Show
        Werner Punz added a comment - Ok I now have the code working in the same manner as Mojarras compliant browsers behavior, I also have fixed the code to behave the same in non compliant browsers (unlike Mojarra which produces an inconsistent result) I also fixed up the body replacement code. Give it a try, it now should be have as mojarra in w3c compliant browsers! (I also added a comment on the jsr-open list so the behavior might change within the next days again)
        Hide
        Werner Punz added a comment -

        Ok the recommendation so far from the open mailinglist is that the multi node component case should not occur from the component authors side, I have yet not really any confirmation on the actions I can take.
        It is either block the update or do just a "soft" error and then proceed.

        For now I wont start any further actions on this, but have in mind that if you want to handle the ppr case properly
        enclose your component code into a node with the client id being the identifier for the node, this is the only cross browser working way for both implementations, any other construct is bound to fail at least on IE6+ for Mojarra by leaving a dirty dom in your way or ruining your layout!

        Show
        Werner Punz added a comment - Ok the recommendation so far from the open mailinglist is that the multi node component case should not occur from the component authors side, I have yet not really any confirmation on the actions I can take. It is either block the update or do just a "soft" error and then proceed. For now I wont start any further actions on this, but have in mind that if you want to handle the ppr case properly enclose your component code into a node with the client id being the identifier for the node, this is the only cross browser working way for both implementations, any other construct is bound to fail at least on IE6+ for Mojarra by leaving a dirty dom in your way or ruining your layout!
        Hide
        Mark Li added a comment -

        good to see your solution.
        i am closing a company project using jsf2.0, its very bussy.
        after updating to myfaces 2.0.0, I still find some issues about this solution, and I fix it by myself temporarily , Should I open a new issue, i will paste it here firstly

        Show
        Mark Li added a comment - good to see your solution. i am closing a company project using jsf2.0, its very bussy. after updating to myfaces 2.0.0, I still find some issues about this solution, and I fix it by myself temporarily , Should I open a new issue, i will paste it here firstly
        Hide
        Mark Li added a comment -

        1、javascript will not run
        orginal:
        myfaces._impl._util._Utils.replaceHtmlItem = function (request, context, itemIdToReplace, newTag, form)

        { ..... } else {
        var replaceItem = myfaces._impl._util._Utils.findHtmlItemFromFragment(fragment, item.id);
        if (replaceItem == null) { replaceItem = fragment }
        evalNode = item.parentNode.replaceChild(replaceItem, item);
        }

        ....
        }


        fix:
        orginal:
        myfaces._impl._util._Utils.replaceHtmlItem = function (request, context, itemIdToReplace, newTag, form) { ..... }

        else {
        var replaceItem = myfaces._impl._util._Utils.findHtmlItemFromFragment(fragment, item.id);
        if (replaceItem == null)

        { replaceItem = fragment }

        evalNode = item.parentNode.replaceChild(replaceItem, item);
        evalNode = replaceItem;
        }

        ....
        }

        Show
        Mark Li added a comment - 1、javascript will not run orginal: myfaces._impl._util._Utils.replaceHtmlItem = function (request, context, itemIdToReplace, newTag, form) { ..... } else { var replaceItem = myfaces._impl._util._Utils.findHtmlItemFromFragment(fragment, item.id); if (replaceItem == null) { replaceItem = fragment } evalNode = item.parentNode.replaceChild(replaceItem, item); } .... } fix: orginal: myfaces._impl._util._Utils.replaceHtmlItem = function (request, context, itemIdToReplace, newTag, form) { ..... } else { var replaceItem = myfaces._impl._util._Utils.findHtmlItemFromFragment(fragment, item.id); if (replaceItem == null) { replaceItem = fragment } evalNode = item.parentNode.replaceChild(replaceItem, item); evalNode = replaceItem; } .... }
        Hide
        Mark Li added a comment - - edited

        2. on IE6 the problem will not be fixed.

        orginal:
        myfaces._impl._util._Utils.replaceHtmlItem = function (request, context, itemIdToReplace, newTag, form)

        { ............. } else {
        item.insertAdjacentHTML("beforeBegin", newTag);
        evalNode = item.previousSibling;
        item.parentNode.removeChild(item);
        if (item.id != "myfaces_bodyplaceholder" && ("undefined" == typeof evalNode.id || null == evalNode.id || evalNode.id != item.id)) { var subNode = document.getElementById(item.id); subNode.parentNode.removeChild(subNode); evalNode.parentNode.replaceChild(subNode, evalNode) }
        }
        ................
        }

        fix:
        myfaces._impl._util._Utils.replaceHtmlItem = function (request, context, itemIdToReplace, newTag, form) { ............. }

        else {
        //start
        var tmpElement = document.createElement("div");
        tmpElement.innerHTML = newTag;
        var replaceItem = myfaces._impl._util._Utils.findHtmlItemFromFragment(tmpElement, item.id);
        if(replaceItem != null)

        { item.parentNode.insertBefore(replaceItem, item); item.parentNode.removeChild(item); evalNode = replaceItem; }

        else

        { //end item.insertAdjacentHTML("beforeBegin", newTag); evalNode = item.previousSibling; item.parentNode.removeChild(item); }

        if (item.id != "myfaces_bodyplaceholder" && ("undefined" == typeof evalNode.id || null == evalNode.id || evalNode.id != item.id))

        { var subNode = document.getElementById(item.id); subNode.parentNode.removeChild(subNode); evalNode.parentNode.replaceChild(subNode, evalNode) }

        }
        ................
        }

        Show
        Mark Li added a comment - - edited 2. on IE6 the problem will not be fixed. orginal: myfaces._impl._util._Utils.replaceHtmlItem = function (request, context, itemIdToReplace, newTag, form) { ............. } else { item.insertAdjacentHTML("beforeBegin", newTag); evalNode = item.previousSibling; item.parentNode.removeChild(item); if (item.id != "myfaces_bodyplaceholder" && ("undefined" == typeof evalNode.id || null == evalNode.id || evalNode.id != item.id)) { var subNode = document.getElementById(item.id); subNode.parentNode.removeChild(subNode); evalNode.parentNode.replaceChild(subNode, evalNode) } } ................ } fix: myfaces._impl._util._Utils.replaceHtmlItem = function (request, context, itemIdToReplace, newTag, form) { ............. } else { //start var tmpElement = document.createElement("div"); tmpElement.innerHTML = newTag; var replaceItem = myfaces._impl._util._Utils.findHtmlItemFromFragment(tmpElement, item.id); if(replaceItem != null) { item.parentNode.insertBefore(replaceItem, item); item.parentNode.removeChild(item); evalNode = replaceItem; } else { //end item.insertAdjacentHTML("beforeBegin", newTag); evalNode = item.previousSibling; item.parentNode.removeChild(item); } if (item.id != "myfaces_bodyplaceholder" && ("undefined" == typeof evalNode.id || null == evalNode.id || evalNode.id != item.id)) { var subNode = document.getElementById(item.id); subNode.parentNode.removeChild(subNode); evalNode.parentNode.replaceChild(subNode, evalNode) } } ................ }
        Hide
        Mark Li added a comment -

        3、a bug about _Utils.findHtmlItemFromFragment

        orginal:
        myfaces._impl._util._Utils.findHtmlItemFromFragment = function (fragment, itemId) {
        ...........
        if (fragment.childNodes.length == 1 && fragment.childNodes[0].id == itemId)

        { return fragment; }

        .............
        };

        fix:
        myfaces._impl._util._Utils.findHtmlItemFromFragment = function (fragment, itemId) {
        ...........
        if (fragment.childNodes.length == 1 && fragment.childNodes[0].id == itemId)

        { return fragment.childNodes[0]; }

        .............
        };

        Show
        Mark Li added a comment - 3、a bug about _Utils.findHtmlItemFromFragment orginal: myfaces._impl._util._Utils.findHtmlItemFromFragment = function (fragment, itemId) { ........... if (fragment.childNodes.length == 1 && fragment.childNodes [0] .id == itemId) { return fragment; } ............. }; fix: myfaces._impl._util._Utils.findHtmlItemFromFragment = function (fragment, itemId) { ........... if (fragment.childNodes.length == 1 && fragment.childNodes [0] .id == itemId) { return fragment.childNodes[0]; } ............. };
        Hide
        Mark Li added a comment - - edited

        4、fuzzyform will find the correct form element instance. i didnt read your code carefully, just write an alternative. sorry for this.

        orignal:
        myfaces._impl._util._Utils.fuzzyFormDetection = function (request, context, element)

        { ......... }

        fix:
        myfaces._impl._util._Utils.fuzzyFormDetection = function (request, context, element) {
        var sourceForm1 = myfaces._impl._util._Utils.getParent(null, context, element, "form");
        if (sourceForm1 == null)

        { alert("source form is null: " + context.source.id); }

        else {
        for (var i = 0; i < document.forms.length; i++)

        { f = document.forms[i]; if (f.id == sourceForm1.id) sourceForm = f; }

        }
        return sourceForm1;
        }

        Show
        Mark Li added a comment - - edited 4、fuzzyform will find the correct form element instance. i didnt read your code carefully, just write an alternative. sorry for this. orignal: myfaces._impl._util._Utils.fuzzyFormDetection = function (request, context, element) { ......... } fix: myfaces._impl._util._Utils.fuzzyFormDetection = function (request, context, element) { var sourceForm1 = myfaces._impl._util._Utils.getParent(null, context, element, "form"); if (sourceForm1 == null) { alert("source form is null: " + context.source.id); } else { for (var i = 0; i < document.forms.length; i++) { f = document.forms[i]; if (f.id == sourceForm1.id) sourceForm = f; } } return sourceForm1; }
        Hide
        Mark Li added a comment -

        1、html element is dirty.

        oringal
        myfaces._impl._util._Utils.getParent = function (request, context, item, tagNameToSearchFor) {
        try {
        if ("undefined" == typeof item || null == item)

        { throw Error("myfaces._impl._util._Utils.getParen: item is null or undefined,this not allowed") }

        var parentItem = ("undefined" != typeof item.parentNode) ? item.parentNode : null;
        if ("undefined" != typeof item.tagName && null != item.tagName && item.tagName.toLowerCase() == tagNameToSearchFor)

        { return item }
        while (parentItem != null && parentItem.tagName.toLowerCase() != tagNameToSearchFor) { parentItem = parentItem.parentNode }
        ..........
        };

        fix:

        myfaces._impl._util._Utils.getParent = function (request, context, item, tagNameToSearchFor) {
        try {
        if ("undefined" == typeof item || null == item) { throw Error("myfaces._impl._util._Utils.getParen: item is null or undefined,this not allowed") }
        ////////////// start write by mark
        if (item.id != null && item.id != '') item = document.getElementById(item.id);
        ////////////// end write by mark

        var parentItem = ("undefined" != typeof item.parentNode) ? item.parentNode : null;
        if ("undefined" != typeof item.tagName && null != item.tagName && item.tagName.toLowerCase() == tagNameToSearchFor) { return item }

        while (parentItem != null && parentItem.tagName.toLowerCase() != tagNameToSearchFor) {
        ////////////// start write by mark
        if (parentItem.id != null && parentItem.id != "")

        { parentItem = document.getElementById(parentItem.id); }

        ////////////// end write by mark
        parentItem = parentItem.parentNode
        }
        ...................
        };

        Show
        Mark Li added a comment - 1、html element is dirty. oringal myfaces._impl._util._Utils.getParent = function (request, context, item, tagNameToSearchFor) { try { if ("undefined" == typeof item || null == item) { throw Error("myfaces._impl._util._Utils.getParen: item is null or undefined,this not allowed") } var parentItem = ("undefined" != typeof item.parentNode) ? item.parentNode : null; if ("undefined" != typeof item.tagName && null != item.tagName && item.tagName.toLowerCase() == tagNameToSearchFor) { return item } while (parentItem != null && parentItem.tagName.toLowerCase() != tagNameToSearchFor) { parentItem = parentItem.parentNode } .......... }; fix: myfaces._impl._util._Utils.getParent = function (request, context, item, tagNameToSearchFor) { try { if ("undefined" == typeof item || null == item) { throw Error("myfaces._impl._util._Utils.getParen: item is null or undefined,this not allowed") } ////////////// start write by mark if (item.id != null && item.id != '') item = document.getElementById(item.id); ////////////// end write by mark var parentItem = ("undefined" != typeof item.parentNode) ? item.parentNode : null; if ("undefined" != typeof item.tagName && null != item.tagName && item.tagName.toLowerCase() == tagNameToSearchFor) { return item } while (parentItem != null && parentItem.tagName.toLowerCase() != tagNameToSearchFor) { ////////////// start write by mark if (parentItem.id != null && parentItem.id != "") { parentItem = document.getElementById(parentItem.id); } ////////////// end write by mark parentItem = parentItem.parentNode } ................... };
        Hide
        Mark Li added a comment - - edited

        thats all!
        and further discussing, should myfaces support 'fuzzy element id' ajax execute?
        like:
        <h:form id="f">
        <h:inputText id="a" />
        </h:form>
        javascript like:
        jsf.ajax.request(this,event,

        {execute:'a'}

        );
        not
        jsf.ajax.request(this,event,

        {execute:'f:a'}

        );

        i add my owner code to support this, but its complex, and will involve rending certain component in every pages, so i dont recommend it.

        Show
        Mark Li added a comment - - edited thats all! and further discussing, should myfaces support 'fuzzy element id' ajax execute? like: <h:form id="f"> <h:inputText id="a" /> </h:form> javascript like: jsf.ajax.request(this,event, {execute:'a'} ); not jsf.ajax.request(this,event, {execute:'f:a'} ); i add my owner code to support this, but its complex, and will involve rending certain component in every pages, so i dont recommend it.
        Hide
        Werner Punz added a comment - - edited

        Hello Mark thanks for all your code and suggestions

        First I will check your changes and fixes and mergen them in, but give me a few days to process them.
        (probably monday or tuesday I will have time to do this, have in mind I am doing this in my non customer related time)

        First again to your fixes, I have yet to check them, but it seems to me that
        it still is the problem you reported in the beginning, again as I said in the eg, wrap your elements
        in a root node with the identifier of your client id, that ensures your components will work on both
        myfaces and mojarra in the PPR case. You cannot really fix the problem entirely
        on javascript level within the impl, this is a problem of not having full control over the rendering behavior on the spec side
        by forcing the components in an update cycle before even opening the rendering.
        So I can say, it is better to follow the recommendations of the EG than to try to doctor within the specifics of
        one impl, which then might break the compatibility to the other in your code.

        The only way to solve this over all platforms in a clean manner is simply, wrap your components into a root element
        with the identifier of your clientId.

        I can give you more details on how the rendering behavior works:
        ppr request comes in for render:

        {id1}

        automated server processing happens
        the server issues a <update id="id1">
        and then goes into the component to tell it to render itself!
        so the component then renders its code
        after that the server says </update>

        what then happens is following response:

        <update="id">
        <[[CDATA
        <div id="id1">
        mycomponent code inputs etc...
        </div>
        ]]>
        </update>

        so what happens now is simply if you do not wrap it into a root node or the user does not by issuing an encapsulating element, the update happens on id1 and replaces it with several fragments

        <update="id1">
        <[[CDATA
        <div id="id2">
        <div id="id1">
        </div>
        <div id="id3">
        </div>
        </div>
        ]]>
        </update>

        so what happens now is you get following html

        <div id="id2">
        <div id="id1">
        </div>
        <div id="id3">
        </div>
        </div>

        and at the next request

        <div id="id2">
        <div id="id2">
        <div id="id1">
        </div>
        <div id="id3">
        </div>
        </div>
        <div id="id3">
        </div>
        </div>

        Which is clearly broken html.

        You can deal to some degree with the problem on javascript level, but you cannot cover all usecases without breaking the component of someone else doing the same thing in a different combination and functionality.

        And in the end doing it that way revealed after testing you will get problems on mojarra and myfaces.
        (Mojarra even more than MyFaces after my latest fixes).

        This problem as I said can only be fixed entirely on spec level, by allowing a path to the component authors
        which gives them full control over the ppr rendering process.
        (I filed an issue for that)

        So again, it comes down to follow a certain pattern in your component design process to be clean

        I also cannot recommend to rely on specifics within myfaces, you will definitely break compatibiltiy to Mojarra.
        always render something along the lines of:
        <update="id1">
        <[[CDATA
        <div id="id1">

        </div>
        ]]>
        </update>

        not
        <update="id1">
        <[[CDATA
        <div id="id2">

        </div>
        <div id="id1">
        </div>
        ]]>
        </update>

        As I said this is not by me, this is an official recommendation from the EG after I was querying them regarding this issue. I also filed a bug and a proposal to fix this problem on spec level, but that will take some time to get it resolved.

        As for the second request fuzzy identifier handling:

        Myfaces can only support what the spec gives and what the spec clearly not breaks, eg. Extensions are possible but not totally different behavior.
        A fuzzy element execute or render on javascript level is a definitive no go.
        But for such cases you can use libraries like jquery or dojo query which support things like that

        I will give you some pseudo code (dojo query, since I am more familiar with that one):
        var executeList = dojo.query("#*myId");
        var identifiers = [];
        for(var cnt = 0; cnt <executeList.length; cnt++

        { identifiers.push(executeList[cnt].id) }

        return executeList.join(" ");

        This is pseudo code, I am not sure if I got the query right, but you get the idea,
        as I said for the request and response object I am bound to the spec, I cannot extend
        it for fuzzy elements within execute and render on the official api level.

        Show
        Werner Punz added a comment - - edited Hello Mark thanks for all your code and suggestions First I will check your changes and fixes and mergen them in, but give me a few days to process them. (probably monday or tuesday I will have time to do this, have in mind I am doing this in my non customer related time) First again to your fixes, I have yet to check them, but it seems to me that it still is the problem you reported in the beginning, again as I said in the eg, wrap your elements in a root node with the identifier of your client id, that ensures your components will work on both myfaces and mojarra in the PPR case. You cannot really fix the problem entirely on javascript level within the impl, this is a problem of not having full control over the rendering behavior on the spec side by forcing the components in an update cycle before even opening the rendering. So I can say, it is better to follow the recommendations of the EG than to try to doctor within the specifics of one impl, which then might break the compatibility to the other in your code. The only way to solve this over all platforms in a clean manner is simply, wrap your components into a root element with the identifier of your clientId. I can give you more details on how the rendering behavior works: ppr request comes in for render: {id1} automated server processing happens the server issues a <update id="id1"> and then goes into the component to tell it to render itself! so the component then renders its code after that the server says </update> what then happens is following response: <update="id"> <[[CDATA <div id="id1"> mycomponent code inputs etc... </div> ]]> </update> so what happens now is simply if you do not wrap it into a root node or the user does not by issuing an encapsulating element, the update happens on id1 and replaces it with several fragments <update="id1"> <[[CDATA <div id="id2"> <div id="id1"> </div> <div id="id3"> </div> </div> ]]> </update> so what happens now is you get following html <div id="id2"> <div id="id1"> </div> <div id="id3"> </div> </div> and at the next request <div id="id2"> <div id="id2"> <div id="id1"> </div> <div id="id3"> </div> </div> <div id="id3"> </div> </div> Which is clearly broken html. You can deal to some degree with the problem on javascript level, but you cannot cover all usecases without breaking the component of someone else doing the same thing in a different combination and functionality. And in the end doing it that way revealed after testing you will get problems on mojarra and myfaces. (Mojarra even more than MyFaces after my latest fixes). This problem as I said can only be fixed entirely on spec level, by allowing a path to the component authors which gives them full control over the ppr rendering process. (I filed an issue for that) So again, it comes down to follow a certain pattern in your component design process to be clean I also cannot recommend to rely on specifics within myfaces, you will definitely break compatibiltiy to Mojarra. always render something along the lines of: <update="id1"> <[[CDATA <div id="id1"> </div> ]]> </update> not <update="id1"> <[[CDATA <div id="id2"> </div> <div id="id1"> </div> ]]> </update> As I said this is not by me, this is an official recommendation from the EG after I was querying them regarding this issue. I also filed a bug and a proposal to fix this problem on spec level, but that will take some time to get it resolved. As for the second request fuzzy identifier handling: Myfaces can only support what the spec gives and what the spec clearly not breaks, eg. Extensions are possible but not totally different behavior. A fuzzy element execute or render on javascript level is a definitive no go. But for such cases you can use libraries like jquery or dojo query which support things like that I will give you some pseudo code (dojo query, since I am more familiar with that one): var executeList = dojo.query("#*myId"); var identifiers = []; for(var cnt = 0; cnt <executeList.length; cnt++ { identifiers.push(executeList[cnt].id) } return executeList.join(" "); This is pseudo code, I am not sure if I got the query right, but you get the idea, as I said for the request and response object I am bound to the spec, I cannot extend it for fuzzy elements within execute and render on the official api level.
        Hide
        Werner Punz added a comment - - edited

        Btw. also afair, the recommendation of one of the EG members was not to doctor around here to identify where the child is and omit the wrapping code,
        or make other assumptoons, but to throw clearly an error in this case. While I have not followed this approach the implementations might head into this direction in the long run.
        So design the components as clean as possible.

        http://www.mail-archive.com/jsr-314-open@jcp.org/msg00003.html

        Show
        Werner Punz added a comment - - edited Btw. also afair, the recommendation of one of the EG members was not to doctor around here to identify where the child is and omit the wrapping code, or make other assumptoons, but to throw clearly an error in this case. While I have not followed this approach the implementations might head into this direction in the long run. So design the components as clean as possible. http://www.mail-archive.com/jsr-314-open@jcp.org/msg00003.html
        Hide
        Ganesh Jung added a comment -

        Probably it's the responsability of the component authors here that 1 component always maps to 1 root DOM node with 1 id. Everything else will result in a bunch of problems and teh restriction is not too bad, I think.

        Show
        Ganesh Jung added a comment - Probably it's the responsability of the component authors here that 1 component always maps to 1 root DOM node with 1 id. Everything else will result in a bunch of problems and teh restriction is not too bad, I think.
        Hide
        Ganesh Jung added a comment -

        concerning jsf.ajax.request(this,event,

        {execute:'a'}

        ):

        The jsf.ajax.request API is pure javascript. I don't think it's a good idea to mingle with JSF component ids here. If you component ids why not put a hidden button with nested f:ajax and call the button's onclick?

        Best regards,
        Ganesh

        Show
        Ganesh Jung added a comment - concerning jsf.ajax.request(this,event, {execute:'a'} ): The jsf.ajax.request API is pure javascript. I don't think it's a good idea to mingle with JSF component ids here. If you component ids why not put a hidden button with nested f:ajax and call the button's onclick? Best regards, Ganesh
        Hide
        Werner Punz added a comment -

        Ok the findHtmlItem has a bug.

        But back to the general problem I have to probably revert the behavior, to the recommendation of the expert group.
        The reason simply is, that the spec clearly says, that the entire content has to be replaced, some fixup code is not really possible here.

        The "update" element enables DOM elements matching the "id"
        attribute to be updated with the contents of this element.
        Page 438

        <xsd:complexType name="partial-response-updateType">
        <xsd:annotation>
        <xsd:documentation>
        The "update" element enables DOM elements matching the "id"
        attribute to be updated with the contents of this element.
        </xsd:documentation>

        Which means the entire content not just cherry picking something.
        So I have to revert it to the original behavior without find html element.
        The issue with cherry picking the way you want it is also this will not work consitently over all browsers,
        because you do not get a consistent eval behavior.

        So my fix is, not to fix it but to put this into wontfix/invalid since the Expert Group is clear in this area as well as
        the spec, everything has to be updated!

        So all I can for now say is adjust simply your code to something like

        <div id="clientId">
        <input id="clientId:secondIdentifier">
        </div>

        and you are on the save side for all cases and the future

        Show
        Werner Punz added a comment - Ok the findHtmlItem has a bug. But back to the general problem I have to probably revert the behavior, to the recommendation of the expert group. The reason simply is, that the spec clearly says, that the entire content has to be replaced, some fixup code is not really possible here. The "update" element enables DOM elements matching the "id" attribute to be updated with the contents of this element. Page 438 <xsd:complexType name="partial-response-updateType"> <xsd:annotation> <xsd:documentation> The "update" element enables DOM elements matching the "id" attribute to be updated with the contents of this element. </xsd:documentation> Which means the entire content not just cherry picking something. So I have to revert it to the original behavior without find html element. The issue with cherry picking the way you want it is also this will not work consitently over all browsers, because you do not get a consistent eval behavior. So my fix is, not to fix it but to put this into wontfix/invalid since the Expert Group is clear in this area as well as the spec, everything has to be updated! So all I can for now say is adjust simply your code to something like <div id="clientId"> <input id="clientId:secondIdentifier"> </div> and you are on the save side for all cases and the future
        Hide
        Werner Punz added a comment -

        Please for a check why this is the expected behavior for JSF 2.0 see

        http://www.mail-archive.com/jsr-314-open@jcp.org/msg00010.html

        And also what you can do about it is simply you can embed your element into a wrapping element with the identifier of clientId!

        Also for further reference please check the detailed comments in this thread. Every change from the structure the EG has proposed in the mail thread above will cause mojarra to fail on IE6 and myfaces to fail as well.

        Also why this bug is invalid please check the section in the spec dealing with the update cycle!
        <xsd:complexType name="partial-response-updateType">
        <xsd:annotation>
        <xsd:documentation>
        The "update" element enables DOM elements matching the "id"
        attribute to be updated with the contents of this element.
        </xsd:documentation>
        </xsd:annotation>
        <xsd:simpleContent>
        <xsd:extension base="xsd:string">
        <xsd:attribute name="id" type="xsd:string" use="required"/>
        </xsd:extension>
        </xsd:simpleContent>
        </xsd:complexType>

        which to me is a full replacement of what update sends!
        Hence I am reverting my update changes now, but the new find code is helpful
        so I will leave it in.

        Show
        Werner Punz added a comment - Please for a check why this is the expected behavior for JSF 2.0 see http://www.mail-archive.com/jsr-314-open@jcp.org/msg00010.html And also what you can do about it is simply you can embed your element into a wrapping element with the identifier of clientId! Also for further reference please check the detailed comments in this thread. Every change from the structure the EG has proposed in the mail thread above will cause mojarra to fail on IE6 and myfaces to fail as well. Also why this bug is invalid please check the section in the spec dealing with the update cycle! <xsd:complexType name="partial-response-updateType"> <xsd:annotation> <xsd:documentation> The "update" element enables DOM elements matching the "id" attribute to be updated with the contents of this element. </xsd:documentation> </xsd:annotation> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute name="id" type="xsd:string" use="required"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> which to me is a full replacement of what update sends! Hence I am reverting my update changes now, but the new find code is helpful so I will leave it in.
        Hide
        Mark Li added a comment -

        you are right, I am just fixing some problem from practice, not concerning the specification. I will check the specification later, maybe them have other view of ajax replacement.

        (totally following a specification is a very hard work (sometime its impossible ), I understand your situation.)

        in fact, I would like to extend uicomponents and renderers, not scratch everything from beginning. it will speed up the development process.

        Show
        Mark Li added a comment - you are right, I am just fixing some problem from practice, not concerning the specification. I will check the specification later, maybe them have other view of ajax replacement. (totally following a specification is a very hard work (sometime its impossible ), I understand your situation.) in fact, I would like to extend uicomponents and renderers, not scratch everything from beginning. it will speed up the development process.
        Hide
        Mark Li added a comment - - edited

        yes, a well designed component should always be wrapped into a root element.

        but sometime it is difficult to put everything in one root element, in fact, I find this problem when I use my own component a float div. I use jQuery, I want to use simple component like

        component:
        <lxht:component >
        <div id="#

        {clientId}">
        <div><lxht:insert/></div>
        <script>
        jQuery(document.getElementById('#{clientId}

        ')).dialog(

        {autoOpen:false}

        );
        </script>
        </div>
        </lxht:component>

        jsf:

        <lxhs:test id="a">
        <h:form>
        <h:inputText value="#

        {TestBean.value}

        "></h:inputText>
        <lxhs:commandButton ajaxExecute="@form" ajaxRender="a"/>
        </h:form>
        </lxhs:test>
        <input type="button" value="show dialog" onclick="jQuery(document.getElementById('a')).dialog('open');"/>

        when open the dialog, rend the dialog will casue display problem.

        I think well-formated html doesnt mean a lot.
        html is old, writing html/ javascript which can run everywhere is very difficult.

        if we just treat html as some text not xml, life will become easier.

        Show
        Mark Li added a comment - - edited yes, a well designed component should always be wrapped into a root element. but sometime it is difficult to put everything in one root element, in fact, I find this problem when I use my own component a float div. I use jQuery, I want to use simple component like component: <lxht:component > <div id="# {clientId}"> <div><lxht:insert/></div> <script> jQuery(document.getElementById('#{clientId} ')).dialog( {autoOpen:false} ); </script> </div> </lxht:component> jsf: <lxhs:test id="a"> <h:form> <h:inputText value="# {TestBean.value} "></h:inputText> <lxhs:commandButton ajaxExecute="@form" ajaxRender="a"/> </h:form> </lxhs:test> <input type="button" value="show dialog" onclick="jQuery(document.getElementById('a')).dialog('open');"/> when open the dialog, rend the dialog will casue display problem. I think well-formated html doesnt mean a lot. html is old, writing html/ javascript which can run everywhere is very difficult. if we just treat html as some text not xml, life will become easier.
        Hide
        Werner Punz added a comment -

        This is an entirely different issue here what we are dealing with is heavy dom manipulation on the side of jquery.
        Which means we have to resolve that from jqueries side as well.

        The dialog is the nastiest of all components (well the html editor is equally nasty).
        The reason for this is, that html dialogs usually are done following way:

        Rip the source for the dialog out of any element in existence, put it directly underneath your
        document dom node, so that position absolute works over all browsers in an absolute way.
        To the worse the original element will be heavily decorated by other constructs which resemble the dialog controls)
        (You can easily see that if you open firebug, the original span is shifted to the document node and outside of the form and everything is decorated)

        So what we have here is a nasty detachment issue, which is not fixable on the jsf.js side but instead has to be fixed outside of it, to the worse, every javascript complib does all this slightly different so there is no generic cleanup way, but if we stay on the jquery side there is a working solution to your problem:

        <h:commandLink id="button2" onclick="$('#myDialog').dialog('destroy');$('#myDialog').remove(); jsf.ajax.request(this,event,

        {execute:'@this', render:'myDialog_placeHolder'}

        ); return false;" action="#

        {myBean2.doSearch}

        " value="press me for next ajax"
        >
        </h:commandLink>

        <h:panelGroup id="myDialog_placeHolder">
        <h:panelGroup styleClass="myDlg" id="myDialog">
        <h:panelGroup id="content">
        #

        {myBean2.refresh}

        </h:panelGroup>

        </h:panelGroup>
        <script type="text/javascript">
        /**

        • we delay the dialog buildup slightly
        • that way everything should be updated in the dom
          */
          $("#myDialog").dialog();
          </script>
          </h:panelGroup>

        So what we do here is following, we wrap the dialog into an element with a fixed identifier (dependend on our client id, that element never will be changed and is the placeholder for future updates.
        Then we let jquery do the work on the dialog, which will automatically end outside of the form (be careful if you put input elements into the dialog this will fail unless you wrap a form into it)

        And then before issuing the ppr update we clear the dialog and kill the detached element, after that jsf.ajax can perform its part cleanly.

        Alternatively you can make a listener over the jsf.ajax event queue to see which elements get rendered before or shortly after the request and then do the element killing there.

        Sorry for having this so complicated but this is really an issue which is not solvable within the scope of jsf.ajax.

        The only bug in all this is, that the jquery $('#myDialog').dialog('destroy'); does not restore the dom node in its original position but leaves it in the new one, (this is a severe bug if you ask me) hence we have to issue
        a following $('#myDialog').remove(); to clean up the dom tree properly. This definitely has to be sent to the jquery guys!

        Show
        Werner Punz added a comment - This is an entirely different issue here what we are dealing with is heavy dom manipulation on the side of jquery. Which means we have to resolve that from jqueries side as well. The dialog is the nastiest of all components (well the html editor is equally nasty). The reason for this is, that html dialogs usually are done following way: Rip the source for the dialog out of any element in existence, put it directly underneath your document dom node, so that position absolute works over all browsers in an absolute way. To the worse the original element will be heavily decorated by other constructs which resemble the dialog controls) (You can easily see that if you open firebug, the original span is shifted to the document node and outside of the form and everything is decorated) So what we have here is a nasty detachment issue, which is not fixable on the jsf.js side but instead has to be fixed outside of it, to the worse, every javascript complib does all this slightly different so there is no generic cleanup way, but if we stay on the jquery side there is a working solution to your problem: <h:commandLink id="button2" onclick="$('#myDialog').dialog('destroy');$('#myDialog').remove(); jsf.ajax.request(this,event, {execute:'@this', render:'myDialog_placeHolder'} ); return false;" action="# {myBean2.doSearch} " value="press me for next ajax" > </h:commandLink> <h:panelGroup id="myDialog_placeHolder"> <h:panelGroup styleClass="myDlg" id="myDialog"> <h:panelGroup id="content"> # {myBean2.refresh} </h:panelGroup> </h:panelGroup> <script type="text/javascript"> /** we delay the dialog buildup slightly that way everything should be updated in the dom */ $("#myDialog").dialog(); </script> </h:panelGroup> So what we do here is following, we wrap the dialog into an element with a fixed identifier (dependend on our client id, that element never will be changed and is the placeholder for future updates. Then we let jquery do the work on the dialog, which will automatically end outside of the form (be careful if you put input elements into the dialog this will fail unless you wrap a form into it) And then before issuing the ppr update we clear the dialog and kill the detached element, after that jsf.ajax can perform its part cleanly. Alternatively you can make a listener over the jsf.ajax event queue to see which elements get rendered before or shortly after the request and then do the element killing there. Sorry for having this so complicated but this is really an issue which is not solvable within the scope of jsf.ajax. The only bug in all this is, that the jquery $('#myDialog').dialog('destroy'); does not restore the dom node in its original position but leaves it in the new one, (this is a severe bug if you ask me) hence we have to issue a following $('#myDialog').remove(); to clean up the dom tree properly. This definitely has to be sent to the jquery guys!
        Hide
        Werner Punz added a comment -

        Btw. just another additional comment, there is already a complib utiizing jquery, the yui widgets and others, that is primefaces, so there is no real need to doctor too much on that level for normal usecases.

        Show
        Werner Punz added a comment - Btw. just another additional comment, there is already a complib utiizing jquery, the yui widgets and others, that is primefaces, so there is no real need to doctor too much on that level for normal usecases.
        Hide
        Mark Li added a comment - - edited

        in practice, "<h:panelGroup id="myDialog_placeHolder"> " will not work, because i want to render the content during it display. render these will lead dialog disappear. and $("#myDialog").dialog() should has autopen:false option, use outside html element to show it.

        further, i should explain my code,
        I have my own component composite tools. it is like facelets, lxht:component is like ui:omponent, lxht:insert is like ui:insert, but my tools can run much more faster .

        the example is code for a Test Component,

        <lxht:component >
        <div id="#

        {clientId}">
        <div><lxht:insert/></div>
        <script> $('#{clientId}

        ').dialog(

        {autoOpen:false}

        ); </script>
        </div>
        </lxht:component>

        #clientId is a variable present uicomponent.getClientId(context);

        this will produces html code (if clientid is j_test, sub component children is <h:form>....</h:form> ):

        <div id="j_test" >
        div><h:form>....</h:form></div>
        <script>$('#j_test').dialog(

        {autoOpen:false}

        );</script>
        </div>

        in your code, you use two ui component h:panelGroup, but in my case, i only want to use one, my component 'test'.

        so the code in .jspx file is simpler

        <lxhs:test id="a">
        <h:form>....</h:form>
        </lxhs:test>
        <input type="button" value="show dialog" onclick="jQuery(document.getElementById('a')).dialog('open');"/>

        only one component here, lxhs:test.

        I write some component from scratch, because I want to keep every thing simple. i really like js component framework, i can put a lot thing in one component,

        at first, i use facelets to do this, but after several months use, I find facelets is not good enough for me, heavy component tree, must have client id etc. so I design my own component tools, it just wrap a bunch of html code into one jsf component like the example above. i name it facekit

        I want you understand my thought. keep everything fast, simple,

        therefore i write the custom component test, put every thing in jsf component. keep .jspx file simpler. is that the jsf purpose?

        in the case, the flexible of ajax is very very important, because when you put every thing in ONE component, a lot issues will appear

        further,yes, a well designed component should always be wrapped into a root element. but flexibility somehow is important too.

        a lot of thanks for your patience.

        Show
        Mark Li added a comment - - edited in practice, "<h:panelGroup id="myDialog_placeHolder"> " will not work, because i want to render the content during it display. render these will lead dialog disappear. and $("#myDialog").dialog() should has autopen:false option, use outside html element to show it. further, i should explain my code, I have my own component composite tools. it is like facelets, lxht:component is like ui:omponent, lxht:insert is like ui:insert, but my tools can run much more faster . the example is code for a Test Component, <lxht:component > <div id="# {clientId}"> <div><lxht:insert/></div> <script> $('#{clientId} ').dialog( {autoOpen:false} ); </script> </div> </lxht:component> #clientId is a variable present uicomponent.getClientId(context); this will produces html code (if clientid is j_test, sub component children is <h:form>....</h:form> ): <div id="j_test" > div><h:form>....</h:form></div> <script>$('#j_test').dialog( {autoOpen:false} );</script> </div> in your code, you use two ui component h:panelGroup, but in my case, i only want to use one, my component 'test'. so the code in .jspx file is simpler <lxhs:test id="a"> <h:form>....</h:form> </lxhs:test> <input type="button" value="show dialog" onclick="jQuery(document.getElementById('a')).dialog('open');"/> only one component here, lxhs:test. I write some component from scratch, because I want to keep every thing simple. i really like js component framework, i can put a lot thing in one component, at first, i use facelets to do this, but after several months use, I find facelets is not good enough for me, heavy component tree, must have client id etc. so I design my own component tools, it just wrap a bunch of html code into one jsf component like the example above. i name it facekit I want you understand my thought. keep everything fast, simple, therefore i write the custom component test, put every thing in jsf component. keep .jspx file simpler. is that the jsf purpose? in the case, the flexible of ajax is very very important, because when you put every thing in ONE component, a lot issues will appear further,yes, a well designed component should always be wrapped into a root element. but flexibility somehow is important too. a lot of thanks for your patience.
        Hide
        Mark Li added a comment - - edited

        other bug.

        <h:form id="a">
        <h:commandButton action="#

        {TestBean.action}

        " value="submit"/>
        </h:form>

        <h:form>
        <input type="button" value="ajax ReRender" onclick="jsf.ajax.request(this,event,{execute:'@form',render:'a', onevent:function(data){alert(travelObjectString(data))}})"/>
        </h:form>

        after ajax render h:form a, button submit cant work anymore.

        when ajaxrender h:form,
        server returns:

        ,type:event
        ,status:success
        ,source:[object HTMLInputElement]
        ,responseXML:[object Document]
        ,responseText:<?xml version="1.0" encoding="utf-8"?><partial-response><changes><update id="a"><Unable to render embedded object: File (j_id1643039915_61eeccea" name="a:j_id1643039915_61eeccea" type="submit" value="submit" /><input type="hidden" name="a_SUBMIT" value="1" /></form>]]></update><update id="javax.faces.ViewState"><) not found.[CDATA[kHvZEC3xUFrvph58FMXk3M1hmkXeI5frIq4lJC0k89Aes6jXgxar/a87bJnEgK+heJGFPEw2GymAluUJeQj83g==]]></update></changes></partial-response>
        ,responseCode:200

        there is not <input type="hidden" id="javax.faces.ViewState"> inside <form id="a"></form>

        its seems when ViewHandler.writeState(FacesContext context), if(context.getPartialViewContext().isAjaxRequest()) will return directly, Why?

        btw, not find useful stuff in specification (JSF_20090506.pdf)

        Show
        Mark Li added a comment - - edited other bug. <h:form id="a"> <h:commandButton action="# {TestBean.action} " value="submit"/> </h:form> <h:form> <input type="button" value="ajax ReRender" onclick="jsf.ajax.request(this,event,{execute:'@form',render:'a', onevent:function(data){alert(travelObjectString(data))}})"/> </h:form> after ajax render h:form a, button submit cant work anymore. when ajaxrender h:form, server returns: ,type:event ,status:success ,source: [object HTMLInputElement] ,responseXML: [object Document] ,responseText:<?xml version="1.0" encoding="utf-8"?><partial-response><changes><update id="a">< Unable to render embedded object: File (j_id1643039915_61eeccea" name="a:j_id1643039915_61eeccea" type="submit" value="submit" /><input type="hidden" name="a_SUBMIT" value="1" /></form>]]></update><update id="javax.faces.ViewState"><) not found. [CDATA [kHvZEC3xUFrvph58FMXk3M1hmkXeI5frIq4lJC0k89Aes6jXgxar/a87bJnEgK+heJGFPEw2GymAluUJeQj83g==] ]></update></changes></partial-response> ,responseCode:200 there is not <input type="hidden" id="javax.faces.ViewState"> inside <form id="a"></form> its seems when ViewHandler.writeState(FacesContext context), if(context.getPartialViewContext().isAjaxRequest()) will return directly, Why? btw, not find useful stuff in specification (JSF_20090506.pdf)
        Hide
        Werner Punz added a comment - - edited

        As I said before the issue you run into is a problem with jquery, in case of a dialog it rips out your component moves it to the top of the dom tree to have the positioning working via css: position:absolute on all browsers (position fixed which would be the real way to do this does not work on ie6)
        and then decorates it. Alll you can do is to fix all this manually.
        I gave you just a proof of concept, what you can do is to set a listener onevent which removes the decoration.

        jsf.ajax.request(.... onevent:processDialogHandling)

        data.status has the status
        and
        eventData.responseCode has the responseCode

        in Your case you could use the complete method for instance for the cleanup of the elements jquery puts in.

        var processDialogHandling = function processEvent(data) {
        if (data.status == "complete" && data.responseCode>= 200 && data.responseCode < 300)

        { $('#myDialog').dialog('destroy');$('#myDialog').remove(); }


        }

        you can also do this in a more generic manner by having some kind
        of dialog registry in your page and use jsf.ajax.addOnEvent for a global cleanup function.
        the data object has status, responseCode, responseXml and ResponseTxt
        so you can set a marker there upon which your cleanup code can trigger globally
        for instance if you check your responseXml for $('identifier').dialog();
        you can rip out the identifier, do the needed cleanup steps and then let jsf.ajax do its job.

        as for your autoOpen stuff, this is also a matter of providing the needed infrastructure, you have to
        save the open status before the update and then either open your dialog or leave it unopened.
        All this is heavy framework specific which means what you do here will only work in jquery (dojo for instance
        does all this quite differently although the dialog mechanism works similar)

        For instance you can use data.status == "success" for the open handling here in the processEvent method.

        As for the second issue, I will look into it.

        Show
        Werner Punz added a comment - - edited As I said before the issue you run into is a problem with jquery, in case of a dialog it rips out your component moves it to the top of the dom tree to have the positioning working via css: position:absolute on all browsers (position fixed which would be the real way to do this does not work on ie6) and then decorates it. Alll you can do is to fix all this manually. I gave you just a proof of concept, what you can do is to set a listener onevent which removes the decoration. jsf.ajax.request(.... onevent:processDialogHandling) data.status has the status and eventData.responseCode has the responseCode in Your case you could use the complete method for instance for the cleanup of the elements jquery puts in. var processDialogHandling = function processEvent(data) { if (data.status == "complete" && data.responseCode>= 200 && data.responseCode < 300) { $('#myDialog').dialog('destroy');$('#myDialog').remove(); } } you can also do this in a more generic manner by having some kind of dialog registry in your page and use jsf.ajax.addOnEvent for a global cleanup function. the data object has status, responseCode, responseXml and ResponseTxt so you can set a marker there upon which your cleanup code can trigger globally for instance if you check your responseXml for $('identifier').dialog(); you can rip out the identifier, do the needed cleanup steps and then let jsf.ajax do its job. as for your autoOpen stuff, this is also a matter of providing the needed infrastructure, you have to save the open status before the update and then either open your dialog or leave it unopened. All this is heavy framework specific which means what you do here will only work in jquery (dojo for instance does all this quite differently although the dialog mechanism works similar) For instance you can use data.status == "success" for the open handling here in the processEvent method. As for the second issue, I will look into it.
        Hide
        Werner Punz added a comment -

        Hello Mark here is a full example which will showcase how to apply everything

        <h:commandLink id="button2" action="#

        {myBean2.doSearch}

        " value="press me for next ajax">
        <f:ajax execute="@this" render="myDialog_placeHolder" />
        </h:commandLink>

        <h:panelGroup id="myDialog_placeHolder">
        <h:panelGroup styleClass="myDlg" id="myDialog">
        <h:panelGroup id="content">
        #

        {myBean2.refresh}

        </h:panelGroup>

        </h:panelGroup>
        <script type="text/javascript">
        //<![CDATA[
        /**

        • we delay the dialog buildup slightly
        • that way everything should be updated in the dom
          */

        if('undefined' == typeof myDialogInit) {
        //at first rendering add a generic listener for this control
        jsf.ajax.addOnEvent(function (data) {
        if (data.status == "complete" && data.responseCode>= 200 && data.responseCode < 300)

        { this.openStatus = $('#myDialog').dialog('isOpen'); $('#myDialog').dialog('destroy');$('#myDialog').remove(); }

        else if (data.status == "success") {
        if(this.openStatus)

        { $("#myDialog").dialog("open"); }

        }
        });
        var myDialogInit = true;
        }

        $("#myDialog").dialog(

        {autoOpen:false}

        );
        //]]>
        </script>
        </h:panelGroup>

        </h:form>
        <script type="text/javascript">
        $("#myDialog").dialog("open");
        </script>

        What happens is that a listener per dialog is registered once for this specific dialog which takes care over the jquery cleanup process.

        That should resolve your problem, nevertheless you have to be aware that the dialog itself is ripped out of the form which outside of the dialog.

        Show
        Werner Punz added a comment - Hello Mark here is a full example which will showcase how to apply everything <h:commandLink id="button2" action="# {myBean2.doSearch} " value="press me for next ajax"> <f:ajax execute="@this" render="myDialog_placeHolder" /> </h:commandLink> <h:panelGroup id="myDialog_placeHolder"> <h:panelGroup styleClass="myDlg" id="myDialog"> <h:panelGroup id="content"> # {myBean2.refresh} </h:panelGroup> </h:panelGroup> <script type="text/javascript"> //<![CDATA[ /** we delay the dialog buildup slightly that way everything should be updated in the dom */ if('undefined' == typeof myDialogInit) { //at first rendering add a generic listener for this control jsf.ajax.addOnEvent(function (data) { if (data.status == "complete" && data.responseCode>= 200 && data.responseCode < 300) { this.openStatus = $('#myDialog').dialog('isOpen'); $('#myDialog').dialog('destroy');$('#myDialog').remove(); } else if (data.status == "success") { if(this.openStatus) { $("#myDialog").dialog("open"); } } }); var myDialogInit = true; } $("#myDialog").dialog( {autoOpen:false} ); //]]> </script> </h:panelGroup> </h:form> <script type="text/javascript"> $("#myDialog").dialog("open"); </script> What happens is that a listener per dialog is registered once for this specific dialog which takes care over the jquery cleanup process. That should resolve your problem, nevertheless you have to be aware that the dialog itself is ripped out of the form which outside of the dialog.
        Hide
        Werner Punz added a comment - - edited

        Btw. Mark the we should move this discussion over to the myfaces users mailinglist.

        The Jira is the wrong place for this discussion.

        As for the other issue I raised a separate ticket for this one please follow
        https://issues.apache.org/jira/browse/MYFACES-2700

        this is an issue which affects both implementations.
        The main problem with all this is we deal with multiple problems here

        a) Jquery does heavy dom shifting to bypass a problem IE6 has (namely a non working position fixed), that way it breaks the normal JSF form handling because it shifts all controls outside of the parent form.

        b) The workaround is to embed the entire form into the dialog, and then we run into issue b) I will see what I can do to find a way to bypass the problem in a working way for both implementations under MYFACES-2700, I have to double check again the viewstate update specification to see what I can do.

        Show
        Werner Punz added a comment - - edited Btw. Mark the we should move this discussion over to the myfaces users mailinglist. The Jira is the wrong place for this discussion. As for the other issue I raised a separate ticket for this one please follow https://issues.apache.org/jira/browse/MYFACES-2700 this is an issue which affects both implementations. The main problem with all this is we deal with multiple problems here a) Jquery does heavy dom shifting to bypass a problem IE6 has (namely a non working position fixed), that way it breaks the normal JSF form handling because it shifts all controls outside of the parent form. b) The workaround is to embed the entire form into the dialog, and then we run into issue b) I will see what I can do to find a way to bypass the problem in a working way for both implementations under MYFACES-2700 , I have to double check again the viewstate update specification to see what I can do.
        Hide
        Werner Punz added a comment -

        Hey Mark, I am on the ball to get this up and running, the dual form usecase needs a fix on the Spec side (see also https://issues.apache.org/jira/browse/MYFACES-2700 which I opened for this)
        So keep your heads up, I am rather sure we will get this up and running.
        In the meanwhile feel free to discuss this issue further on the users mailinglist, I will monitor it).

        Werner

        Show
        Werner Punz added a comment - Hey Mark, I am on the ball to get this up and running, the dual form usecase needs a fix on the Spec side (see also https://issues.apache.org/jira/browse/MYFACES-2700 which I opened for this) So keep your heads up, I am rather sure we will get this up and running. In the meanwhile feel free to discuss this issue further on the users mailinglist, I will monitor it). Werner
        Hide
        Mark Li added a comment -

        Hey Werner,
        Ok discuss this on the users mailinglist .

        Show
        Mark Li added a comment - Hey Werner, Ok discuss this on the users mailinglist .

          People

          • Assignee:
            Unassigned
            Reporter:
            Mark Li
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Time Tracking

              Estimated:
              Original Estimate - 4h
              4h
              Remaining:
              Remaining Estimate - 4h
              4h
              Logged:
              Time Spent - Not Specified
              Not Specified

                Development