0

I am facing problems into triggering an ajax call through a hidden command button multiple times inside a javascript loop. Actually The javascript code seems to be executed before the ajax call gets a successful response which has as a result, the value I am processing each time not to be updated before the ajax next request is sent.

Below I am showing an example

.xhtml form code

<h:form id = "jsfform">
  <h:inputHidden id="attributes" value="#{myBean.attributesStr}" />
  <p:commandButton id="button" update="@form" style="display: none"
      ajax="true">
     <f:actionListener binding="#{myBean.bindAttributes()}"/>
  </p:commandButton>
</h:form>

MyBean.java

@ManagedBean(name = "myBean")
@ViewScoped
public class MyBeanimplements Serializable {
   private String attributesStr;
   private List<String> attributes;
   //getters setters ommitted

   public void bindAttributes(){
      this.attributes.add(attributesStr);
   }
}

.js function triggering the button to make the ajax call

var attributes ="";
function ajaxFunction(){
  for(let index = 0; index < 5; index++){
    attributes += "a";
    document.getElementById('jsfform:attributes').value = attributes
    document.getElementById('jsfform:button').onclick(); //trigger the ajax function
  }
}

When I am debugging now, my list seems to have the following values

["a","a","a","a","a"]

while I would like my values to be

["a","aa","aaa","aaaa","aaaaa"]

which is caused by the fact that the value that I am binding from the form to the backend variable through the hidden input field is not updated on time because the javascript code executes the ajax requests in sequence before the first request returns its response.

Which are the workarounds in these cases? Thanks in advance :)

What I have tried

I tried to "disable" the button when it is clicked and "re-enable" it on the complete event of my AJAX call and let javascript waiting for my button to be re-enabled but this led to an endless loop.

<h:form id = "jsfform">
  <h:inputHidden id="attributes" value="#{myBean.attributesStr}" />
  <p:commandButton id="button" update="@form" style="display: none"
      ajax="true" oncomplete="this.disabled = false">
     <f:actionListener binding="#{myBean.bindAttributes()}"/>
  </p:commandButton>
</h:form>

and in javascript waiting for the button to be re-enabled

var attributes ="";
function ajaxFunction(){
  for(let index = 0; index < 5; index++){
    attributes += "a";
    while(true) {
      if(document.getElementById('jsfform:button').disabled == false){
         document.getElementById('jsfform:attributes').value = attributes
         document.getElementById('jsfform:button').onclick(); //trigger the ajax function
         document.getElementById('jsfform:button').disabled = true;
         break;
      }
    }

  }
}
NickAth
  • 1,089
  • 1
  • 14
  • 35
  • Why exactly do you have `update="@form"`? – BalusC Sep 18 '19 at 16:25
  • Hi BalusC, thanks for the interest, well this is not a real example but in my real problem I a updating form since the actual actionlistwner function is updating multiple components of my form, is this related? – NickAth Sep 18 '19 at 16:30
  • 1
    Not per definition. Ultimately you'd better use `` instead https://stackoverflow.com/q/16588327 It supports passing parameters via JS so you don't need to fiddle with hidden inputs. – BalusC Sep 18 '19 at 16:34
  • @BalusC I would need to do a code refactoring to introduce remotecommandbutton, would that fixed my problem? The problem lies on the fact that the JavaScript loops is executed triggering Ajax results in a row before the first is finished, would replacement of commandbutton with remotecommandbutton fix this problem? – NickAth Sep 18 '19 at 16:54
  • I'm curious to your actual usecase. This seems 'fabricated' without a real logical business function. And no, `p:remoteCommand` as such won't solve your problem. you'd need to do some 'blocking' with the ajax onstart amd oncomplete to make it synchronous but again, the real usecase would help – Kukeltje Sep 18 '19 at 18:49
  • Hi @Kukeltje, ok my usecase in a "simplified" form is the following: 1) I am loading a zip of json files through an html button 2) These json files get unzipped and parsed each one separately 3) Each JSON is processed by my javascript code to do some work on the frontend of my application. 4) `I am "binding" each json (a list of custom objects) into a backend Java list of custom objects back to my bean` through this ajax call 5) I have a loop for each json file that should store the json into a hidden value, call the backend function to bind it to the list through ajax and store them – NickAth Sep 18 '19 at 19:52
  • I hope I made my point clear :) , thanks – NickAth Sep 18 '19 at 19:54
  • Yes a I think I sort of understand and honestly, very weird design... especially all seems to be fully automagic in a loop. Why not process them on the server? – Kukeltje Sep 19 '19 at 05:47
  • The main purpose of the json file is to be parsed by the JavaScript code and set things on the frontend part, I am just “keeping” the frontend info in the backend by binding the list of JavaScript objects into a list of backend java objects to render them through primefaces – NickAth Sep 19 '19 at 07:38
  • Well I managed to solve my problem by using the "async" property (`async = "true"`) on p:ajax so that my continuous requests are not queued :) I do not really see any better way to solve this – NickAth Sep 19 '19 at 10:11

0 Answers0