skip to Main Content

I would like to replace a larger set of alert() in my program with a custom routine new-alert().
The visual structure through a bootstrap modal is no problem.
However, since I want to replace a lot of alert() (more than 100) in a rather complex system (more than 50,000 lines of PHP and JS code), I am unfortunately forced to replicate parts of the behavior of alert(). More specifically, the behavior that it actually blocks JS code execution!
To make it a bit more precise, the JS code after a new-alert() should happen just like with an alert() only after the user confirms.
Unlike the alert(), however, it is a desired side-effect if the page and browser remains "operable", i.e. the user can enter a new URL for example.

As an example I have created a small demo code in Codepen:
https://codepen.io/MichaelBootstrap/pen/RwxKmWd?editors=1111

But you can find it also below as Code Sniplet

I experimented with setTimeout() and await() before, but didn’t get it to work.

A solution with JQuery is also OK, I use JQuery in other places anyway.

For newer and revised functions I already used complete non-blocking /async functions, but with the mass of "legacy" functions I have no choice for now. So please don’t discuss that this could be solved much nicer as non-blocking / asyncron, I’m aware of that!

HTML:

var myModalEl = document.getElementById('exampleModal')
myModalEl.addEventListener('hidden.bs.modal', confirm_alert )

function alert_something() {
  // alert("Error"); // the old alert()
   new_alert("Error");
  console.log("This code should only executed, if new_alert() is confirmed");
}

function new_alert(text) {
   // insert text will be done later
   var myModalEl = document.getElementById('exampleModal');
   var modal = bootstrap.Modal.getOrCreateInstance(myModalEl);
   modal.show()
   wait_for_confirm();
}

function wait_for_confirm() {
   // .....
}

function confirm_alert() {
  // trigger completion of wait_for_confirm()
  // .....
  console.log("Alert confirmed");
 }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.0.2/js/bootstrap.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" class="btn btn-primary m-4" onclick="alert_something()">
  Alert me 
</button>

<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">Alert</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        Alert Text
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
      </div>
    </div>
  </div>
</div>

2

Answers


  1. Chosen as BEST ANSWER

    Finaly I find a solution! It loops over an asyncrone function that uses SetTimer with a Promise. Every second (can be more often) it checks if the user has done the confirm. I would like to cancel the timeout directly with cancalTime(), but that had side effects so far. The code is by far not "nice" yet, will put in still in a class and remove the global variables. The code is to be used also with caution, errors with the asyncronen function calls are difficult to find. And the whole solution is also not really nice, so I'm thinking myself whether I really build this in. But I was curious to see if there wasn't a solution.

    https://codepen.io/MichaelBootstrap/pen/jOYLBde?editors=1111

    var myModalEl = document.getElementById('exampleModal')
    myModalEl.addEventListener('hidden.bs.modal', confirm_alert )
    
    var result = false;
    
    async function alert_something() {
      // alert("Error"); // the old alert()
         // insert text will be done later
       var myModalEl = document.getElementById('exampleModal');
       var modal = bootstrap.Modal.getOrCreateInstance(myModalEl);
       modal.show();
      
       console.log('calling');
       for (i=1;result == false; i++) {
          const result = await resolveAfter1000ms();
         console.log("loop "+i);
       }
      console.log("done");
      
      console.log("This code should only executed, if new_alert() is confirmed");
    }
    
    function confirm_alert() {
      // trigger completion of wait_for_confirm()
      console.log("Alert confirmed");
      result = true;
    }
    
    function resolveAfter1000ms() {
      return new Promise(resolve => {
         setTimeout(() => {
          resolve('resolved');
        }, 1000);
      });
    }
    

  2. I’m sorry to say¹ that the answer is: You can’t. You quite simply can’t. That is not a feature offered in browsers. The only reason alert (and confirm and prompt) still exist is to support legacy code (and they’re somewhat under threat of removal). There are no new modern ways to do it on the main thread.²

    If you have code relying on the stop-the-world behavior of alert, you have to keep using alert. Modern replacements would require changing the code to handle waiting asynchronously and continuing, for instance by making the function stack leading up to it async and using await. (That may not be as much work as you might expect, but it’s probably not trivial, either.) But synchronous blocking behavior is just not possible other than the built-ins.


    ¹ I’m not sorry it can’t be done. I’m just sympathetic to your situation of dealing with a large legacy codebase where you want to be able to do it.

    ² "…on the main thread…" On a worker thread, you could use Atomics.wait (though you probably shouldn’t). But that doesn’t help you, because you can’t do it on the main thread.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search