THI
THI

Reputation: 365

Multiple clicks on button in SAP UI5

I have almost tried everything to prevent multiple clicks on a button press which leads to multiple order creation/ service calls - Made the button disable immediately on press, gave it a busy state, wrote addEventDelegate for dblClick, set/reset flag upon order creation, etc. Nothing works!

Below is my code:

Inside the fragment

     <HBox alignItems="Center">
     <Button id="1"/>
     <Button id="2"/>
     <Button id="save" text="{i18n>SaveOrder}" press="onSubmit" 
          fieldGroupIds="saveSubmitButtons"  
           visible="order>/Other/SaveVisible}" enabled 
             ="order>/Other/SaveEnabled}"/>
    <Button id="submit" text="{i18n>SubmitOrder}" 
           fieldGroupIds="saveSubmitButtons" press="onSubmit" visible=" 
           {order>/Other/SubmitVisible}" enabled =" 
           {order>/Other/SubmitEnabled}"/>
       </HBox>

****Inside Controller*** Save / Submit use the same function depending upon the source further action is taken. But both have the issue of multiple clicks. Currently commented the double click event capture functionality.

_initializeData: function(){
      // jQuery.sap.delayedCall(500, this, "attachDblClick");
     }
 attachDblClick: function (oEvent) {
     // var that = this;
     //this.getView().getControlsByFieldGroupId("saveSubmitButtons").
      //forEach(function (element) {
      // element.addEventDelegate({
     //  ondblclick: function (that) {
    //      element.setBusy(true);
   //       element.setBusyIndicatorDelay(0);
  //        this.onSubmit.bind(this);  
 //****Note: This above call does not work - It never redirects to the 
       function
 //    }            
 //     }, this);
//  });
//  },

onSubmit: function (oEvent) {
 var flag = this.getModel("order").getProperty("/Other/SaveEnabled");
 if(flag){
 this.getModel("order").setProperty("/Other/SaveEnabled", false);
 this.getModel("order").setProperty("/Other/SubmitEnabled", false);
 this.source = oEvent.getSource().getText();
 var that = this;
 setTimeout(function()
    {
 POUtils.onSubmit(that, that.source);
     }, 3000);
           }

POUtils.js

onSubmit: function (oContext, mode) {
 ....
  /*oContext.OdataModel.create("/POSet", oContext.Data, null, 
  oContext.success.bind(oContext), oContext.error.bind(oContext));*/

  var token = null;
  $.ajax({
  url: sServiceURl,
  type: "GET",
  async: true,
  beforeSend: function (xhr) {
  sap.ui.core.BusyIndicator.show(0);
  xhr.setRequestHeader("X-CSRF-Token", "Fetch");
  },
  complete: function (xhr) {
  token = xhr.getResponseHeader("X-CSRF-Token");
  oContext.OdataModel.create("/OrdersSet", oContext.Data, null, 
  oContext.successs.bind(oContext), oContext.error.bind(oContext));
       }});

 // error function
error: function(){
  oContext.getModel("order").setProperty("/Other/SaveEnabled", true); 
 oContext.getModel("order").setProperty("/Other/SubmitEnabled", true); 
 }

Upvotes: 0

Views: 3286

Answers (4)

Mikael G
Mikael G

Reputation: 742

Make sure that your backend service supports Repeatable Requests and this is no longer an issue. Each request from your UI5 app should have a Request Id that the service promise to execute only once.

Settings for Idempotent Services in SAP: https://help.sap.com/doc/saphelp_hba/1.0/en-US/67/8b5dcd6a5c41789b27b46eb34a6a86/content.htm?no_cache=true

Upvotes: 1

Marc
Marc

Reputation: 6190

I saw the following lines in your code:

element.setBusy(true);
element.setBusyIndicatorDelay(0);

This will set the element to busy with the current delay (probably 1000) and then sets the delay to 0. Obviously this will not help. Also it will set the delay everytime the button is clicked, even if the value is already set.

If you switch these lines it should work. First set the delay, then set the busy state.

Even better is to set the delay directly in the view. This is code extracted from a productive application which does not allow double clicking:

In your view/fragment:

<Button busyIndicatorDelay="0" 
    text="Save" 
    type="Accept" 
    press="onPressSave" />

In your controller:

onPressSave: function (oEvent) {
    const oButton = oEvent.getSource();
    oButton.setBusy(true);

    // more code

    oModel.create(sKey, oObject, {
        success: function (oResponse) {
            oButton.setBusy(false);
            // more success handling code
        },
        error: function (oError) {
            oButton.setBusy(false);
            // more error handling code
        }
    });
}

Upvotes: 1

Gunasekhar Reddy
Gunasekhar Reddy

Reputation: 1

I had the same issue with the users clicking on multiple times, The set property was taking time and what worked is on the ide setvisible. Also note, if you are using a fragment, then you cannot directly fetch the id, the syntax to fetch the id is slightly different (u can google for the same).

        // also disable the accept button, preventing the user not to double click. 
        this.getView().byId("oacceptbtn").setVisible(false);

Hope this helps.

Upvotes: 0

Ji aSH
Ji aSH

Reputation: 3457

The 'setProperty' method will trigger some asynchronous updates on the binding, making it possible to click the button several times before it is finally rerendered as disabled.

You could simply store in your controller the current call, and prevent any other calls while it is running :

onSubmit: function (oEvent) {
  var flag = this.getModel("order").getProperty("/Other/SaveEnabled");

  // CHECK THE FLAG
  if (flag && !this._callOnGoing) {
    this.getModel("order").setProperty("/Other/SaveEnabled", false);
    this.getModel("order").setProperty("/Other/SubmitEnabled", false);
    this.source = oEvent.getSource().getText();
    var that = this;

    // CREATE THE FLAG
    this._callOnGoing = true

    POUtils.onSubmit(that, that.source);
  }
}

POUtils.js

onSubmit: function (oContext, mode) {
  ....
  /*oContext.OdataModel.create("/POSet", oContext.Data, null, 
  oContext.success.bind(oContext), oContext.error.bind(oContext));*/

  var token = null;
  $.ajax({
    url: sServiceURl,
    type: "GET",
    async: true,
    beforeSend: function (xhr) {
      sap.ui.core.BusyIndicator.show(0);
      xhr.setRequestHeader("X-CSRF-Token", "Fetch");
    },
    complete: function (xhr) {
      token = xhr.getResponseHeader("X-CSRF-Token");
      oContext.OdataModel.create("/OrdersSet", oContext.Data, null, 
      oContext.successs.bind(oContext), oContext.error.bind(oContext));

      // RESET THE FLAG
      delete oContext._callOnGoing
    }});

    // error function
    error: function(){
      oContext.getModel("order").setProperty("/Other/SaveEnabled", true); 
      oContext.getModel("order").setProperty("/Other/SubmitEnabled", true); 

      // RESET THE FLAG
      delete oContext._callOnGoing
    }

Upvotes: 1

Related Questions