# AutoComplete

Muchas bibliotecas de Javascript con AJAX ofrecen funcionalidad para proporcionar autocompletado según la cual un selectlist de resultados potencialmente concordantes se visualiza a medida que el usuario tipea. El ayudante AutoComplete pretende simplificar el retorno de respuestas aceptables a esos métodos.

Dado que no todas la bibliotecas JS implementan el autocompletado de la misma manera, el ayudante AutoComplete ofrece algunas funcionalidades abstractas de base necesarias para muchas bibliotecas, e implementaciones concretas para distintas bibliotecas. Los tipos de datos de retorno son generalmente o bien arrays de strings JSON , array de arrays JSON (donde cada miembro del array está en un array asociativo de metadatos utilizado para crear la selectlist), o HTML .

El uso básico para cada aplicación es el mismo:

    class FooController extends Zend_Controller_Action
    {
        public function barAction()
        {
            // Ejecutar alguna lógica...

            // Codificar y enviar la respuesta;
            $this->_helper->autoCompleteDojo($data);

            // O explicitamente:
            $response = $this->_helper->autoCompleteDojo
                                      ->sendAutoCompletion($data);

            // O prepare simplemente la respuesta de autocompletado:
            $response = $this->_helper->autoCompleteDojo
                                      ->prepareAutoCompletion($data);
        }
    }

Por defecto, el autocompletado hace lo siguiente:

- Desactiva esquemas y a ViewRenderer.

- Establece las cabeceras apropiadas para la respuesta.

- Establece el cuerpo de la respuesta con datos codificados o formateados para autocompletar.

- Envía la respuesta.

Los métodos disponibles para el ayudante incluyen:

- `disableLayouts()` puede ser utilizada para desactivar esquemas y a ViewRenderer. Típicamente, esto se llama dentro de `prepareAutoCompletion()` .

- `encodeJson($data, $keepLayouts = false)` codificará datos a JSON , y opcionalmente habilitando o deshabilitando esquemas. Típicamente, esto se llama dentro de `prepareAutoCompletion()` .

- `prepareAutoCompletion($data, $keepLayouts = false)` se utiliza para preparar datos en el formato necesario de la respuesta para la aplicación concreta, opcionalmente los esquemas pueden habilitarse o deshabilitarse. El valor de retorno variará dependiendo de la implementación.

- `sendAutoCompletion($data, $keepLayouts = false)` se utiliza para preparar datos en el formato necesario de la respuesta para la aplicación concreta. Esta llama a `prepareAutoCompletion()` , y entonces envía la respuesta.

- `direct($data, $sendNow = true, $keepLayouts = false)` se utiliza cuando se llama al ayudante como un método del ayudante intermediario. El flag `$sendNow` se utiliza para determinar si se debe llamar a `sendAutoCompletion()` o a `prepareAutoCompletion()` , respectivamente.

Actualmente, AutoComplete soporta las bibliotecas AJAX de Dojo y Scriptaculous.

## AutoCompletado con Dojo

Dojo no tiene un widget de autocompletado per se, pero tiene dos widgets que pueden ejecutar AutoCompletado: ComboBox y FilteringSelect. En ambos casos, necesitan de un almacén de datos que implemente QueryReadStore; para obtener más información sobre estos temas, ver la documentación en dojo.data

En Zend Framework, puede pasar un simple array indexado al ayudante AutoCompleteDojo, y este regresará una adecuada respuesta JSON para su uso como almacenamiento:

    // dentro del controlador de acción:
    $this->_helper->autoCompleteDojo($data);

### AutoCompletion con Dojo Usando Zend MVC

AutoCompletion con Dojo via Zend MVC requiere varias cosas: generar un objeto form para el ComboBox en el que usted quiere AutoCompletado, un controlador de acción para prestar servicio a los resultados de AutoCompletion, creando un QueryReadStore personalizado para conectar a la acción AutoCompletion, y la generación del Javascript a utilizar en la inicializción de AutoCompletion del lado del servidor.

En primer lugar, veamos el Javascript necesario. Dojo ofrece un marco completo para crear Javascript OOP , tal como lo hace Zend Framework para PHP . Parte de eso es la capacidad de crear pseudo-namespaces utilizando la jerarquía de directorios. Crearemos un directorio 'custom' en el mismo nivel en el cual el directorio de Dojo forma parte de la distribución Dojo. Dentro del directorio, crearemos un archivo Javascript, `TestNameReadStore.js` , con el siguiente contenido:

    dojo.provide("custom.TestNameReadStore");
    dojo.declare("custom.TestNameReadStore", dojox.data.QueryReadStore, {
        fetch:function (request) {
            request.serverQuery = { test:request.query.name };
            return this.inherited("fetch", arguments);
        }
    });

Esta clase es simplemente una extensión del propio QueryReadStore de Dojo, que es de por sí misma una clase abstracta. Simplemente definimos un método por el cual realizamos la solicitud, y se le asigna al elemento 'test'.

A continuación, vamos a crear el elemento form para el que queremos AutoCompletion:

    class TestController extends Zend_Controller_Action
    {
        protected $_form;

        public function getForm()
        {
            if (null === $this->_form) {
                $this->_form = new Zend_Form();
                $this->_form->setMethod('get')
                    ->setAction(
                        $this->getRequest()->getBaseUrl() . '/test/process'
                    )
                    ->addElements(array(
                        'test' => array('type' => 'text', 'options' => array(
                            'filters'        => array('StringTrim'),
                            'dojoType'       => array('dijit.form.ComboBox'),
                            'store'          => 'testStore',
                            'autoComplete'   => 'false',
                            'hasDownArrow'   => 'true',
                            'label' => 'Your input:',
                        )),
                        'go' => array('type' => 'submit',
                                      'options' => array('label' => 'Go!'))
                    ));
            }
            return $this->_form;
        }
    }

Aquí, estamos simplemente creando un formulario con los métodos 'test' y 'go'. El método 'test' agrega varios atributos especiales específicos de Dojo: dojoType, store, AutoComplete y hasDownArrow. El dojoType es utilizado para indicar que estamos creando un ComboBox, y que vamos a vincularlo a un almacén de datos (clave 'store') de 'testStore' -- veremos más de esto más adelante. Especificando ' AutoComplete ' como `FALSE` se le dice a Dojo que no seleccione automáticamente el primer acierto, sino mostrar una lista de aciertos. Por último, 'hasDownArrow' crea una flecha abajo similar a un select box para que podamos mostrar y ocultar los aciertos o concordancias.

Vamos a añadir un método para mostrar la forma, así como un punto final para el procesamiento de AutoCompletion:

    class TestController extends Zend_Controller_Action
    {
        // ...

        /**
         * Página final
         */
        public function indexAction()
        {
            $this->view->form = $this->getForm();
        }

        public function autocompleteAction()
        {
            if ('ajax' != $this->_getParam('format', false)) {
                return $this->_helper->redirector('index');
            }
            if ($this->getRequest()->isPost()) {
                return $this->_helper->redirector('index');
            }

            $match = trim($this->getRequest()->getQuery('test', ''));

            $matches = array();
            foreach ($this->getData() as $datum) {
                if (0 === strpos($datum, $match)) {
                    $matches[] = $datum;
                }
            }
            $this->_helper->autoCompleteDojo($matches);
        }
    }

En nuestro `autocompleteAction()` hacemos una serie de cosas. En primer lugar, esperamos a asegurarnos de que tengamos una petición post, y que existe un parámetro 'form' establecido al valor 'ajax'; esto es simplemente para ayudar a reducir preguntas espúreas a la acción. A continuación, vamos a comprobar el parámetro 'test', y compararlo contra nuestros datos. (Yo deliberadamente dejé de lado la implementación de `getData()` aquí -- podría ser cualquier tipo de fuente de datos). Por último, enviamos nuestros aciertos a nuestro ayudante AutoCompletion.

Ahora que tenemos todas las piezas en el backend, veamos lo que necesitamos para entregar en nuestro script de vista para la página final. En primer lugar, necesitamos configurar nuestro data store, luego hacer nuestro formulario, y finalmente garantizar que las biblotecas Dojo apropiadas -- incluyendo que nuestro data store personalizado -- estén cargadas. Veamos el script de vista, el cual comenta los pasos:

    <?php // establecemos nuestro data store: ?>
    <div dojoType="custom.TestNameReadStore" jsId="testStore"
        url="<?php echo $this->baseUrl() ?>/unit-test/autocomplete/format/ajax"
        requestMethod="get"></div>

    <?php // mostramos nuestro form: ?>
    <?php echo $this->form ?>

    <?php // establecemos CSS relacionado con Dojo a cargar en HTML head: ?>
    <?php $this->headStyle()->captureStart() ?>
    @import "<?php echo $this->baseUrl()
    ?>/javascript/dijit/themes/tundra/tundra.css";
    @import "<?php echo $this->baseUrl() ?>/javascript/dojo/resources/dojo.css";
    <?php $this->headStyle()->captureEnd() ?>

    <?php // setup de javascript para cargar en HTML head, incluyendo todas las
       // bibliotecas Dojo requeridas: ?>
    <?php $this->headScript()
            ->setAllowArbitraryAttributes(true)
            ->appendFile($this->baseUrl() . '/javascript/dojo/dojo.js',
                'text/javascript',
                array('djConfig' => 'parseOnLoad: true'))
            ->captureStart() ?>
    djConfig.usePlainJson=true;
    dojo.registerModulePath("custom","../custom");
    dojo.require("dojo.parser");
    dojo.require("dojox.data.QueryReadStore");
    dojo.require("dijit.form.ComboBox");
    dojo.require("custom.TestNameReadStore");
    <?php $this->headScript()->captureEnd()

Note que las llamadas a los ayudantes de vista como headStyle y headScript; son ubicadores, que podemos suministrar a la sección 'head' del HTML de nuestro script de vista.

Ahora tenemos todas las piezas para que el AutoCompletion de Dojo pueda trabajar.

## AutoCompletion con Scriptaculous

Scriptaculous espera una respuesta HTML en un formato específico.

El ayudante para utilizar con esta biblioteca es 'AutoCompleteScriptaculous'. Simplemente proporcionarle un array de datos, y el ayudante creará una respuesta HTML compatible con Ajax.Autocompleter.