1 <?xml version="1.0" encoding="UTF-8"?>
3 <sect3 id="zend.controller.actionhelpers.autocomplete">
4 <title>AutoComplete</title>
7 Many <acronym>AJAX</acronym> javascript libraries offer functionality for providing
8 autocompletion whereby a selectlist of potentially matching results is
9 displayed as the user types. The <emphasis>AutoComplete</emphasis> helper aims
10 to simplify returning acceptable responses to such methods.
14 Since not all JS libraries implement autocompletion in the same way, the
15 <emphasis>AutoComplete</emphasis> helper provides some abstract base
16 functionality necessary to many libraries, and concrete implementations
17 for individual libraries. Return types are generally either <acronym>JSON</acronym> arrays
18 of strings, <acronym>JSON</acronym> arrays of arrays (with each member array being an
19 associative array of metadata used to create the selectlist), or <acronym>HTML</acronym>.
23 Basic usage for each implementation is the same:
26 <programlisting language="php"><![CDATA[
27 class FooController extends Zend_Controller_Action
29 public function barAction()
31 // Perform some logic...
33 // Encode and send response;
34 $this->_helper->autoCompleteDojo($data);
37 $response = $this->_helper->autoCompleteDojo
38 ->sendAutoCompletion($data);
40 // Or simply prepare autocompletion response:
41 $response = $this->_helper->autoCompleteDojo
42 ->prepareAutoCompletion($data);
48 By default, autocompletion does the following:
52 <listitem><para>Disables layouts and ViewRenderer.</para></listitem>
53 <listitem><para>Sets appropriate response headers.</para></listitem>
56 <para>Sets response body with encoded or formatted autocompletion data.</para>
59 <listitem><para>Sends response.</para></listitem>
63 Available methods of the helper include:
69 <methodname>disableLayouts()</methodname> can be used to disable layouts and
70 the ViewRenderer. Typically, this is called within
71 <methodname>prepareAutoCompletion()</methodname>.
77 <methodname>encodeJson($data, $keepLayouts = false)</methodname> will encode
78 data to <acronym>JSON</acronym>, optionally enabling or disabling layouts.
79 Typically, this is called within
80 <methodname>prepareAutoCompletion()</methodname>.
86 <methodname>prepareAutoCompletion($data, $keepLayouts = false)</methodname>
87 is used to prepare data in the response format necessary for the
88 concrete implementation, optionally enabling or disabling
89 layouts. The return value will vary based on the implementation.
95 <methodname>sendAutoCompletion($data, $keepLayouts = false)</methodname>
96 is used to send data in the response format necessary for the
97 concrete implementation. It calls
98 <methodname>prepareAutoCompletion()</methodname>, and then sends the
105 <methodname>direct($data, $sendNow = true, $keepLayouts =
106 false)</methodname> is used when calling the helper as a method of
107 the helper broker. The <varname>$sendNow</varname> flag is used to
108 determine whether to call <methodname>sendAutoCompletion()</methodname> or
109 <methodname>prepareAutoCompletion()</methodname>, respectively.
115 Currently, <emphasis>AutoComplete</emphasis> supports the Dojo and Scriptaculous
116 <acronym>AJAX</acronym> libraries.
119 <sect4 id="zend.controller.actionhelpers.autocomplete.dojo">
120 <title>AutoCompletion with Dojo</title>
123 Dojo does not have an AutoCompletion widget per se, but has two
124 widgets that can perform AutoCompletion: ComboBox and
125 FilteringSelect. In both cases, they require a data store that
126 implements the QueryReadStore; for more information on these topics, see the <ulink
127 url="http://dojotoolkit.org/reference-guide/dojo/data.html">dojo.data</ulink>
132 In Zend Framework, you can pass a simple indexed array to the
133 AutoCompleteDojo helper, and it will return a <acronym>JSON</acronym> response suitable
134 for use with such a store:
137 <programlisting language="php"><![CDATA[
138 // within a controller action:
139 $this->_helper->autoCompleteDojo($data);
142 <example id="zend.controller.actionhelpers.autocomplete.dojo.example1">
143 <title>AutoCompletion with Dojo Using Zend MVC</title>
146 AutoCompletion with Dojo via the Zend <acronym>MVC</acronym> requires several
147 things: generating a form object for the ComboBox on which you
148 want AutoCompletion, a controller action for serving the
149 AutoCompletion results, creating a custom QueryReadStore to connect
150 to the AutoCompletion action, and generation of the javascript
151 to use to initialize AutoCompletion on the server side.
155 First, let's look at the javascript necessary. Dojo offers a
156 complete framework for creating <acronym>OOP</acronym> javascript, much as Zend
157 Framework does for <acronym>PHP</acronym>. Part of that is the ability to create
158 pseudo-namespaces using the directory hierarchy. We'll create a
159 'custom' directory at the same level as the Dojo directory
160 that's part of the Dojo distribution. Inside that directory,
161 we'll create a javascript file, <filename>TestNameReadStore.js</filename>, with the
165 <programlisting language="javascript"><![CDATA[
166 dojo.provide("custom.TestNameReadStore");
167 dojo.declare("custom.TestNameReadStore", dojox.data.QueryReadStore, {
168 fetch:function (request) {
169 request.serverQuery = { test:request.query.name };
170 return this.inherited("fetch", arguments);
176 This class is simply an extension of Dojo's own QueryReadStore,
177 which is itself an abstract class. We simply define a method by
178 which to request, and assigning it to the 'test' element.
182 Next, let's create the form element for which we want
186 <programlisting language="php"><![CDATA[
187 class TestController extends Zend_Controller_Action
191 public function getForm()
193 if (null === $this->_form) {
194 $this->_form = new Zend_Form();
195 $this->_form->setMethod('get')
197 $this->getRequest()->getBaseUrl() . '/test/process'
200 'test' => array('type' => 'text', 'options' => array(
201 'filters' => array('StringTrim'),
202 'dojoType' => array('dijit.form.ComboBox'),
203 'store' => 'testStore',
204 'autoComplete' => 'false',
205 'hasDownArrow' => 'true',
206 'label' => 'Your input:',
208 'go' => array('type' => 'submit',
209 'options' => array('label' => 'Go!'))
218 Here, we simply create a form with 'test' and 'go' methods. The
219 'test' method adds several special, Dojo-specific attributes:
220 dojoType, store, autoComplete, and hasDownArrow. The dojoType is
221 used to indicate that we are creating a ComboBox, and we will
222 link it to a data store (key 'store') of 'testStore' -- more on
223 that later. Specifying 'autoComplete' as <constant>FALSE</constant> tells
224 Dojo not to automatically select the first match, but instead show a list of
225 matches. Finally, 'hasDownArrow' creates a down arrow similar to
226 a select box so we can show and hide the matches.
230 Let's add a method to display the form, as well as an end point
231 for processing AutoCompletion:
234 <programlisting language="php"><![CDATA[
235 class TestController extends Zend_Controller_Action
242 public function indexAction()
244 $this->view->form = $this->getForm();
247 public function autocompleteAction()
249 if ('ajax' != $this->_getParam('format', false)) {
250 return $this->_helper->redirector('index');
252 if ($this->getRequest()->isPost()) {
253 return $this->_helper->redirector('index');
256 $match = trim($this->getRequest()->getQuery('test', ''));
259 foreach ($this->getData() as $datum) {
260 if (0 === strpos($datum, $match)) {
264 $this->_helper->autoCompleteDojo($matches);
270 In our <methodname>autocompleteAction()</methodname> we do a number of
271 things. First, we look to make sure we have a post request, and
272 that there is a 'format' parameter set to the value 'ajax';
273 these are simply to help reduce spurious queries to the action.
274 Next, we check for a 'test' parameter, and compare it against
275 our data. (I purposely leave out the implementation of
276 <methodname>getData()</methodname> here -- it could be any sort of data
277 source.) Finally, we send our matches to our AutoCompletion
282 Now that we have all the pieces on the backend, let's look at
283 what we need to deliver in our view script for the landing page.
284 First, we need to setup our data store, then render our form,
285 and finally ensure that the appropriate Dojo libraries --
286 including our custom data store -- get loaded. Let's look at the
287 view script, which comments the steps:
290 <programlisting language="php"><![CDATA[
291 <?php // setup our data store: ?>
292 <div dojoType="custom.TestNameReadStore" jsId="testStore"
293 url="<?php echo $this->baseUrl() ?>/unit-test/autocomplete/format/ajax"
294 requestMethod="get"></div>
296 <?php // render our form: ?>
297 <?php echo $this->form ?>
299 <?php // setup Dojo-related CSS to load in HTML head: ?>
300 <?php $this->headStyle()->captureStart() ?>
301 @import "<?php echo $this->baseUrl()
302 ?>/javascript/dijit/themes/tundra/tundra.css";
303 @import "<?php echo $this->baseUrl() ?>/javascript/dojo/resources/dojo.css";
304 <?php $this->headStyle()->captureEnd() ?>
306 <?php // setup javascript to load in HTML head, including all required
307 // Dojo libraries: ?>
308 <?php $this->headScript()
309 ->setAllowArbitraryAttributes(true)
310 ->appendFile($this->baseUrl() . '/javascript/dojo/dojo.js',
312 array('djConfig' => 'parseOnLoad: true'))
314 djConfig.usePlainJson=true;
315 dojo.registerModulePath("custom","../custom");
316 dojo.require("dojo.parser");
317 dojo.require("dojox.data.QueryReadStore");
318 dojo.require("dijit.form.ComboBox");
319 dojo.require("custom.TestNameReadStore");
320 <?php $this->headScript()->captureEnd() ?>
324 Note the calls to view helpers such as headStyle and headScript;
325 these are placeholders, which we can then render in the <acronym>HTML</acronym>
326 head section of our layout view script.
330 We now have all the pieces to get Dojo AutoCompletion working.
335 <sect4 id="zend.controller.actionhelpers.autocomplete.scriptaculous">
336 <title>AutoCompletion with Scriptaculous</title>
340 url="http://wiki.script.aculo.us/scriptaculous/show/Ajax.Autocompleter">Scriptaculous</ulink>
341 expects an <acronym>HTML</acronym> response in a specific format.
345 The helper to use with this library is 'AutoCompleteScriptaculous'.
346 Simply provide it an array of data, and the helper will create an
347 <acronym>HTML</acronym> response compatible with Ajax.Autocompleter.