Getting code to run synchronously that resides ins

2019-09-11 08:27发布

I have a dropdown notification window that I show when I run certain AJAX functions, let's simplify it as:

function notifyComplete(type, alert_el, response) {

    var msg = response.output;
    var result = response.result;

    // Update msg in alert box
    alert_el.text(msg);

    if (result == 'success') {
        alert_el.addClass('alert-success');
    } else {
        alert_el.addClass('alert-danger');
    }

    // Slide in alert box
    alert_el.addClass('visible');

}

...and I might call it like so:

var alert_el = $('#top_notify').find('.alert');

// Remove any additional classes added by a possible previous run
alert_el.removeClass('visible alert-success alert-info alert-danger alert-warning');

getAjaxData(loadUrl, dataObject, 'POST', 'json')

    .done(function(response) {
        notifyComplete(notify_type, alert_el, response);
    });

..and here is the getAjaxData function if of interest:

function getAjaxData(loadUrl, dataObject, action, type) {

    return jQuery.ajax({
        type: action,
        url: loadUrl,
        data: dataObject,
        dataType: type
    });

}

Now what I am trying to do is find a way I can place this code:

var alert_el = $('#top_notify').find('.alert');

// Remove any additional classes added by a possible previous run
alert_el.removeClass('visible alert-success alert-info alert-danger alert-warning');

...somewhere where I don't have to repeat it every time I want to use the notifyComplete function.

Obviously if notifyComplete is going to be always called within an AJAX block then I can't put it inside the function itself as then you wouldn't be able to get the notify box to slide down more than once without a page reload.

Also, I can't do it afterwards as the slide down notify window duration is handled by CSS and hence JS doesn't know when it's complete.

I had built a current working example on CodePen here but it seems it's broken because of an issue with crossorigin.me

2条回答
迷人小祖宗
2楼-- · 2019-09-11 08:47

If you are trying to call

var alert_el = $('#top_notify').find('.alert');

// Remove any additional classes added by a possible previous run
alert_el.removeClass('visible alert-success alert-info alert-danger alert-warning');

before each $.ajax() call, you can include the lines within $.ajax() beforeSend function within getAjaxData

function getAjaxData(loadUrl, dataObject, action, type) {

    return jQuery.ajax({
        beforeSend: function(jqxhr, settings) {
                      var alert_el = $('#top_notify').find('.alert');
                      // Remove any additional classes added by a possible previous run
                      alert_el
                     .removeClass('visible alert-success alert-info alert-danger alert-warning');
        },
        type: action,
        url: loadUrl,
        data: dataObject,
        dataType: type
    });

}

If you are trying to call the two lines after $.ajax() call, though before notifyComplete you can pass an array of function to .done()

getAjaxData(loadUrl, dataObject, 'POST', 'json')
.done([
  function(response) {
    var alert_el = $('#top_notify').find('.alert');
    // Remove any additional classes added by a possible previous run
    alert_el
    .removeClass('visible alert-success alert-info alert-danger alert-warning');
  }
  , function(response) {
      notifyComplete(notify_type, alert_el, response);
  }
 ]);

if I could pass it a function name as a callback rather than use an anonymous function and thus have to resort to using if/else inside, but obviously also need a way of including parameters with the callback.

You can use Function.prototype.bind() to pass additional parameters to a named function set as value of beforeSend option of $.ajax(). Include logic to check if the additional object or value is the passed object or jQuery jqxhr object that is the default first parameter of beforeSend.

  function handleBeforeSend(args, jqxhr, settings) {
    console.log(args, jqxhr, settings);
    if (args.hasOwnProperty("additionalSettings")) {
      // do stuff with `args.additionalSettings`
    }
  }

  $.ajax({
    url:"/path/to/server/",
    type: "POST",
    beforeSend: handleBeforeSend.bind(null, {additionalSettings:[0,1,2]})
  });

jsfiddle https://jsfiddle.net/dackdrek/


Implemented within current javascript

$().ready(function() {

  function handleBeforeSend(bool, jqxhr, settings) {
    console.log(bool, jqxhr, settings);
    if (bool === true) {
      var alert_el = $('#top_notify').find('.alert');
      // Remove any additional classes added by a possible previous run
      alert_el.removeClass('visible alert-success alert-info alert-danger alert-warning');
    }
  }

  function notifyComplete(type, alert_el, response) {

    var msg = response.output;
    var result = response.result;

    // Update msg in alert box
    alert_el.text(msg);

    if (result == 'success') {
      alert_el.addClass('alert-success');
    } else {
      alert_el.addClass('alert-danger');
    }

    // Slide in alert box
    alert_el.addClass('visible');

  }

  function getAjaxData(loadUrl, dataObject, action, type, beforeSend, bool) {

    return jQuery.ajax({
      type: action,
      url: loadUrl,
      data: dataObject,
      dataType: type,
      beforeSend: beforeSend.bind(null, bool)
    });

  }
  // pass `true` to `handleBeforeSend`
  getAjaxData("/echo/json/", {
      json: JSON.stringify({
          "output": "123",
          "result": "success"
        })
      }, "POST", "json", handleBeforeSend, true)
    .then(function(response) {
      notifyComplete(null, $('#top_notify'), response)
    });
  setTimeout(function() {
  // pass `false` to `handleBeforeSend`
  getAjaxData("/echo/json/", {
      json: JSON.stringify({
          "output": "123",
          "result": "success"
        })
      }, "POST", "json", handleBeforeSend, false)
    .then(function(response) {
      notifyComplete(null, $('#top_notify'), response)
    })
   }, 5000)
})

jsfiddle https://jsfiddle.net/dackdrek/4/

查看更多
萌系小妹纸
3楼-- · 2019-09-11 08:51

You have a couple of options.

  1. You can use setTimeout in the notifyComplete function, place it at the end and give it a reasonable amount of time so the notification alert disappears automatically after it appears

  2. Also, I can't do it afterwards as the slide down notify window duration is handled by CSS and hence JS doesn't know when it's complete.

    That is not correct, you can use the trantisitionend or animationend events to check when a CSS effect has finished. If you are using something like bootstrap, you can use transitionend in the alert element.

查看更多
登录 后发表回答