| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect3 id="zend.controller.actionhelpers.autocomplete">
- <title>AutoComplete</title>
- <para>
- Many <acronym>AJAX</acronym> javascript libraries offer functionality for providing
- autocompletion whereby a selectlist of potentially matching results is
- displayed as the user types. The <emphasis>AutoComplete</emphasis> helper aims
- to simplify returning acceptable responses to such methods.
- </para>
- <para>
- Since not all JS libraries implement autocompletion in the same way, the
- <emphasis>AutoComplete</emphasis> helper provides some abstract base
- functionality necessary to many libraries, and concrete implementations
- for individual libraries. Return types are generally either <acronym>JSON</acronym> arrays
- of strings, <acronym>JSON</acronym> arrays of arrays (with each member array being an
- associative array of metadata used to create the selectlist), or <acronym>HTML</acronym>.
- </para>
- <para>
- Basic usage for each implementation is the same:
- </para>
- <programlisting language="php"><![CDATA[
- class FooController extends Zend_Controller_Action
- {
- public function barAction()
- {
- // Perform some logic...
- // Encode and send response;
- $this->_helper->autoCompleteDojo($data);
- // Or explicitly:
- $response = $this->_helper->autoCompleteDojo
- ->sendAutoCompletion($data);
- // Or simply prepare autocompletion response:
- $response = $this->_helper->autoCompleteDojo
- ->prepareAutoCompletion($data);
- }
- }
- ]]></programlisting>
- <para>
- By default, autocompletion does the following:
- </para>
- <itemizedlist>
- <listitem><para>Disables layouts and ViewRenderer.</para></listitem>
- <listitem><para>Sets appropriate response headers.</para></listitem>
- <listitem>
- <para>Sets response body with encoded or formatted autocompletion data.</para>
- </listitem>
- <listitem><para>Sends response.</para></listitem>
- </itemizedlist>
- <para>
- Available methods of the helper include:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <methodname>disableLayouts()</methodname> can be used to disable layouts and
- the ViewRenderer. Typically, this is called within
- <methodname>prepareAutoCompletion()</methodname>.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>encodeJson($data, $keepLayouts = false)</methodname> will encode
- data to <acronym>JSON</acronym>, optionally enabling or disabling layouts.
- Typically, this is called within
- <methodname>prepareAutoCompletion()</methodname>.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>prepareAutoCompletion($data, $keepLayouts = false)</methodname>
- is used to prepare data in the response format necessary for the
- concrete implementation, optionally enabling or disabling
- layouts. The return value will vary based on the implementation.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>sendAutoCompletion($data, $keepLayouts = false)</methodname>
- is used to send data in the response format necessary for the
- concrete implementation. It calls
- <methodname>prepareAutoCompletion()</methodname>, and then sends the
- response.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>direct($data, $sendNow = true, $keepLayouts =
- false)</methodname> is used when calling the helper as a method of
- the helper broker. The <varname>$sendNow</varname> flag is used to
- determine whether to call <methodname>sendAutoCompletion()</methodname> or
- <methodname>prepareAutoCompletion()</methodname>, respectively.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Currently, <emphasis>AutoComplete</emphasis> supports the Dojo and Scriptaculous
- <acronym>AJAX</acronym> libraries.
- </para>
- <sect4 id="zend.controller.actionhelpers.autocomplete.dojo">
- <title>AutoCompletion with Dojo</title>
- <para>
- Dojo does not have an AutoCompletion widget per se, but has two
- widgets that can perform AutoCompletion: ComboBox and
- FilteringSelect. In both cases, they require a data store that
- implements the QueryReadStore; for more information on these topics, see the <ulink
- url="http://dojotoolkit.org/reference-guide/dojo/data.html">dojo.data</ulink>
- documentation.
- </para>
- <para>
- In Zend Framework, you can pass a simple indexed array to the
- AutoCompleteDojo helper, and it will return a <acronym>JSON</acronym> response suitable
- for use with such a store:
- </para>
- <programlisting language="php"><![CDATA[
- // within a controller action:
- $this->_helper->autoCompleteDojo($data);
- ]]></programlisting>
- <example id="zend.controller.actionhelpers.autocomplete.dojo.example1">
- <title>AutoCompletion with Dojo Using Zend MVC</title>
- <para>
- AutoCompletion with Dojo via the Zend <acronym>MVC</acronym> requires several
- things: generating a form object for the ComboBox on which you
- want AutoCompletion, a controller action for serving the
- AutoCompletion results, creating a custom QueryReadStore to connect
- to the AutoCompletion action, and generation of the javascript
- to use to initialize AutoCompletion on the server side.
- </para>
- <para>
- First, let's look at the javascript necessary. Dojo offers a
- complete framework for creating <acronym>OOP</acronym> javascript, much as Zend
- Framework does for <acronym>PHP</acronym>. Part of that is the ability to create
- pseudo-namespaces using the directory hierarchy. We'll create a
- 'custom' directory at the same level as the Dojo directory
- that's part of the Dojo distribution. Inside that directory,
- we'll create a javascript file, <filename>TestNameReadStore.js</filename>, with the
- following contents:
- </para>
- <programlisting language="javascript"><![CDATA[
- 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);
- }
- });
- ]]></programlisting>
- <para>
- This class is simply an extension of Dojo's own QueryReadStore,
- which is itself an abstract class. We simply define a method by
- which to request, and assigning it to the 'test' element.
- </para>
- <para>
- Next, let's create the form element for which we want
- AutoCompletion:
- </para>
- <programlisting language="php"><![CDATA[
- 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;
- }
- }
- ]]></programlisting>
- <para>
- Here, we simply create a form with 'test' and 'go' methods. The
- 'test' method adds several special, Dojo-specific attributes:
- dojoType, store, autoComplete, and hasDownArrow. The dojoType is
- used to indicate that we are creating a ComboBox, and we will
- link it to a data store (key 'store') of 'testStore' -- more on
- that later. Specifying 'autoComplete' as <constant>FALSE</constant> tells
- Dojo not to automatically select the first match, but instead show a list of
- matches. Finally, 'hasDownArrow' creates a down arrow similar to
- a select box so we can show and hide the matches.
- </para>
- <para>
- Let's add a method to display the form, as well as an end point
- for processing AutoCompletion:
- </para>
- <programlisting language="php"><![CDATA[
- class TestController extends Zend_Controller_Action
- {
- // ...
- /**
- * Landing page
- */
- 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);
- }
- }
- ]]></programlisting>
- <para>
- In our <methodname>autocompleteAction()</methodname> we do a number of
- things. First, we look to make sure we have a post request, and
- that there is a 'format' parameter set to the value 'ajax';
- these are simply to help reduce spurious queries to the action.
- Next, we check for a 'test' parameter, and compare it against
- our data. (I purposely leave out the implementation of
- <methodname>getData()</methodname> here -- it could be any sort of data
- source.) Finally, we send our matches to our AutoCompletion
- helper.
- </para>
- <para>
- Now that we have all the pieces on the backend, let's look at
- what we need to deliver in our view script for the landing page.
- First, we need to setup our data store, then render our form,
- and finally ensure that the appropriate Dojo libraries --
- including our custom data store -- get loaded. Let's look at the
- view script, which comments the steps:
- </para>
- <programlisting language="php"><![CDATA[
- <?php // setup our data store: ?>
- <div dojoType="custom.TestNameReadStore" jsId="testStore"
- url="<?php echo $this->baseUrl() ?>/unit-test/autocomplete/format/ajax"
- requestMethod="get"></div>
- <?php // render our form: ?>
- <?php echo $this->form ?>
- <?php // setup Dojo-related CSS to load in 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 javascript to load in HTML head, including all required
- // Dojo libraries: ?>
- <?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() ?>
- ]]></programlisting>
- <para>
- Note the calls to view helpers such as headStyle and headScript;
- these are placeholders, which we can then render in the <acronym>HTML</acronym>
- head section of our layout view script.
- </para>
- <para>
- We now have all the pieces to get Dojo AutoCompletion working.
- </para>
- </example>
- </sect4>
- <sect4 id="zend.controller.actionhelpers.autocomplete.scriptaculous">
- <title>AutoCompletion with Scriptaculous</title>
- <para>
- <ulink
- url="http://wiki.script.aculo.us/scriptaculous/show/Ajax.Autocompleter">Scriptaculous</ulink>
- expects an <acronym>HTML</acronym> response in a specific format.
- </para>
- <para>
- The helper to use with this library is 'AutoCompleteScriptaculous'.
- Simply provide it an array of data, and the helper will create an
- <acronym>HTML</acronym> response compatible with Ajax.Autocompleter.
- </para>
- </sect4>
- </sect3>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|