ICEfaces
  1. ICEfaces
  2. ICE-7562

MyFaces: h:selectOneRadio inside ice core:singleSubmit tag throws errors

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 3.0.RC1
    • Fix Version/s: 3.0.RC2, 3.0
    • Component/s: Sample Apps
    • Labels:
      None
    • Environment:
      ICEfaces 3, showcase sample app., MyFaces 2.1.3
    • Assignee Priority:
      P1

      Description

      Using the showcase sample with MyFaces 2.1.3, several demos that use the h:selectOneRadio component can fail with errors:

      ace:menubar:
      Effects:
      Internet Explorer / Firefox: When changing 'Transition Effect' multiple times the radio button becomes unselected and a validation error is seen.
      Haven't seen this myself and couldn't reproduce exactly as described. There were some intermittent client side errors in the console but not on every click:

      [window] configuration not found for INPUT
      [window] configuration not found for INPUT
      [window] Error [status: clientError code: undefined]: undefined
      exception ? console.er...ror(formatOutput(category, message));
      'cannot find enclosing form' when calling method: [nsIDOMEventListener::handleEvent]
      [Break On This Error] originalHandler.handleEvent(event);

      ----------------------------------------------------------

      ace:menu:
      Type:
      Internet Explorer / Firefox: When changing 'Type of Menu' multiple times the radio button becomes unselected and a validation error is seen.
      Haven't seen this myself and couldn't reproduce exactly as described. There were some intermittent client side errors in the console but not on every click:

      [window] configuration not found for INPUT
      [window] configuration not found for INPUT
      [window] Error [status: clientError code: undefined]: undefined
      exception ? console.er...ror(formatOutput(category, message));
      'cannot find enclosing form' when calling method: [nsIDOMEventListener::handleEvent]
      [Break On This Error] originalHandler.handleEvent(event);

      ----------------------------------------------------

      ace:menubar:
      Effects:
      Internet Explorer / Firefox: When changing 'Transition Effect' multiple times the radio button becomes unselected and a validation error is seen.
      Haven't seen this myself and couldn't reproduce exactly as described. There were some intermittent client side errors in the console but not on every click:

      [window] configuration not found for INPUT
      [window] configuration not found for INPUT
      [window] Error [status: clientError code: undefined]: undefined
      exception ? console.er...ror(formatOutput(category, message));
      'cannot find enclosing form' when calling method: [nsIDOMEventListener::handleEvent]
      [Break On This Error] originalHandler.handleEvent(event);

        Activity

        Hide
        Deryk Sinotte added a comment -

        This one is a bit trickier to reproduce. The most reliable method is to use the ace:menubar example, chose the "Type" demo and then click between the radio buttons quickly. It requires that you run with MyFaces and Firefox (or IE). I did not see problems using Mojarra or WebKit browsers.

        With Firefox, using the Firebug JS Debugger, I was able to capture the following:

        serverErrorMessage
        "MyFaces ERROR:Affected Class:myfaces._impl.xhrCore._AjaxRequest Affected Method:send Error Name:undefined Error Name:undefined Error Description:undefined Error Number:undefined Error Line Number:undefined "

        serverErrorName
        "UNKNOWN"

        source
        input#j_id1290760492_491dd227:typeIn:2 sliding

        status
        "clientError"

        type
        "error"

        Show
        Deryk Sinotte added a comment - This one is a bit trickier to reproduce. The most reliable method is to use the ace:menubar example, chose the "Type" demo and then click between the radio buttons quickly. It requires that you run with MyFaces and Firefox (or IE). I did not see problems using Mojarra or WebKit browsers. With Firefox, using the Firebug JS Debugger, I was able to capture the following: serverErrorMessage "MyFaces ERROR:Affected Class:myfaces._impl.xhrCore._AjaxRequest Affected Method:send Error Name:undefined Error Name:undefined Error Description:undefined Error Number:undefined Error Line Number:undefined " serverErrorName "UNKNOWN" source input#j_id1290760492_491dd227:typeIn:2 sliding status "clientError" type "error"
        Hide
        Deryk Sinotte added a comment -

        There seems to be a timing related issue...perhaps with the MyFaces queue...as I can only get this to happen by clicking quickly between radio buttons. When it does happen, it looks like the root issue is the exception "cannot find enclosing form" :

        function enclosingForm(element) {
        return element.form || detect(parents(element), function(e)

        { return tag(e) == 'form'; }

        , function()

        { throw 'cannot find enclosing form'; }

        );
        }

        which is caught by the MyFaces client code when doing the "send" in _AjaxRequest:

        send : function() {
        try

        { //we have to encode at send time, otherwise //we pick up old viewstates this._initRequestParams(); this._startXHR(); this._startTimeout(); }

        catch (e)

        { //_onError//_onError this._onException(this._xhr, this._context, "myfaces._impl.xhrCore._AjaxRequest", "send", e); }

        },

        Show
        Deryk Sinotte added a comment - There seems to be a timing related issue...perhaps with the MyFaces queue...as I can only get this to happen by clicking quickly between radio buttons. When it does happen, it looks like the root issue is the exception "cannot find enclosing form" : function enclosingForm(element) { return element.form || detect(parents(element), function(e) { return tag(e) == 'form'; } , function() { throw 'cannot find enclosing form'; } ); } which is caught by the MyFaces client code when doing the "send" in _AjaxRequest: send : function() { try { //we have to encode at send time, otherwise //we pick up old viewstates this._initRequestParams(); this._startXHR(); this._startTimeout(); } catch (e) { //_onError//_onError this._onException(this._xhr, this._context, "myfaces._impl.xhrCore._AjaxRequest", "send", e); } },
        Hide
        Deryk Sinotte added a comment -

        There seems to be a common thread with the issue in ICE-7456. If I add <f:ajax> to the radio button group, the issue appears to go away.

        Show
        Deryk Sinotte added a comment - There seems to be a common thread with the issue in ICE-7456 . If I add <f:ajax> to the radio button group, the issue appears to go away.
        Hide
        Deryk Sinotte added a comment - - edited

        On Ted's suggestion I took a closer look at the queueing of Ajax requests on the client side. The problem seems to occur when we click fast enough that the second request gets queued. From MyFaces_AjaxRequestQueue

        enqueue : function(request) {
        if (typeof request._delay == "number") {
        this.clearDelayTimeout();
        var _Lang = myfaces._impl._util._Lang;
        this._delayTimeoutId = window.setTimeout(
        _Lang.hitch(this, function()

        { this.clearDelayTimeout(); //lets clear the delay time to enqueue correctly delete request._delay; this.enqueue(request); }

        ), request._delay);
        } else {
        if (this._curReq == null)

        { this._curReq = request; this._curReq.send(); }

        else {

        //Problem seems to occur when the curReq != null causing the subsequent request to be queued

        this._callSuper("enqueue", request);
        if (request._queueSize != this._size)

        { this.setQueueSize(request._queueSize); }

        }
        }
        },

        Where the comment is, the problem only happens when this condition is met. That is, it happens when the second request gets queued.

        Show
        Deryk Sinotte added a comment - - edited On Ted's suggestion I took a closer look at the queueing of Ajax requests on the client side. The problem seems to occur when we click fast enough that the second request gets queued. From MyFaces_AjaxRequestQueue enqueue : function(request) { if (typeof request._delay == "number") { this.clearDelayTimeout(); var _Lang = myfaces._impl._util._Lang; this._delayTimeoutId = window.setTimeout( _Lang.hitch(this, function() { this.clearDelayTimeout(); //lets clear the delay time to enqueue correctly delete request._delay; this.enqueue(request); } ), request._delay); } else { if (this._curReq == null) { this._curReq = request; this._curReq.send(); } else { //Problem seems to occur when the curReq != null causing the subsequent request to be queued this._callSuper("enqueue", request); if (request._queueSize != this._size) { this.setQueueSize(request._queueSize); } } } }, Where the comment is, the problem only happens when this condition is met. That is, it happens when the second request gets queued.
        Hide
        Deryk Sinotte added a comment -

        Behaviour looks similar to that described in http://jira.icefaces.org/browse/ICE-7118, where commandLinks were being handled in a non-Ajax fashion. We created a SystemEventListener to add behaviours to commandLinks so that they would use the appropriate code path in jsf.js. I tried the same approach with the radio buttons but it did not work - I could still reproduce the issue by clicking fast enough.

        The difference is that, with commandLinks, the handlers were being rendered out with different handlers depending on whether f:ajax tags were present or not. This would lead to "full" submit code being run rather than partial submits. However with radio buttons, I don't believe that's the case. They don't have a default, non-Ajax handler and the code begin executed seems to be the proper Ajax requests. The problem seems more likely to involve queueing of the requests (as it only happens if you click quickly) and then trying to process the form associated with the request after it's taken off the queue while the response to the previous request is being processed/applied to the DOM.

        Show
        Deryk Sinotte added a comment - Behaviour looks similar to that described in http://jira.icefaces.org/browse/ICE-7118 , where commandLinks were being handled in a non-Ajax fashion. We created a SystemEventListener to add behaviours to commandLinks so that they would use the appropriate code path in jsf.js. I tried the same approach with the radio buttons but it did not work - I could still reproduce the issue by clicking fast enough. The difference is that, with commandLinks, the handlers were being rendered out with different handlers depending on whether f:ajax tags were present or not. This would lead to "full" submit code being run rather than partial submits. However with radio buttons, I don't believe that's the case. They don't have a default, non-Ajax handler and the code begin executed seems to be the proper Ajax requests. The problem seems more likely to involve queueing of the requests (as it only happens if you click quickly) and then trying to process the form associated with the request after it's taken off the queue while the response to the previous request is being processed/applied to the DOM.
        Hide
        Deryk Sinotte added a comment -

        Attaching screenshots showing MyFaces and Mojarra handling events where it tries to find the enclosing forms for the radio button that has just been clicked.

        Show
        Deryk Sinotte added a comment - Attaching screenshots showing MyFaces and Mojarra handling events where it tries to find the enclosing forms for the radio button that has just been clicked.
        Hide
        Deryk Sinotte added a comment -

        The attached screenshots show differences in the logic for find the enclosing form of the component that triggered the event. I added some logging to application.js in the filterICEfacesEvents function.

        function filterICEfacesEvents(f) {
        var isICEfacesEvent = false;
        return function(e) {
        try {
        var source = e.source;
        //Logging goes here
        var form = formOf(source);
        if (form.id)

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

        isICEfacesEvent = form['ice.view'] || form['ice.window'];
        } catch (ex)

        { //ignore failure to find forms since that usually occurs after the update is applied }

        //invoke callback only when event is triggered from an ICEfaces enabled form
        if (isICEfacesEvent)

        { f(e); }

        };
        }

        When you click on one of the buttons to change the menu type, the following is dumped to the Firebug console:

        Mojarra:

        filterICEfacesEvents: parent exists for [object HTMLInputElement] with id j_idt98:typeIn:1 [begin - event]
        filterICEfacesEvents: parent exists for [object HTMLInputElement] with id j_idt98:typeIn:1 [complete - event]
        filterICEfacesEvents: parent exists for [object HTMLInputElement] with id j_idt98:typeIn:1 [success - event]

        MyFaces

        filterICEfacesEvents: parent exists for [object HTMLInputElement] with id j_id1290760492_491dd227:typeIn:1 [begin - event]
        filterICEfacesEvents: no parent for [object HTMLInputElement] with id j_id1290760492_491dd227:typeIn:1 [complete - event]
        filterICEfacesEvents: no parent for [object HTMLInputElement] with id j_id1290760492_491dd227:typeIn:1 [success - event]

        Note the decision to ignore any failures to find forms as per ICE-7322.

        //ignore failure to find forms since that usually occurs after the update is applied

        You can see from the logging that after the initial event, the radio button no longer has a parent and this is why we are seeing the client side errors. Under normal usage (ie not clicking fast enough to queue requests), this doesn't seem to cause a problem with MyFaces. However, once a request is queued, when it tries to send the queued request, it's not ignoring the failure to find a form and causing the exceptions we see in the client. It actually doesn't appear to disrupt functionality in any severe way that I can see as you can continue to click the radio buttons and have the page updated.

        Show
        Deryk Sinotte added a comment - The attached screenshots show differences in the logic for find the enclosing form of the component that triggered the event. I added some logging to application.js in the filterICEfacesEvents function. function filterICEfacesEvents(f) { var isICEfacesEvent = false; return function(e) { try { var source = e.source; //Logging goes here var form = formOf(source); if (form.id) { form = document.getElementById(form.id); } isICEfacesEvent = form ['ice.view'] || form ['ice.window'] ; } catch (ex) { //ignore failure to find forms since that usually occurs after the update is applied } //invoke callback only when event is triggered from an ICEfaces enabled form if (isICEfacesEvent) { f(e); } }; } When you click on one of the buttons to change the menu type, the following is dumped to the Firebug console: Mojarra: filterICEfacesEvents: parent exists for [object HTMLInputElement] with id j_idt98:typeIn:1 [begin - event] filterICEfacesEvents: parent exists for [object HTMLInputElement] with id j_idt98:typeIn:1 [complete - event] filterICEfacesEvents: parent exists for [object HTMLInputElement] with id j_idt98:typeIn:1 [success - event] MyFaces filterICEfacesEvents: parent exists for [object HTMLInputElement] with id j_id1290760492_491dd227:typeIn:1 [begin - event] filterICEfacesEvents: no parent for [object HTMLInputElement] with id j_id1290760492_491dd227:typeIn:1 [complete - event] filterICEfacesEvents: no parent for [object HTMLInputElement] with id j_id1290760492_491dd227:typeIn:1 [success - event] Note the decision to ignore any failures to find forms as per ICE-7322. //ignore failure to find forms since that usually occurs after the update is applied You can see from the logging that after the initial event, the radio button no longer has a parent and this is why we are seeing the client side errors. Under normal usage (ie not clicking fast enough to queue requests), this doesn't seem to cause a problem with MyFaces. However, once a request is queued, when it tries to send the queued request, it's not ignoring the failure to find a form and causing the exceptions we see in the client. It actually doesn't appear to disrupt functionality in any severe way that I can see as you can continue to click the radio buttons and have the page updated.
        Hide
        Deryk Sinotte added a comment -

        With some help from Mircea, I've made a change to submit.js where, during singleSubmits, the cloned children of our singleSubmit form are not removed until after the updates have been applied.

        Our singleSubmit form is designed to clone the nodes it needs to do the submission and then remove them when it's done. The exceptions we were seeing were generally due to the radio inputs not being able to find the parent form during certain event broadcasts. The reason is that when MyFaces queued the requests and then sent them, the radio buttons had already been removed from the form and where basically orphans.

        ICEfaces typically catches and ignores the "cannot find form" errors but once the requests were queued, the processing done to take them off the queue and send them would snag on the exception (ie MyFaces wouldn't ignore it and it would propagate to normal JSF client-side error handling).

        The code change allows for the cloned nodes to be removed after the updates have been applied and so don't cause a problem in finding the form. After this change, I'm unable to get the radio buttons to throw the errors when clicking quickly.

        Show
        Deryk Sinotte added a comment - With some help from Mircea, I've made a change to submit.js where, during singleSubmits, the cloned children of our singleSubmit form are not removed until after the updates have been applied. Our singleSubmit form is designed to clone the nodes it needs to do the submission and then remove them when it's done. The exceptions we were seeing were generally due to the radio inputs not being able to find the parent form during certain event broadcasts. The reason is that when MyFaces queued the requests and then sent them, the radio buttons had already been removed from the form and where basically orphans. ICEfaces typically catches and ignores the "cannot find form" errors but once the requests were queued, the processing done to take them off the queue and send them would snag on the exception (ie MyFaces wouldn't ignore it and it would propagate to normal JSF client-side error handling). The code change allows for the cloned nodes to be removed after the updates have been applied and so don't cause a problem in finding the form. After this change, I'm unable to get the radio buttons to throw the errors when clicking quickly.

          People

          • Assignee:
            Deryk Sinotte
            Reporter:
            Ken Fyten
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: