gigaZhang / struts2-jquery

Automatically exported from code.google.com/p/struts2-jquery
0 stars 0 forks source link

Subscribing to event fired by an sj:select breaks because of event reuse in jquery 1.9+. This breaks existing double sj:select where selecting value from one populates the other. #999

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Setup two selects 
      <s:url id="listUrl" action="%{formName}!conditionBuilder" />
      <span id="listOneSpan">
      <sj:select  
            list="list_one" 
            onChangeTopics="reloadListTwo"
            onSuccessTopics="listOneSuccess"
            href="%{listUrl}"  
            id="list_1"
            name="list_1"
            multiple="false"
     />
     </span>
     <span id="listTwoSpan">
     <sj:select  
            list="list_two" 
            reloadTopics="reloadListTwo"
            onSuccessTopics="reloadListTwoSuccess" 
            id="list_2"      
            href="%{listUrl}"     
            name="list_2"     
            emptyOption="false"
            formIds="%{formName}"
     />
     </span>

2. In some other included javascript file have $.subscribe to the event 
populating list 2
$.subscribe('reloadListTwo', function(event, data) {
         window.console.log("reloadListTwo event: "+ event);
         window.console.log("reloadListTwo data: "+ data);
});

3. Change selection of list_one to fire reloadListTwo event

What is the expected output? 
What should happen is when json is returned from server list_two should be 
populated from results as was the case when jquery 1.8.x was in use and 
addtional processing in subscribed function should occur.

What do you see instead?
HIERARCHY_REQUEST_ERR exception stating that you cannot append options to the 
document element.
What is happening is in jquery 1.10.x it tries to reuse the event object and 
does not set Target attribute unless it is null.  So the flow is
$.subscribe('reloadListTwo')...  Sets event.target to the document, which is 
correct for this elementless call.

In jquery.struts2.js.subscribeHandler, the container that has elements appended 
to it is defined by the event target:
 $.subscribeHandler($.struts2_jquery.handler.load, function(event, data) {
     var s2j = $.struts2_jquery,
     container = $(event.target), 
     ...

event.target is only set in first trigger iteration (jquery.1.10.0 trigger, 
line 4972

// Clean up the event in case it is being reused
event.result = undefined;
if ( !event.target ) {
event.target = elem;
} 

So in this cast target is alaways the Document object.  On the second iteration 
event target should be "list_2" for the newly retrieved options to be appended 
to.
Hence code breaks here in jquery.struts2.js (pubSuc method line 361_:
 ...
if (modus === 'select') {
  element = $('<option value="' + option.value + '">' + option.text + '</option>');
  if (option.selected) {
    element.prop("selected", true);
  }
  element.appendTo(c); //c is the [document] element instead of select element so exception is thrown
} 

What version of the product are you using? On what operating system?
Struts2Jquery 3.6
Struts 2.3.14.2
Windoews 7

Please provide any additional information below.
I think a fix would be to insure we always set the target right, appears a 
change needs to happen in jquery.struts2.js#pubSuc() perhaps

Original issue reported on code.google.com by da...@kickflipinc.com on 19 Jun 2013 at 4:02