Pergunta

No momento, não estamos usando nenhuma estrutura séria do lado do cliente além do jQuery (e jQuery.ui + validação + plug-ins de assistente de formulário).

Um problema que surge algumas vezes em nosso código é este:

  1. Temos um botão que inicia uma chamada Ajax para o servidor.
  2. Enquanto a chamada está ocorrendo, exibimos um ícone "carregando" com algum texto
  3. Se o servidor retornar um resultado muito rapidamente (por exemplo, <200 ms), "dormiremos" por 200 milis (usando setTimeout()), para evitar a oscilação do ícone e do texto em espera .
  4. Após max(the call returns, a minimal timeout), limpamos o ícone de carregamento e o texto.
  5. Em seguida, exibimos um texto de erro, se houver algum problema na chamada ajax (o servidor não retorna 500, mas um json personalizado que tem uma propriedade "mensagem de erro". Na verdade, às vezes temos esse na resposta por campo do formulário ... e, em seguida, correspondemos os erros aos campos do formulário ... mas estou divagando).
  6. Em caso de sucesso, fazemos ... algo (depende da situação).

Estou tentando minimizar a reutilização de código e escrever ou reutilizar um padrão / pedaço de código / estrutura que faça isso. Embora eu provavelmente não comece a usar uma nova estrutura de serviço pesado inteiro apenas para este caso de uso, ainda gostaria de saber quais são minhas opções ... talvez uma estrutura do lado do cliente seja boa para outras coisas também. Se houver uma estrutura leve que não exige que eu vire todo o meu código de cabeça para baixo e eu pudesse usar apenas em casos específicos, poderíamos realmente usá-la em vez de reinventar a roda.

Recentemente ouvi falar sobre Ember.js - é uma boa opção para resolver este problema? Como você resolveria isso?

Foi útil?

Solução

$(function(){
 var buttonSelector = "#button";
 $('body').on({'click': function(evt){
    var $button = $(this);
    $button.toggleClass('loading');
    var time = new Date();
    $.get('some/ajax').then(function(data,text,jqXhr){
   // typical guess at load work
       $button.empty();
       $(data).wrap($button);
    }).fail(function(data,text,jqXhr){
     alert("failed");
    }).done(function(data,text,jqXhr){
       var elapsed = new Date();
      if((elapsed - time) < 200){
        alert("to short, wait");
      }
      $button.toggleClass('loading');
    });
  }},buttonSelector,null);
});

Outras dicas

Apenas envolva $ .ajax em sua própria função.dessa forma, você pode implementar seu próprio fila etc. Eu sugeriria fazer um componente jquery para isso.Ele pode ficar muito poderoso, por exemplo, você também pode passar cabeçalhos http etc.
Com relação a frameworks, depende de seus requisitos.
Por exemplo, você pode considerar Kendo UI, tem uma boa estrutura para a criação de fontes de dados: http://demos.kendoui.com/web/datasource/index.html .

Working Sample Code (well, almost)

I was going for something along the lines of @DefyGravity's answer anyway - his idea is good, but is still pseudo-code/not fully complete. Here is my working code (almost working demo, up to the Ajax URL itself, and UI tweaks)

The code & usage example:

jQuery.fn.disable = function() {
    $(this).attr("disabled", "disabled");
    $(this).removeClass("enabled");

    // Special handling of jquery-ui buttons: http://stackoverflow.com/questions/3646408/how-can-i-disable-a-button-on-a-jquery-ui-dialog
    $(this).filter("button").button({disabled: true});
};
jQuery.fn.enable = function() {
    $(this).removeAttr("disabled");
    $(this).addClass("enabled");
    // Special handling of jquery-ui buttons: http://stackoverflow.com/questions/3646408/how-can-i-disable-a-button-on-a-jquery-ui-dialog
    $(this).filter("button").button({disabled: false});
};


function AjaxCallbackWaiter(ajaxUrl, button, notificationArea, loadingMessage, errorMessage, inSuccessHandler, inFailureHandler) {
    // Every request that takes less than this, will be intentionally delayed to prevent a flickering effect
    // http://ripper234.com/p/sometimes-a-little-sleep-is-ok/
    var minimalRequestTime = 800;
    var loadingIconUrl = 'http://loadinfo.net/images/preview/11_cyrcle_one_24.gif?1200916238';

    var loadingImageContent = $("<img class='loading-image small' src='" + loadingIconUrl + "'/><span class='loading-text'>" + loadingMessage + "</span>");
    var errorContentTemplate = $("<span class='error ajax-errors'></span>");

    var requestSentTime = null;

    button.click(clickHandler);

    function displayLoadingMessage() {
        clearNotificationArea();
        notificationArea.html(loadingImageContent);
    }

    function clearNotificationArea() {
        notificationArea.html("");
    }

    function displayError(message) {
        var errorContent = errorContentTemplate.clone(errorContentTemplate).html(message);
        notificationArea.html(errorContent);
    }

    function ajaxHandler(result) {
        var requestReceivedTime = new Date().getTime();
        var timeElapsed = requestReceivedTime - requestSentTime;
        // Reset requestSentTime, preparing it for the next request
        requestSentTime = null;

        var sleepTime = Math.max(0, minimalRequestTime - timeElapsed);

        function action() {
            clearNotificationArea();
            button.enable();
            if (result) {
                inSuccessHandler();
            } else {
                displayError(errorMessage);
                inFailureHandler();
            }
        }

        if (sleepTime <= 0) {
            action();
        } else {
            setTimeout(action, sleepTime);
        }
    }

    function failureHandler() {

    }

    function clickHandler(){
        if (requestSentTime !== null) {
            logError("Bad state, expected null");
        }
        requestSentTime = new Date().getTime();
        displayLoadingMessage();
        button.disable();
        $.get(ajaxUrl, 'json').then(ajaxHandler, failureHandler);
    }
}

// Usage:
var ajaxUrl = 'FILL IN YOUR OWN URL HERE';
var button = $("#clickme");
var notificationArea = $(".ajax-notification-area");

var waitingMessage = "Doing Stuff";
var errorMessage = "Not Good<br/> Please try again";

$(document).ready(function(){
  new AjaxCallbackWaiter(
    ajaxUrl,
    button, 
    notificationArea,
    waitingMessage,
    errorMessage,
    function(){
      alert("All is well with the world");
    },
    function(){
      alert("Not good - winter is coming");
    });
});
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top