Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   HTML, Javascript y otros (https://www.clubdelphi.com/foros/forumdisplay.php?f=38)
-   -   xhr, AJAX en menos de 1 KB (https://www.clubdelphi.com/foros/showthread.php?t=63838)

dec 05-03-2009 01:56:48

xhr, AJAX en menos de 1 KB
 
Hola,

Je je je... No sé si os podrá interesar, probablemente, no, pero, por si queráis echar un vistazo, aquí tenéis una clase para javascript: xhr, que, puede usarse para trabajar con el famoso objeto XmlHttpRequest, de una forma más o menos sencilla, y, que, sólo ocupa 723 bytes, "minimizada".

Más información en este enlace :)

roman 05-03-2009 02:20:32

Una pregunta: ¿qué jQuery no tiene ya la implementación de ajax? Lo pregunto porque me sorprende un poco que siendo tú el number one fan de jQuery, programes una función aparte y que -encima- ¡no es un plugin de jQuery! :D

Bueno, es un poco por molestar :p

Otra pregunta: en la documentación pones:

Código:

xhr.call({
  url : 'backend.php'
});

xhr.Success = function(xhr){
  alert(xhr.responseText);
}

¿No tendría que adjuntarse el evento primero, es decir, antes de la llamada?

Por ahí tenía yo una función js que lee los campos de un formulario y prepara los pares necesarios para mandarlos vía GET o POST. De esta manera, puedes partir de un formulario ya hecho y mandarlo con ajax. Si te interesa la busco y se la anexas a tu función.

// Saludos

dec 05-03-2009 02:30:56

Hola,

Gracias por tu respuesta Román. Hombre, jQuery es mucha jQuery... esto no la sustituye, ni dios que lo pensó, como se suele decir. Se trataba de jugar un poco, de quitarme la obsesión (quizá un tanto estúpida) de la cabeza, en fin. Otra cosa es que, además de una especie de juguete, pueda usarse realmente, llegado el caso.

Poniéndome en un hipotético caso (vale, muy hipotético) de tener que hacer alguna petición HTTP vía "AJAX" y no necesite nada más (jQuery), usar la clase de que hablamos vale 723 bytes... así que puede ser una opción, no sé, hipotéticamente. :D Pero sí, jQuery tiene un muy completo soporte para AJAX, mucho mejor que el que xhr proporcione, sin dudarlo.

Lo del evento luego de la llamada a "call()", sí, es casualidad pero yo también lo he visto antes. Lo voy a cambiar, y, sin embargo, como la llamada se realiza "asíncronamente" (por defecto) todavía creo que funcionaría el asunto: al fin y al cabo el objeto "xhr" está disponible, pero, en todo caso, queda más fino (y posiblemente evite problemas) si el evento se sitúa antes de la llamada a "call()", sí. ;)

Respecto del código que dices... me parece que hasta lo tengo guardado por aquí. No me importaría echarle un vistazo, empero, piensa que Xhr es "another 1 KB less "AJAX" library", no vayamos a jorobar el eslogan el primer día. Je je je je... :D :D

PD. Ya está cambiado el asunto del evento antes de "call()".

PD2. No me has dicho si te parece que estoy loco del todo o qué. :D

PD3. Adjunta por aquí el código que dices (por no buscarlo yo...) o envíamelo Román, por favor: igual cabe. :D

Ñuño Martínez 05-03-2009 10:04:22

Interesante, interesante...

Resulta que estoy con un pequeño proyecto y estaba buscando la forma de trabajar con AJAX un poco más a mi estilo. Me hice un módulo en el trabajo y hasta ahora creí que era el que iba a incluir en el proyecto, pero después de ver esto ya no estoy seguro.

No creo que lo incluya tal cual en mi proyecto (entre otras cosas, la GPL nunca fue de mi agrado, prefiero Zlib, MIT o FreeBSD), pero como mínimo voy a reescribir mi módulo. :D

dec 05-03-2009 15:24:43

Hola,

Gracias Ñuño. La licencia es ahora LGPL, empero, no creo que tengamos problemas. ¿Verdad? ;)

roman 05-03-2009 16:43:26

Siempre he pensado que esto de Ajax se ha manejado como algo oscuro y complicado y hasta se escriben libros dedicados a ello, cuando en verdad no es más que:

1. Crear un objeto de tipo XHTTPRequest
2. Usarlo para enviar una petición HTTP
3. Asignar su evento OnReadyStateChange

La parte más "difícil" es la 1 porque se debe crear el objeto según qué navegador y qué versión, pero una búsqueda en Google nos dará múltiples versiones.

En la parte 2 simplemente hay que especificar el método de la petición (GET, POST o HEAD) y si el envío es síncrono o asíncrono. No hay mucho que pensarle, debe ser asíncrono a no ser que -en las condiciones actuales- queramos fastidiar al usuario congelando su navegador.

Lo interesante está en la parte 3, en dónde esencialmente sólo nos interesa esperar a recibir el readyState = 4 indicando que ya se competó la respuesta y determinar el status de la misma: =200 ok, !=200 not ok (básicamente).

Y ya, no hay nada más. De verdad.

Es más, la X de ajax no sé ni quién la use, porque normalmente veo que se usa la respuesta de tipo texto en lugar de xml, y si se quiere algo más estructurado, mejor usar json, que puede manejarse directamente con javascript.

Lo que sí hay extra son las facilidades para recibir esta respuesta, como es la de ponerla en automático en un <div> y traducir el onreadystatechange en eventos cómodos para el programador. Es lo que ha hecho David.


Ahora, como yo no soy dado a las licencias gpl, mit, lgpl y cosas así, pues les pongo aquí lo que alguna vez hice, lo pongo al dominio público, osea para que cada cual haga con el lo que desee. Lo único interesante -posiblemente- es la clase HTTPParams y la función parseForm para leer los campos de un formulario ya hecho y traducirlo en los pares key=value que se envían con la petición HTTP. Pero la verdad es que la he usado muy poco porque no estoy convencido (todavía) de enviar formularios vía ajax.

Código:

/******************************************************************************

    Función createRequest

    Crear un objeto HttpRequest según los distintos navegadores

    Desde luego, esta función puede refinarse tanto como sea necesario.

******************************************************************************/

function createRequest()
{
    if (window.XMLHttpRequest)
    {
        return new XMLHttpRequest();
    }
    else if (window.ActiveXObject)
    {
        return new ActiveXObject('Microsoft.XMLHTTP');
    }

    return null;
}

/******************************************************************************

    Clase HttpParams

    Almacena pares [key, value] para ser enviados en una petición HTTP

*******************************************************************************/

function HttpParams()
{
    this.items = new Array();
}

// Agrega un par a la lista
//
HttpParams.prototype.add = function(key, value)
{
    this.items[this.items.length] = [key, value];
}

// Construye la cadena a ser enviada
//
HttpParams.prototype.getQueryString = function()
{
    var result = '';

    for (var i = 0; i < this.items.length; i++)
    {
        var item = this.items[i];

        if (result)
        {
            result += '&';
        }

        result += item[0] + '=' + item[1];
    }

    return encodeURI(result);
}

/******************************************************************************

    Función parseForm

    Extrae la información de un formulario y la coloca en un objeto HttpParams

******************************************************************************/

function parseForm(form)
{
    var elements = form.elements;
    var params = new HttpParams();
    var element;

    for (var i = 0; i < elements.length; i++)
    {
        element = elements.item(i);

        if (!element.name)
        {
            continue;
        }

        switch (element.type.toLowerCase())
        {
            case 'text': case 'password': case 'hidden': case 'textarea':
                params.add(element.name, element.value);
                break;

            case 'select-one':
                if (element.value)
                {
                    params.add(element.name, element.value);
                }
                break;

            case 'select-multiple':
                options = element.options;

                for (j = 0; j < options.length; j++)
                {
                    option = options.item(j);

                    if (option.selected)
                    {
                        params.add(element.name, option.value);
                    }
                }
                break;

            case 'radio':  case 'checkbox':
                if (element.checked)
                {
                    params.add(element.name, element.value);
                }
                break;
        }
    }

    return params;
}

/******************************************************************************

    Clase Ajax

    Interfaz para el envio de peticiones HTTP através de un objeto HTTPRequest

******************************************************************************/

function Ajax(url)
{
    this.url = url;
    this.params = new HttpParams();
    this.async = true;
    this.request = null;
    this.handler = null;
}

Ajax.prototype.send = function(method)
{
    // Crear un objeto HttpRequest
    //
    // Estos objetos no parecen ser reusables por lo que hay que crearlos cada
    // vez que enviemos una petición HTTP
    //
    this.request = createRequest();

    // Si la llamada es asíncrona, establecer el procesador de eventos
    //
    if (this.request && this.async)
    {
        var self = this; // extraño ¿no?

        this.request.onreadystatechange = function()
        {
            // cuando se llame a este evento, this es una copia del objeto
            // por ello es que debemos usar self
            //
            if (self.request.readyState == 4 && self.request.status == 200 && self.handler != null)
            {
                // llamar al manejador del usuario
                self.handler();
            }
        }
    }

    if (method.toLowerCase() == 'post')
    {
        this.request.open(method, this.url, this.async);
        this.request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        this.request.send(this.params.getQueryString());
    }
    else
    {
        this.request.open(method, this.url + '?' + this.params.getQueryString(), this.async);
        this.request.send(null);
    }

    // Si la llamada fue síncrona, llamar al manejador ahora
    //
    if (!this.async && this.handler != null)
    {
        this.handler();
    }
}

Ajax.prototype.getText = function()
{
    return this.request.responseText;
}

Ajax.prototype.getXml = function()
{
    return this.request.responseXml;
}

Ajax.prototype.parseForm = function(form)
{
    this.params = parseForm(form);
}

// Saludos

dec 05-03-2009 16:58:37

Hola,

Gracias por el código Román. Hombre, está claro que al final no se hace sino lo mismo. Sin embargo, hay formas y formas. No tienes sino darte una vuelta en busca de "bibliotecas" que permiten trabajar "a alto nivel" con el objeto XmlHttpRequest famoso. No ya algo como jQuery, que, implementa no sólo métodos como "get" y "post", sino "load", "getScript", "getJSON", y algunos más, que lo que hacen es ponernos las cosas más sencillas: y precisamente por lo que dices: sabemos lo que hay que hacer, pero, delegamos esto en jQuery, ahorrándonos así trabajo y algunas cosas más, como estar pendiente de posibles problemas, incompatibilidades, etc., puesto que ya lo hacen por nosotros.

Pero, he dicho que no sólo bibliotecas como jQuery encontrarás si buscas este tipo de "AJAX libraries"... Así unas se basarán en funciones, "get", "post", etc., otras, como la que he presentado en este hilo, utilizarán un sólo método, al que es posible pasar diferentes argumentos opcionales. Todas, más o menos, sirven para lo mismo: en un par de líneas de código nos permiten hacer peticiones HTTP en segundo plano, de una manera o de otra, evitándonos tener que preparar por nuestra cuenta el objeto "XmlHttpRequest", su "onreadystatechange", etc. Como estas "bibiliotecas" son diferentes, unas se adaptarán mejor o peor a nuestra forma de hacer las cosas.

Sé que no llevabas mala intención, y, respecto de la licencia del poco código que he presentado aquí, no creo que haya que hacerse problemas, pero, el argumento que has utilizado arriba me ha sonado como si yo te dijese, "Hombre, para qué vas a usar la VCL de Delphi y el componetne "TButton", si puedes crear tu propio botón empleando la API de Windows"... Je je je je... claro que podría crear el botón usando el API de Windows, pero, ¡dónde va a parar! Y por eso, entre otras cosas, utilizamos entornos como Delphi. Pero, en fin, conste que te doy la razón, porque, en efecto, al final se trata de hacer uso del objeto XmlHttpRequest de una forma o de otra. Uno mismo podría hacerlo por su cuenta. ;)

PD. Ahora voy a echar un vistazo al código que has puesto arriba. Y gracias. :)

roman 05-03-2009 17:14:32

Cita:

Empezado por dec (Mensaje 340316)
Sé que no llevabas mala intención, y, respecto de la licencia del poco código que he presentado aquí, no creo que haya que hacerse problemas, pero, el argumento que has utilizado arriba me ha sonado como si yo te dijese, "Hombre, para qué vas a usar la VCL de Delphi y el componetne "TButton", si puedes crear tu propio botón empleando la API de Windows"... Je je je je... claro que podría crear el botón usando el API de Windows, pero, ¡dónde va a parar! Y por eso, entre otras cosas, utilizamos entornos como Delphi. Pero, en fin, conste que te doy la razón, porque, en efecto, al final se trata de hacer uso del objeto XmlHttpRequest de una forma o de otra. Uno mismo podría hacerlo por su cuenta. ;)

¿Cuándo me has visto con mala intención? :p

La intención era simplemente desmitificar el ajax. Concuerdo contigo en que hay bibliotecas que nos facilitan las cosas y desde luego que conviene usarlas. Pero a ver, cuando uno ve en la librería (uf, esta vez si está bien usado el término :D) un libro de 200 o 300 páginas, con título: Aplicaciones WEB con Ajax, uno se piensa que debe ser todo un mundo que explorar, cuando en realidad son sólo los tres puntos que puse arriba.

Una vez que uno es conciente de eso, ya con confianza escoge la biblioteca que más le acomode o se fabrica uno la propia (actualmente prefiero usar una ya hecha).

// Saludos

dec 05-03-2009 17:42:52

Hola,

¿Demasiados libros? Bueno, decía Cervantes (o Alonso Quijano, o El Quijote), que no hay libro malo. No sé, ¿no? En esos libros digo yo que enseñarán otras cosas aledañas a las apliaciones en que se piense hacer un uso extensivo de este tipo de "técnicas". Yo no soy tan optimista como Cervantes: debe haber algún que otro libro malo por ahí, en muchos sentidos, pero, en fin. :D

PD. No tenías que haber puesto tu código. Me ha dado ideas. :D

dec 06-03-2009 00:01:42

Hola,

Echa un vistazo Román (bueno, los demás también podéis). :D

roman 06-03-2009 01:54:11

Al rato lo veo, pero por lo pronto aprovecho para decir que sí hay libros malos, aunque desde luego depende de los gustos. Pero vamos, aunque me tachen de ignorante, yo hay dos libros que no tengo ni tendré en mi estantería: "Azul" y "Platero y Yo".

// Saludos

dec 06-03-2009 01:59:51

Hola,

Hum... no leí Azul, pero, ¿qué demonios te hizo el pobre Platero? Tan rechoncho y blandito como el algodón. :(

roman 06-03-2009 02:08:41

Bueno, bueno, espero no haber herido susceptibilidades, pero ése es el problema, un libro que empieza con "Platero es pequeño, peludo, suave; tan blando por fuera, que se diría todo de algodón, que no lleva huesos. Sólo los espejos de azabache de sus ojos son duros cual dos escarabajos de cristal negro." como que se me enmielaban todas las manos sólo de tener el libro entre mis manos :D

// Saludos

dec 06-03-2009 02:21:01

Hola,

¡No vas a quitarme el buen recuerdo que tengo de Platero! :( :( :D

Así al azar:

Cita:

El canario se muere


Mira, Platero; el canario de los niños ha amanecido hoy muerto en su jaula de plata. Es verdad que el pobre estaba ya muy viejo... El invierno último, tú te acuerdas bien, lo pasó silencioso, con la cabeza escondida en el plumón. Y al entrar esta primavera, cuando el sol hacía jardín la estancia abierta y abrían las mejores rosas del patio, él quiso también engalanar la vida nueva, y cantó; pero su voz era quebradiza y asmática, como la voz de una flauta cascada.

El mayor de los niños, que lo cuidaba, viéndolo yerto en el fondo de la jaula, se ha apresurado, lloroso, a decir:

—¡Puej no l'a faltado ná; ni comida, ni agua!

No. No le ha faltado nada, Platero. Se ha muerto porque sí, diría Campoamor, otro canario viejo...

Platero, ¿habrá un paraíso de los pájaros? ¿Habrá un vergel verde sobre el cielo azul, todo en flor de rosales áureos, con almas de pájaros blancos, rosas, celestes, amarillos?

Oye; a la noche, los niños, tú y yo bajaremos el pájaro muerto al jardín. La luna está ahora llena, y a su pálida plata, el pobre cantor, en la mano cándida de Blanca, parecerá el pétalo mustio de un lirio amarillento. Y lo enterraremos en la tierra del rosal grande.

A la primavera, Platero, hemos de ver al pájaro salir del corazón de una rosa blanca. El aire fragante se pondrá canoro, y habrá por el sol de abril un errar encantado de alas invisibles y un reguero secreto de trinos claros de oro puro.

dec 06-03-2009 18:49:39

Hola,

¡Que alguien me pare por dios! :D :D

Ñuño Martínez 09-03-2009 12:59:06

Dec, compañero, lo suyo es grave. Yo me lo haría mirar. :p;):D


La franja horaria es GMT +2. Ahora son las 07:41:21.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi