2010-11-18 13 views
5

El patrón común en las IU basadas en AJAX es que cuando el usuario realiza una acción, se refleja en la UI instantáneamente, pero se marca como inacabada hasta la respuesta AJAX de llegada que confirma que todo está bien. Así es como, por ejemplo, agregar un evento en Google Calendar funciona. Y cuando hay un error, ese cambio temporal de UI se revierte.jQuery AJAX "Deshacer ayuda"

Ahora, realizar dicha reversión manualmente no es demasiado creativo, entonces sospecho que hay algo de "ayuda para deshacer" en jQuery, que permite preservar el estado de los elementos de la IU y restaurarlo - tipo de pila de atributos o algo como eso. Esto ni siquiera tiene que ver con AJAX.

¿Hay algo como eso?

Respuesta

7

En este tipo de situaciones, siempre he encontrado que las máquinas de estado son el camino a seguir. Diseñe su página/JavaScript de modo que, en cualquier momento, pueda especificar un conjunto de entradas y siempre obtendrá el mismo resultado en toda la página. Lo bueno de este enfoque es que no sabe cómo llegó a a donde se encuentra en su programa, solo tiene que saber qué datos resultaron en el estado actual.

Para su caso, se podría crear un objeto básico que describe su estado:

var state = { user: 'Tomasz', ajaxSent: false, otherState: 123 }; 

function updateFromState(state){ 
    // Set all dependent UI visibilities, etc. based on state object 
} 

Entonces, antes de hacer cualquier cambio, empujar a su estado actual en una matriz para que pueda invertir de nuevo si es necesario:

var stateList = []; 
stateList.push({ user: 'Tomasz', ajaxSent: false, otherState: 123 }); 

// Do something that changes your state 
var newState = {user: 'Tomasz', ajaxSent: true, otherState: 123 }; 
updateFromState(newState); 

// Now, if you need to revert 
var previousState = stateList.pop(); 
updateFromState(previousState); 

La desventaja de este enfoque es que en realidad no está "deshaciendo" los efectos secundarios que podría haber invocado. Si, por ejemplo, hiciste una publicación de AJAX que modificó los datos en el servidor, tendrías que entender cómo "deshacer" esa publicación de AJAX. Esto va más allá de simplemente cambiar el estado local de la página. Pero, si no necesita deshacer los efectos del lado del servidor, sino solo poder reflejar con precisión el estado correcto de la página, esto puede funcionar para usted.

Esto es lo que probablemente usaría para empezar, si yo estuviera haciendo algo como esto:

var StateHelper = function(){ 
    var stateList = []; 
    var callbacks = []; 

    this.onChange = function(callback){ 
     callbacks.push(callback); 
    }; 

    this.set = function(opts){ 
     stateList.push(opts); 
     apply(opts); 
    }; 

    this.undo = function(){ 
     if(stateList.length <= 1){ 
      return; // nothing to undo 
     } 

     // To undo, we go back 2, since top of stack is current 
     stateList.pop(); 
     var last = stateList[stateList.length - 1]; 
     apply(last); 
    }; 

    var apply = function(opts){ 
     var length = callbacks.length; 
     for(var i = 0; i < length; i++){ 
      callbacks[i](opts); 
     } 
    }; 
}; 

Entonces, si mi página veía así:

<div id='title' style='text-decoration: underline;'>some title</div> 
<div id='state1' class='clickable'>click to set state2 (title = 'second')</div> 
<div id='state2' class='clickable'>click to set state3 (title = 'third')</div> 
<br/> 
<div id='undo' class='clickable'>undo</div> 

puede ser que utilice los anteriores StateHelper como éste (nota utilicé un toque de jQuery):

// A function that should be called when state changes 
var updateTitle = function(opts){ 
    // Update the pages title based on state 
    console.log('title updating'); 
    $('#title').text(opts.title); 
}; 

var myState = new StateHelper(); 
myState.onChange(updateTitle); // hook the state change event 

// some example states 
var state2 = { title: 'second' }; 
var state3 = { title: 'third' }; 

// Just some click handlers 
$(document).ready(function(){ 
    $('#state1').click(function(){ 
     myState.set(state2); 
    }); 

    $('#state2').click(function(){ 
     myState.set(state3); 
    }); 

    $('#undo').click(function(){ 
     myState.undo(); 
    }); 

    // Set initial state 
    myState.set({title: 'some title'}); 
}); 

Por ejemplo vivo, ver: http://jsfiddle.net/belorion/Hywtc/

+0

+1 para el muy agradable respuesta - Sentí que me faltaba una solución tan simple. Y, de hecho, me preocupa sobre todo deshacer los cambios DOM después de una solicitud fallida de AJAX, por lo que no hay cambios en el servidor para revertir. –

+0

@Tomasz actualizado con algún código – Matt

+0

Todavía estoy por entender todo esto, pero parece una solución a mi problema, por lo que estoy aceptando su respuesta ahora. ¡Gracias! –