2009-08-02 15 views
5

Estoy trabajando en un proyecto en el que nos gustaría dar al usuario la posibilidad de guardar su formulario a medio completar para que puedan volver más tarde y completarlo. Estoy luchando con averiguar exactamente cómo quiero hacer esto. ¿Los guardo en el mismo grupo con las aplicaciones completadas, solo con un estado especial? Realmente no quiero sacrificar la integridad de las aplicaciones completas al tener que hacer que los campos sean anulables cuando no quiero que lo sean.Cómo guardar un formulario medio completado

¿Debo crear la misma estructura de base de datos en un esquema diferente para contener las aplicaciones incompletas? Podría hacer que este otro esquema sea más laxo en las limitaciones de la base de datos y los campos con nulos para dar cuenta de las aplicaciones incompletas.

¿Hay una manera más fácil de hacer esto? ¿Hay alguna manera de guardar el estado de visualización y restaurarlo en otro momento?

¡Gracias por cualquier consejo!

Respuesta

1

Puede haber un par de diferencias entre sus solicitudes completas y estos "medios" estados:

  1. Como usted dice, la mayoría de validación es inadecuado, los campos serán nulos, validaciones cruzadas probbably no se pueden realizar.
  2. Probablemente no necesite capacidades de búsqueda arbitrarias en los datos.

Así que haría uso de una base de datos diferente, con el registro que comprende un par de campos clave como el identificador del usuario, la fecha, el tipo de formulario que se están llenando, etc., y una gota de los campos que ha llenado Soy un chico de Java, así que no conozco la forma .NET de obtener el blob, pero en Java puedo serializar los objetos de datos que respaldan el formulario.

Parece que en C# las técnicas tienen cierta similitud con Java, al menos es lo entiendo article correctamente.

Creo que la elaboración manual de algunos códigos simples "saveAsAString" y "readFromString" sería un poco aburrido pero bastante factible si no existen las técnicas .Net estándar.

+0

Creo que este es el enfoque que quiero tomar, pero la parte de serialización es la parte con la que necesito ayuda. –

+0

Agregó una referencia a lo que parece ser un artículo relevante, tal vez haga una segunda pregunta acerca de las técnicas de serialización si nadie responde aquí. – djna

0

Definitivamente lo guardaré en la base de datos. Su plan para guardar con un estado especial (un indicador booleano llamado Complete funcionaría). Luego puede crear una vista que solo extraiga elementos donde Complete = true, llamados CompletedApplications.

3

Obviamente no puede guardarlo en las tablas de datos reales, así que crearía una tabla separada con un ID de usuario, formid y tipo de datos binarios. Combina los formularios en una estructura serializable y serialízalos a db. Cuando el usuario vuelve, puede deserializar y restaurar el estado del formulario.

+0

¿Puede proporcionarnos alguna guía sobre la serialización del formulario web? Es una página con un control Wizard que tiene varios pasos. –

+0

Estoy de acuerdo con tener un LOB serializado, significa que no tiene que tener muchas columnas con nulos en el DB. Es posible guardar en la base de datos, pero no lo recomiendo. @ MikeC- no serializaría el formulario web, sino el modelo de dominio al que está vinculado. – RichardOD

+0

@RichardOD - ¿algún ejemplo? –

4

Luché con el mismo problema. Una diferencia es que mi método implica ajax de guardado automático similar a lo que se ve en Gmail y Blogger. Pero eso no debería cambiar la implementación, realmente.

El problema fue que no quería guardar en las tablas habituales porque eso habría requerido validación (validación de enteros, monedas, fechas, etc.). Y no quería fastidiar al usuario sobre eso cuando realmente están tratando de irse.

Lo que finalmente se me ocurrió fue una tabla llamada AjaxSavedData. Es una tabla permanente en la base de datos, pero los datos que contiene tienden a ser temporales. En otras palabras, almacenará los datos del usuario temporalmente hasta que completen la página y pasen a la siguiente.

La mesa se compone de unas pocas columnas:

AjaxSavedDataID - int:

Clave primaria.

ID de usuario - int:

identificar al usuario (bastante fácil).

PageName - varchar (100):

necesario hacerlo si está trabajando con varias páginas.

ControlID - varchar (100):

me llaman a esto un ControlID, pero no deja de ser la propiedad ClientID que expone .NET para todos los WebControls. Entonces, si por ejemplo txtEmail estuviera dentro de un control de usuario llamado Contacto, entonces ClientID sería Contact_txtEmail.

Valor - VARCHAR (MAX):

El valor introducido por el usuario para un campo o control dado.

dateChanged - fecha y hora:

La fecha se añadió el valor o modificado.

Junto con algunos controles personalizados, este sistema facilita que todo esto "simplemente funcione". En nuestro sitio, se garantiza que el ClientID de cada cuadro de texto, lista desplegable, lista de botones de radio, etc. será único y consistente para una página determinada. Así que pude escribir todo esto para que la recuperación de los datos guardados funcione automáticamente. En otras palabras, no tengo que cablear esta funcionalidad cada vez que agregue algunos campos a un formulario.

Esta funcionalidad de ahorro automático se abrirá paso en una aplicación de seguro de negocios en línea muy dinámica en techinsurance.com para que sea un poco más fácil de usar.

En caso de que esté interesado, aquí está el Javascript que permite el ahorro de auto-:

function getNewHTTPObject() { 
    var xmlhttp; 

    /** Special IE only code */ 
    /*@cc_on 
    @if (@_jscript_version >= 5) 
    try { 
     xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); 
    } 
    catch (e) { 
     try { 
      xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); 
     } 
     catch (E) { 
      xmlhttp = false; 
     } 
    } 
    @else 
     xmlhttp = false; 
    @end 
    @*/ 

    /** Every other browser on the planet */ 
    if (!xmlhttp && typeof XMLHttpRequest != 'undefined') { 
     try { 
      xmlhttp = new XMLHttpRequest(); 
     } 
     catch (e) { 
      xmlhttp = false; 
     } 
    } 

    return xmlhttp; 
} 

function AjaxSend(url, myfunction) { 
    var xmlHttp = getNewHTTPObject(); 
    url = url + "&_did=" + Date(); 
    xmlHttp.open("GET", url, true); 
    var requestTimer = setTimeout(function() { xmlHttp.abort(); }, 2000); 
    xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 
    xmlHttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2005 00:00:00 GMT"); 
    xmlHttp.onreadystatechange = function() { 
     if (xmlHttp.readyState != 4) 
      return; 
     var result = xmlHttp.responseText; 
     myfunction(result); 
    }; 
    xmlHttp.send(null); 
} 

// Autosave functions 
var SaveQueue = []; // contains id's to the DOM object where the value can be found 
var SaveQueueID = []; // contains id's for binding references (not always the same) 

function ArrayContains(arr, value) { 
    for (i = 0; i < arr.length; i++) { 
     if (arr[i] == value) 
      return true; 
    } 

    return false; 
} 

function GetShortTime() { 
    var a_p = ""; 
    var d = new Date(); 
    var curr_hour = d.getHours(); 

    if (curr_hour < 12) 
     a_p = "AM"; 
    else 
     a_p = "PM"; 

    if (curr_hour == 0) 
     curr_hour = 12; 
    else if (curr_hour > 12) 
     curr_hour = curr_hour - 12; 

    var curr_min = d.getMinutes(); 
    curr_min = curr_min + ""; 

    if (curr_min.length == 1) 
     curr_min = "0" + curr_min; 

    return curr_hour + ":" + curr_min + " " + a_p; 
} 

function Saved(result) { 
    if (result == "OK") { 
     document.getElementById("divAutoSaved").innerHTML = "Application auto-saved at " + GetShortTime(); 
     document.getElementById("divAutoSaved").style.display = ""; 
    } 
    else { 
     document.getElementById("divAutoSaved").innerHTML = result; 
     document.getElementById("divAutoSaved").style.display = ""; 
    } 
} 

function getQueryString(name, defaultValue) { 
    var query = window.location.search.substring(1); 
    var vars = query.split("&"); 
    for (var i = 0; i < vars.length; i++) { 
     var pair = vars[i].split("="); 
     if (pair[0] == name) { 
      return pair[1]; 
     } 
    } 

    return defaultValue; 
} 

function urlencode(str) { 
    return escape(str).replace(/\+/g, '%2B').replace(/%20/g, '+').replace(/\*/g, '%2A').replace(/\//g, '%2F').replace(/@/g, '%40'); 
} 

function AutoSave() { 
    if (SaveQueue.length > 0) { 
     var url = "/AjaxAutoSave.aspx?step=" + getQueryString("step", "ContactInformation"); 

     for (i = 0; i < SaveQueue.length; i++) { 
      switch (document.getElementById(SaveQueue[i]).type) { 
       case "radio": 
        if (document.getElementById(SaveQueue[i]).checked) 
         url += "&" + SaveQueueID[i] + "=" + urlencode(document.getElementById(SaveQueue[i]).value); 
        break; 
       case "checkbox": 
        if (document.getElementById(SaveQueue[i]).checked) 
         url += "&" + SaveQueueID[i] + "=" + urlencode(document.getElementById(SaveQueue[i]).value); 
       default: 
        url += "&" + SaveQueueID[i] + "=" + urlencode(document.getElementById(SaveQueue[i]).value); 
      } 
     } 

     SaveQueue = []; 
     SaveQueueID = []; 
     AjaxSend(url, Saved); 
    } 
} 

function AddToQueue(elem, id) { 
    if (id == null || id.length == 0) 
     id = elem.id; 

    if (!ArrayContains(SaveQueueID, id)) { 
     SaveQueue[SaveQueue.length] = elem.id; 
     SaveQueueID[SaveQueueID.length] = id; 
    } 
} 

Añadir esto a su página para hacer este trabajo:

window.setInterval("AutoSave()", 5000); 

Y a aplicar esto a una Cuadro de texto, DropDownList, Cuadro de lista, o casilla de verificación sólo tiene que añadir este atributo:

onchange="AddToQueue(this)" 

... o esto para un RadioButtonList o CheckBoxList:

onchange="AddToQueue(this, '" + this.ClientID + "')" 
+0

Entonces, cuando está guardando los controles ¿simplemente itera a través de la colección Controls? –

+0

En realidad, como se trata de una solución basada en ajax, el ahorro se realiza por cambio a través de Javascript. Tengo Javascript en eventos de cambio en todos los campos que detectan los cambios que realiza un usuario y agrega esos cambios a una matriz. Y luego tengo una llamada setInterval que vacía la matriz y envía todos esos cambios a través de ajax a una página aspx por separado cada 5 segundos. De esta forma solo actualizará lo que se cambia y nada más, haciendo un buen uso del ancho de banda. –

+0

Por cierto, todo este material de AJAX es completamente personalizado. Ni siquiera me molesté en tratar de usar el material AJAX de .NET porque me estaba confundiendo. –

-1

pensado nunca de utilizar Silverlight? Silverlight tiene almacenamiento aislado. He visto varios ejemplos donde los desarrolladores usan almacenamiento aislado para almacenar costosos datos del lado del cliente.

http://pietschsoft.com/post/2008/10/Silverlight-Client-Side-Database-via-LINQ-and-Isolated-Storage.aspx

Y luego usando js para obtener los datos en una salida:

http://msdn.microsoft.com/en-us/library/cc221414%28VS.95%29.aspx

Esto le impide necesidad de ningún espacio adicional DB porque las entradas de forma temporal todos los del usuario se almacenan en aislada Almacenamiento, cuando regresen a la página, le preguntará al usuario si desea reanudar su edición ... y luego rellenará el formulario con los datos en un almacenamiento aislado ...

suena más gr aceful que agregar una nueva base de datos?

Hay una desventaja que es una solución que depende de la máquina.

Depende del objetivo exacto del ahorro de formularios parciales? ¿Es para que pueda aparecer en otras máquinas? si es así, esta no es la solución correcta y un DB save es un mal mejor.

+0

Silverlight no es aplicable. –

Cuestiones relacionadas