0

I have two javascript/jquery functions in my app, there is always refresh() function, which grabs data from database and redraw frontend view.

One of methods is sending data into PHP function, which makes simple insert to MySQL database, second edits it, here they are (they're the same, so I post only one):

function insertedit()
{
$('.res').each(function()
{
    $.post("/controller/method/",{id: id},function(data,status,xhr)
    {
        if(status=="success")
        {
        }
    })
});     

refresh();
}

When I'm trying to insert data with this function, all works fine and my view is redrawing asynchronously, but when i'm trying to edit data with it - I have to refresh page to see updated view. I think, that edit operation takes more time than insert and my refresh function, which grabs data from SQL just grabs the old data (undeleted record) - how can I fix it?

EDIT

$(function()
{
 refresh();
});



function insertedit(){
  var $promises = [];
  $('.res').each(function()
  {

    $promises.push(
    $.post("/controller/metgod/",{id, id},function(data,status,xhr)
    {
        if(status=="success")
        {
        }
    })
    );
});     

$.when.apply($, $promises).then(function() {
    refresh();
});
}
pawel
  • 5,976
  • 15
  • 46
  • 68
  • 2
    you should wait to refresh until all ajax requests are finished – kennypu Dec 29 '12 at 01:34
  • I know, but how to do it? – pawel Dec 29 '12 at 01:35
  • It's quicker to `.detach()` the thing you're redrawing - you can still manipulate it with jQuery, then stick it back where it was with `.appendTo()` or similar, so it doesn't redraw in the HTML, just in the DOM. – Popnoodles Dec 29 '12 at 01:37
  • you would use $.when(), map each ajax request as an argument into $.when(), then refresh on .then(). look at here for an example: http://stackoverflow.com/questions/5401969/jquery-ajax-how-to-wait-until-async-requests-success-completes-before-continu – kennypu Dec 29 '12 at 01:41
  • How do you concat the whens within an each? – Popnoodles Dec 29 '12 at 01:45
  • Could you guys provide me some pseudocode or example solution? : ] – pawel Dec 29 '12 at 01:55
  • 1
    should also consider making one ajax request with all of the ID's instead of many requests. Return JSON to match your ID's sent and loop over that – charlietfl Dec 29 '12 at 01:57

2 Answers2

4

Use promises

function insertedit()
{
  var $promises = [];

  $('.res').each(function(id){
    var $this = $(this);

    $promises.push(
      $.post("/controller/method/", {'id': $this.attr('id')}, function(data,status,xhr){
        $this.text(data); // success
      })
    );
  });

  $.when.apply($, $promises).then(function(){
    refresh();
  });     
}

See the fiddle here, it works http://jsfiddle.net/69eMp/4/

pocesar
  • 6,860
  • 6
  • 56
  • 88
  • the `$.post` already returns the promise, I removed the `promise()` at the end of the call. I'm taking that you are using jQuery 1.7 or greater. – pocesar Dec 29 '12 at 02:22
  • btw, I don't know where are you getting that `id` from, make sure you are passing the right parameters, since your original code looks broken (or is pseudo code) – pocesar Dec 29 '12 at 02:25
  • Could you look at my edited question? I'm doing it your way, and I still need to refresh page.. – pawel Dec 29 '12 at 14:55
  • @FrederikWordenskjold it doesn't work because `when` needs arguments and not an array, that's why the need of apply. – pocesar Dec 29 '12 at 21:01
  • @pawel it seems you are using pseudo code, or you have no idea what you're doing. You are missing your `id`, where are you getting that from? – pocesar Dec 29 '12 at 21:02
2

I have had use for such a solution at some point, and here was my solution (here's a live demo here) :

/**
 * Class that will handle delayed function calls
 * @param fn     the funciton to call
 * @param ctx    the context to use as 'this' inside the function
 * @param delay  delay in millis
 */
var AsyncCall= function(fn, ctx, delay) {
   var timer = null;

   ctx   = ctx || window;
   delay = delay || 1;

   return function() {
       // prevent calling the delayed function multiple times
       if (timer) clearTimeout(timer);

       var args = arguments;

       timer = setTimeout(function() {
          timer = null;
          fn.apply(ctx, args);
       }, delay);
   };
};

// wrap the 'refresh' funciton inside the async call object with a 200 millis delay
var refreshAsync = new AsyncCall(refresh, null, 200);

function insertedit()
{
$('.res').each(function()
{
    $.post("/controller/method/",{id: id},function(data,status,xhr)
    {
        if(status=="success")
        {
        }

        // schedule calling 'refresh'
        refreshAsync();
    })
});
}

The reason why this would be preferred is that you don't have to refresh every Ajax requests. With this, it will only execute the refresh function fewer times than if you refresh every single time. And 200 milliseconds is not so long, but enough for Ajax calls to return and is not noticeable by the users.

Yanick Rochon
  • 51,409
  • 25
  • 133
  • 214