# AutoComplete

Viele AJAX Javascript Bibliotheken bieten Funktionalitäten an für eine automatische Vervollständigung wobei eine Auswahlliste von potentiell passenden Ergebnissen angezeigt wird wärend der Benutzer tippt. Der AutoComplete Helfer zielt darauf ab einfach akzeptierbare Ergebnisse zu solchen Methoden zurückzugeben.

Da nicht alle JS Bibliotheken automatische Vervollständigung auf die gleiche Art implementieren bietet der AutoComplete Helfer einige grundsätzliche abstrakte Funktionalitäten zu vielen Bibliotheken und konkrete Implementierungen für individuelle Bibliotheken. Zurückgegebene Typen sind generell entweder JSON Arrays von Strings, JSON Arrays von Arrays (mit jedem Mitgliedsarray das ein assoziatives Array von Metadaten ist, das verwendet wird um die Auswahlliste zu erstellen), oder HTML.

Die grundsätzliche Verwendung ist für jede Implementierung die selbe:

    class FooController extends Zend_Controller_Action
    {
        public function barAction()
        {
            // etwas Logik durchführen...

            // Verschlüsseln und Antwort senden;
            $this->_helper->autoCompleteDojo($data);

            // oder explizit:
            $response = $this->_helper->autoCompleteDojo
                                      ->sendAutoCompletion($data);

            // oder einfach die Antwort der automatischen
            // Vervollständigung vorbereiten;
            $response = $this->_helper->autoCompleteDojo
                                      ->prepareAutoCompletion($data);
        }
    }

Standardmäßig mach die automatische Vervollständigung folgendes:

- Layouts und ViewRenderer ausschalten.

- Die richtigen Antwort Header zu setzen.

- Antwort Body mit verschlüsselten oder formatierten automatisch vervollständigten Daten setzen.

- Antwort senden.

Mögliche Methoden des Helfers beinhalten:

- `disableLayouts()` kann verwendet werden um Layouts und den ViewRenderer auszuschalten. Typischerweise wird das innerhalb von `prepareAutoCompletion()` aufgerufen.

- `encodeJson($data, $keepLayouts = false)` verschlüsselt Daten zu JSON, und aktiviert oder deaktiviert Layouts optional. Typischerweise wird das innerhalb von `prepareAutoCompletion()` aufgerufen.

- `prepareAutoCompletion($data, $keepLayouts = false)` wird verwendet um Daten im Antwortformat vorzubereiten wenn das für die konkrete Implementation notwendig ist, wobei Layouts optional aktiviert oder deaktiviert werden können. Der Rückgabewert variiert basierend auf der Implementierung.

- `sendAutoCompletion($data, $keepLayouts = false)` wird verwendet um Daten im Antwortformat zu senden was für die konkrete Implementierung notendig ist. Sie ruft `prepareAutoCompletion()` und sendet dann die Antwort.

- `direct($data, $sendNow = true, $keepLayouts = false)` wird verwendet wenn der Helfer als Methode des Helfer Brokers aufgerufen wird. Das `$sendNow` Flag wird verwendet um festzustellen ob `sendAutoCompletion()` oder `prepareAutoCompletion()` aufgerufen werden muß.

Aktuell unterstützt AutoComplete die folgenden Dojo und Scriptaculous AJAX Bibliotheken.

## AutoCompletion mit Dojo

Dojo hat per se keinen AutoCompletion Wizard, hat aber zwei Wizards die AutoCompletion ausführen können: ComboBox und FilteringSelect. In beiden Fällen benötigen Sie einen Datenspeicher der QueryReadStore implementiert; für mehr Informationen über dieses Thema siehe die dojo.data Dokumentation.

Im Zend Framework kann ein einfaches indiziertes Array an den AutoCompletionDojo Helfer übergeben werden, und er wird eine JSON Antwort zurückgeben die passend für die Verwendung in so einem Speicher ist:

    // In der Controller Aktion:
    $this->_helper->autoCompleteDojo($data);

### AutoCompletion mit Dojo und der Verwendung von Zend MVC

AutoCompletion mit Dojo, über Zend MVC, benötigt verschiedene Dinge: Erstellung eines Form Objekts für die Kombobox bei der man AutoCompletion will, eine Controller Action für das anbieten der AutoCompletion Ergebnisse, Erstellung eines eigenen QueryReadSote um die AutoCompletion Aktion damit zu verbinden, und Erstellung des Javascripts das zur Initialisierung der AutoCompletion auf der Serverseite zu verwenden ist.

Schauen wir uns zuerst das benötigte Javascript an. Dojo bietet ein komplettes Framework für die Erstellung von OOP Javascript, so wie Zend Framework für PHP. Teile davon sind die Möglichkeit Pseudo-Namespaces zu erstellen indem die Verzeichnis Hirarchie verwendet wird. Wir erstellen ein 'custom' Verzeichnis auf dem gleichen Level wie das Dojo Verzeichnis das Teil der Distribution von Dojo ist. In diesem Verzeichnis, erstellen wir eine Javascript Datei, `TestNameReadStore.js`, mit den folgenden Inhalten:

    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);
        }
    });

Diese Klasse ist einfach eine Erweiterung von Dojo's eigenem QueryReadStore, welche selbst eine Abstrakte Klasse ist. Wir definieren einfach eine Methode mit der angefragt werden soll, und verknüpfen Sie mit dem 'test' Element.

Als nächstes, erstellen wir das Form Element für das wir AutoCompletion wollen:

    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;
        }
    }

Hier erstellen wir einfach eine Form mit den 'test' und 'go' Methoden. Die 'test' Methode fügt verschiedene spezielle, Dojo-spezifische Attribute hinzu: dojoType, store, autoComplete, und hasDownArrow. Der dojoType wird verwendet um anzuzeigen das wir eine ComboBox erstellen, und wir Sie zum Datenspeicher von 'testStore' verbinden wollen (Schlüssel 'store') -- mehr dazu später. Die Spezifizierung von 'autoComplete' mit `FALSE` sagt Dojo das der erste passende Eintrag nicht automatisch ausgewählt wird, aber stattdessen eine Liste von Entsprechnungen angezeigt wird. Letztendlich, erstellt 'hasDownArrow' einen Abwärtspfeil ähnlich einer Selectbox sodas Wir die Entsprechnungen zeigen und verstecken können.

Fügen wir eine Methode hinzu um die Form anzuzeigen, sowie einen Endpunkt für die Bearbeitung der AutoCompletion:

    class TestController extends Zend_Controller_Action
    {
        // ...

        /**
         * Startseite
         */
        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);
        }
    }

in unserer `autocompleteAction()` machen wir eine Anzahl von Dingen. Zuerst schauen wir darauf eine Post Anfrage durchzuführen, und das dort ein 'format' Parameter auf den Wert 'ajax' gesetzt ist; das hilft einfach störende Anfragen zur Aktion zu reduzieren. Als nächstes prüfen wir auf den 'test' Parameter, und vergleichen Ihn mit unseren Daten. (wir haben absichtlich die Implementation von `getData()` hier ausgelassen -- es können einfach jede Art von Datenquelle sein.) Letztendlich senden wir unsere Entsprechungen zum AutoCompletion Helfer.

Jetzt da wir alle Teile des Backends haben, sehen wir uns an was wir benötigen um es in unserem View Skript für die Startseite auszugeben. Zuerst müssen wir unseren Datenspeicher einstellen, dann unsere Form darstellen, und letztendlich sicherstellen das die richtigen Dojo Bibliotheken -- inklusive unserer eigenen Datenspeicher -- geladen werden. Schauen wir uns das View Skript an, das die Schritte kommentiert:

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

    <?php // Die Form darstellen: ?>
    <?php echo $this->form ?>

    <?php // Das Dojo-betreffende CSS einstellen das im
          // HTML Head geladen werden soll: ?>
    <?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 // Javascript einstellen das im HTML Head geladen werden soll,
          // inklusive aller benötigten Dojo Bibliotheken: ?>
    <?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() ?>

Beachte die Aufrufe zu den View Helfern wie headStyle und headScript; das sind Platzhalter, welche dann in der HTML Head Sektion des Layout View Skripts dargestellt werden können.

Wir haben jetzt alle Teil um mit Dojo AutoCompletion zu arbeiten.

## AutoCompletion mit Scriptaculous

Scriptaculous erwartet eine HTML Antwort in einem speziellen Format.

Der Helfer der mit dieser Bibliothek zu verwenden ist 'AutoCompleteScriptaculous'. Es muß einfach ein Array von Daten angegeben werden, und der Helfer wird eine HTML Antwort erstellen die mit Ajax.Autocompleter kompatibel ist.