Search code examples
javascriptprototypejs

Using PrototypeJs or pure JS, how can I avoid a click event but trigger the original handlers later?


I have a Place Order button, that contains a click event that will run some tasks and place the order via ajax.

I would like to add another click event that will be triggered before the original event, and perform some actions and validations.

Depending on the outcome of it:

  1. I would like to prevent the other events to be triggered
  2. OR if success, just proceed and call the other click listeners.

However I'm struggling a lot to achieve that with PrototypeJS or pure JavaScript.

This would be a simple example, but of course I tried many different approaches, including overrigind Event.observe method, cloning the button, and so on.

Any idea is appreciated.

var button = $('onestepcheckout-place-order-button')

//Original event
button.observe('click', function(e) {
  console.log('Order submitted')
})

// New event (I only have access to modify from here onwards)
button.observe('click', function(event) {

  if (confirm('Are you sure?') === false) {
    console.log('The order should not be submitted')
    event.preventDefault()
    event.stopPropagation()
    return false
  }

  // The other events should be triggered (order submitted)
  button.fire('click')
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.3/prototype.js"></script>
<button id="onestepcheckout-place-order-button" type="button"><span>Place order</span></button>


Solution

  • It turns out that, although prototype can store the events internally, we cannot have access to it like we can in jQuery.

    My solution was to clone the original button and add an event to it and also to the form, using pure javascript.

    This way I was able to inject a clone of the original button, but without it events attached, run my function and its validation, and trigger the original button click() event if the validation passes.

    Here's what I did:

    var button = document.getElementById('onestepcheckout-place-order-button')
    var form = document.getElementById('orderForm')
    
    
    // some code will add one or more event listeners to the original button
    button.addEventListener('click', function(e) {
      console.log('Button clicked will submit form via ajax')
      //ajax (the order may be placed via ajax. replace the webhook.site url with yours if you want to see it in action there)
      new Ajax.Request('https://webhook.site/25fab621-3f15-4d9f-ad87-3a746113adf2', {
        method: 'POST',
        data: {
          name: 'John Doe',
          email: '    '
        }
      })
    }, false)
    
    // clone the button
    var newButton = button.cloneNode(true)
    
    // replace old button for the new button (with no events attached)
    button.parentNode.replaceChild(newButton, button)
    
    // just a generic function to validate and prevent default
    var validateAndPreventDefault = function(event) {
      event.preventDefault() // prevent the default behavior of the form/button
    
      if (confirm('Are you sure?') === false) {
        // add condition here
        // if some condition is not met, prevent the form from being submitted
        console.log('The order should not be submitted')
    
        return false
      }
    
      console.log('The order will bet submitted')
      button.click() // trigger the click event on the old button
      return true
      // The other events should be triggered (order submitted)
    }
    
    // add the event listener to the form and the button, preventing the default behavior in both cases
    form.addEventListener('submit', validateAndPreventDefault, false)
    newButton.addEventListener('click', validateAndPreventDefault, false)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.3/prototype.min.js"></script>
    <form id="orderForm" method="post" action="#">
      <!--    type button-->
      <button id="onestepcheckout-place-order-button" type="button"><span>Place order</span></button>
    
      <!--    type submit-->
      <button id="onestepcheckout-place-order-button-original" type="submit"><span>Submit button</span></button>
    </form>