SweetAlert2 and promises

TJ is too short picture TJ is too short · Nov 18, 2017 · Viewed 11.4k times · Source

I'm trying to use SweetAlert2 but I'm having issues to display error messages when something goes wrong. Also, when the user presses the "Cancel" button, the console displays the error: Uncaught (in promise) cancel.

In short, there is a button on my website. If the user presses that button a confirm dialog appears (using SweetAlert2). Here is my code:

swal({
    title: "Are you sure?",
    text: "You will not be able to undo this action!",
    type: "warning",
    showCancelButton: true,
    cancelButtonText: 'No, cancel!',
    confirmButtonColor: "#DD6B55",
    confirmButtonText: "Yes, do it!",
    allowOutsideClick: false
    preConfirm: function () {
        return axios.put('/api/endpoint')
        .then(response => {
            console.log('success')
        })
        .catch(error => {
            console.log('failure')
            swal({
                title: "Something went wrong",
                type: "error",
            })
        });
    }
}).then(function (result) {
    if (result.value) {
        swal('Deleted!', 'Your file has been deleted.', 'success')
    } else if (result.dismiss === 'cancel') {
        swal('Cancelled', 'Your file is safe :)', 'error')
    }
});

If something goes wrong, will be nice to display another SweetAlert2 dialog saying "Something went wrong", but instead of that, it looks like SweetAlert2 is somehow capturing the error and displaying it inside the same confirmation box. Also, there is the issue with the cancel button: If the user cancels, the console displays the already mentioned error.

SweetAlert2 uses promises and I'm still learning how to use them properly, so maybe there is something that I'm doing in the wrong way.

Any help, please?

Thanks in advance

Answer

Willie picture Willie · Jan 17, 2018

I just finished messing around with promises inside SWAL2 for the first time, and have made some serious headway into improving part of the UX of my web application because of it. I have used SWAL2 modals a lot, and found that promises work best when getting user input inside a SWAL modal, and validating that input.

I am using JQuery 3.2.1 and PHP version 5.6

This is the first method for trying to do what I am doing, so please don't assume that it will be an exact fit for your project. I am still doing a bit of testing so keep that in mind.

My overall goal was to get users to input the rest of the information I need from them after they log in to their profile for the first time (and/or they have empty fields for necessary database values).

Here is the basis of what I am using Promises and Ajax to do on a macro level:

swal({...}).then(function(result){ //introduction modal

    swal({...}).then(function(result){ //start getting required info

        swal({...}).then(function(result){ //get some more required info

        }, function (dismiss) {}).catch(swal.noop);

    }, function (dismiss) {}).catch(swal.noop);

}, function (dismiss) {}).catch(swal.noop);

Each one of these modals has different inputs that I need, and that I need to validate, with the exception of the first one.

swal({
    html:'Welcome to my web app!',
    imageUrl: '../path-to-image.png',
    imageWidth: 350,
    imageAlt: 'My Logo',
    animation: false,
    showCancelButton: false,
    confirmButtonColor: '#3085d6',
    cancelButtonColor: '#d33',
    confirmButtonText: 'Complete My Profile',
    cancelButtonText: 'Cancel',
    confirmButtonClass: 'btn btn-success',
    cancelButtonClass: 'btn btn-danger',
    buttonsStyling: false,
    focusConfirm: false
    }).then(function(result) {

After my "Welcome to XYZ web app" greeting, I start immediately on my next modal. this is super simple. Either bring up the next modal if the user hits the one green button they can hit, or display another modal if they close by clicking off it. My code continues:

swal({
    title: 'Your Basic Information',
    html:
    '<div class="form-group"><input type="text" class="form-control" id="FName" name="FName" placeholder="Last Name"></div>'+
    '<div class="form-group"><input type="text" class="phone_us form-control" maxlength="14" data-mask="(000) 000-0000" id="userPhone" name="userPhone" placeholder="Phone Number"></div>'+
    '<div class="form-group"><div class="input-group"><span class="input-group-addon">$</span><input type="text" class="money form-control" id="avgPrice" name="avgPrice" data-mask="#,##0.00" data-mask-reverse="true" maxlength="5" placeholder="Average Price of your Advice"/></div></div>'+
    '<div class="form-group"><textarea class="form-control" name="FInfo" id="FInfo" rows="6" placeholder="Give people a summary of who you are and what kind of great stuff you can do for them."></textarea></div>'+
    '<div class="form-group"><label for="FType">Type of kitchen</label><select class="form-control" name="FType" id="FType"><option>--Select--</option><option>Type 1</option><option>Type 2</option><option>Type 3</option><option>Type 4</option><option>Type 5</option></select></div>',
    showCancelButton: false,
    confirmButtonColor: '#3085d6',
    cancelButtonColor: '#d33',
    confirmButtonText: 'Update and Continue',
    cancelButtonText: 'Cancel',
    confirmButtonClass: 'btn btn-success',
    cancelButtonClass: 'btn btn-danger',
    buttonsStyling: false,
    focusConfirm: false,
    preConfirm: function () {

    //Set our Ajax variables in the start of preConfirm
    //We could've just made a form element as part of the html, and used a FormData class or form_name.serialize(). The current way is for illustration.
    var userPhone = $('#userPhone').val(), FName = $('#FName').val(), avgPrice = $('#avgPrice').val(), FInfo = $('#FInfo').val(), FType = $('#FType').val(), retData = [];

The above variables are all input values except for retData. retData is an array that will be used to store error strings that I receive from PHP. I can then tell JQuery to iterate through the array and display those errors as toastr notifications. There are ways to do this with JSON, yes.

Here comes the meat and potatoes of what I am trying to get to. Now we can use Promise to continue to run our Ajax request with each user click, and leave the modal open until a certain condition is satisfied (all information is validated, and no errors).

return new Promise(function (resolve) {
    //Run our actual ajax request inside the promise. Keeps the SWAL2 modal open
    $.ajax({
    url: prefix+'settings_val_first_modal.php',
    type: 'POST',
    data: ({userPhone: userPhone, FName: FName, avgPrice: avgPrice, FInfo: FInfo, FType: FType}),
    success: function(show) {

        retData.push.apply(retData, show.split(","));

        //Define the condition that keeps us in the promise.

        if(Number(retData[0]) === 0){

            //Remove the zero from our error array
            retData.shift();

            $.each(retData, function(i, val){

                //Display each array element as separate toastr notification
                toastr.error(retData[i]);

            });

        } else{

            //Define the condition that breaks us out of the promise
            resolve(true);

        }
    }
  });
});
}

Then, once that condition is met, we can move on down the modal chain using

}).then(function(result){

and doing whatever we want after that like adding in another swal for a picture upload, or saying thank you to the user with another swal.

swal('You\'re all finished!','You now have full access to XYZ web app!','success');

then we make sure to define our dismiss function for our second modal. In my case, an info swal modal:

}, function (dismiss) {
// dismiss can be 'cancel', 'overlay',
// 'close', and 'timer'
    if (dismiss === 'overlay') {
        swal(
            'Please Finish Your Profile',
            'You need to have a completed profile before you can start using XYZ web application',
            'info'
        );
    }
}).catch(swal.noop);

And there we have it. I know this is a rather lengthy explanation, but I have found this kind of use to be most fitting for promises and SWAL2. Completing the code, we need to define the case that the first modal is dismissed.

}, function (dismiss) {
// dismiss can be 'cancel', 'overlay',
// 'close', and 'timer'
    if (dismiss === 'overlay') {
        swal(
            'Please Contemplate Your Life',
            'Don\'t make me have to toggle this modal again! I\'d rather not!',
            'info'
        );
    }
}).catch(swal.noop);

Ultimately, I started with one goal which was - improve user experience. Promises work here because otherwise, the modal would close after each button click, and a user would have to start down the entire chain again if they did something as simple as not include an @ with an email input or something.

Promises let us keep a SWAL2 modal on screen until some condition is satisfied. the condition could be anything, in my case it was form validation in PHP that returned strings to javascript. If the inputs were fine, the string is '1'. Otherwise the string contains something like '0,"Invalid Phone Number","An account is already associated with this email","etc"'. JQuery then makes an array, removes the leading zero, and outputs toastr notifications for each error in the array.

I hope this helps you in using SWAL2.