开放的编程资料库

当前位置:我爱分享网 > PHP教程 > 正文

使用 Zend Framework 和 Dojo 自动补全

我已经解决了几个关于使用ZendFramework和Dojo设置自动完成器的问题,并决定是时候创建一个关于这个主题的HOWTO了,特别是因为您需要注意一些细微差别。

哪些dijit执行自动完成?

您的首要任务是选择能够自动完成的适当表单元素。Dijit提供了两个,ComboBoxFilteringSelect。但是,它们具有不同的功能:

  • ComboBox允许您输入任意文本;如果它与关联列表不匹配,它仍然被认为是有效的。提交的文本输入不是选项值。(这不同于普通的下拉选择。)
  • FilteringSelect也允许您输入任意文本,但只有当它与提供给它的选项匹配时才会被视为有效。optionvalue已提交,就像普通的下拉选择一样。

一旦您选择了合适的表单元素类型,您就需要指定一个dojo.data存储。dojo.data为dijits和其他dojo组件使用的数据结构提供一致的API。从本质上讲,它只是一个任意JSON结构的数组,每个结构都包含一个公共标识符字段,每个项目包含一个唯一值。在内部,ComboBoxFilteringSelect都可以利用dojo.data存储来填充它们的选项和/或提供匹配项。Dojo为此类目的提供了多种dojo.data存储。

定义表单元素

定义表单元素非常简单。从您的Zend_Dojo_Form实例(或您扩展该类的表单),像往常一样简单地调用addElement()。在本教程的后面,根据您使用的方法,您可能需要向元素定义添加一些信息,但现在,所需要的只是最基本的元素定义:

$form->addElement('ComboBox', 'myAutoCompleteField', array(
    'label' => 'My autocomplete field:',
));

向dojo.data存储提供数据

我们现在要逆向工作,因为在使用Zend_Dojo_Data时向数据存储提供数据相对微不足道。

首先,我们将在我们的控制器中创建一个动作,并将模型和查询参数分配给视图。我们将设置我们的dojo.data存储以通过GET参数q发送查询字符串,这就是我们将分配给视图的内容。

    public function autocompleteAction()
    {
        // First, get the model somehow
        $this->view->model = $this->getModel();

        // Then get the query, defaulting to an empty string
        $this->view->query = $this->_getParam('q', '');
    }

现在,让我们创建视图脚本。首先,我们将禁用布局;其次,我们将查询传递给模型;第三,我们将用我们的查询结果实例化我们的Zend_Dojo_Data对象;最后,我们将回显Zend_Dojo_Data实例。

<?php
// Disable layouts
$this->layout()->disableLayout();

// Fetch results from the model; again, merely illustrative
$results = $this->model->query($this->params);

// Now, create a Zend_Dojo_Data object.
// The first parameter is the name of the field that has a
// unique identifier. The second is the dataset. The third
// should be specified for autocompletion, and should be the
// name of the field representing the data to display in the
// dropdown. Note how it corresponds to \"name\" in the 
// AutocompleteReadStore.
$data = new Zend_Dojo_Data('id', $results, 'name');

// Send our output
echo $data;

这就是它的全部内容。实际上,您可以使用AjaxContext操作帮助程序自动执行其中的一些操作,从而使其更加简单。

使用dojox.data.QueryReadStore

我们现在有一个用于我们的dojo.data数据存储的端点,所以现在我们需要确定要使用的存储类型。

dojox.data.QueryReadStore是一个很棒的dojo.data存储,允许您对数据创建任意查询。它将查询创建为JSON对象:

{
    "query": { "name": "A*" },
    "queryOptions": { "ignoreCase": true },
    "sort": [{ "attribute": "name", "descending": false }],
    "start": 0,
    "count": 10
}

这在两个方面存在问题。首先,如果您要直接使用它,您将仅限于POST请求,将其作为原始帖子提交。其次,相关的是,这意味着请求无法缓存在客户端。

幸运的是,有一种简单的方法可以纠正这种情况:扩展dojox.data.QueryReadStore并重写fetch方法,将查询重写为一个简单的GET查询,使用单个参数。

dojo.provide("custom.AutocompleteReadStore");

dojo.declare(
    "custom.AutocompleteReadStore", // our class name
    dojox.data.QueryReadStore,      // what we're extending
    {
        fetch: function(request) {  // the fetch method
            // set the serverQuery, which sets query string parameters
            request.serverQuery = {q: request.query.name};

            // and then operate as normal:
            return this.inherited("fetch", arguments);
        }
    }
);

现在的问题是,在哪里创建这个定义?

您有两个选择:您可以内联自定义定义(不太直观)并手动将数据存储连接到表单元素,或者您可以创建一个实际的javascript类文件(稍微多一些工作)并让您的表单元素设置数据存储你。

内联自定义QueryReadStore类扩展

完成内联有点棘手,因为您需要以适当的顺序声明事物。使用此技术时,您需要执行以下操作:

  1. 需要dojox.data.QueryReadStore
  2. 定义一个全局JS变量,用于标识您的商店
  3. 使用dojo.providedojo.declare创建您的自定义数据存储扩展
  4. 定义一个onLoad事件来实例化数据存储并将其附加到表单元素

我们可以在输出表单的同一个视图脚本中执行上述所有操作:

<?php
$this->dojo()->requireModule("dojox.data.QueryReadStore");

// Define a new data store class, and 
// setup our autocompleter data store
$this->dojo()->javascriptCaptureStart() ?>
dojo.provide("custom.AutocompleteReadStore");
dojo.declare(
    "custom.AutocompleteReadStore", 
    dojox.data.QueryReadStore, 
    {
        fetch: function(request) {
            request.serverQuery = {q: request.query.name};
            return this.inherited("fetch", arguments);
        }
    }
);
var autocompleter;
<?php $this->dojo()->javascriptCaptureEnd();

// Once dijits have been created and all classes defined,
// instantiate the autocompleter and attach it to the element.
$this->dojo()->onLoadCaptureStart() ?>
function() {
    autocompleter = new custom.AutocompleteReadStore({
        url: "/test/autocomplete",
        requestMethod: "get"
    });
    dijit.byId("myAutoCompleteField").attr({
        store: autocompleter
    });
}
<?php $this->dojo()->onLoadCaptureEnd() ?>
<h1>Autocompletion Example</h1>
<div class="tundra">
<?php echo $this->form ?>
</div>

这很有效,并且是让自动完成为您的元素工作的权宜之计。但是,它违反了DRY原则,因为您不能在其他区域重复使用自定义类。那么,让我们看看更好的解决方案

创建可重用的自定义QueryReadStore类扩展

Dojo开发人员的建议是,您应该将此类创建为javascript类,并使用其他javascript代码。这样做的原因有很多:您可以在其他地方重复使用该类,也可以将其包含在自定义构建中——这将确保它被去除空格并打包,从而减少最终用户的下载量。

这个过程并不像最初听起来那么可怕。假设您的public/目录具有以下结构:

public/
    js/
        dojo/
            dojo.js
        dijit/
        dojox/

我们在这里要做的是为dojo子目录创建一个兄弟目录,称为custom"并在那里创建我们的类文件:

public/
    js/
        dojo/
            dojo.js
        dijit/
        dojox/
        custom/
            AutocompleteReadStore.js

我们将使用上面最初显示的定义,并将其简单地保存为public/js/custom/AutocompleteReadStore.js,并添加一个:在dojo.provide调用,添加这个:

dojo.require("dojox.data.QueryReadStore");

这类似于PHP中的require_once调用,并确保该类在声明自身之前具有所有依赖项。稍后,当我们在ComboBox元素中提示要使用的数据存储类型时,我们将利用这一事实。

在框架方面,我们将稍微更改我们的元素定义,以包含有关它将使用的dojo.data存储的信息:

$form->addElement('ComboBox', 'myAutoCompleteField', array(
    'label'     => 'My autocomplete field:',

    // The javascript identifier for the data store:
    'storeId'   => 'autocompleter',

    // The class type for the data store:
    'storeType' => 'custom.AutocompleteReadStore',

    // Parameters to use when initializint the data store:
    'storeParams' => array(
        'url'           => '/foo/autocomplete',
        'requestMethod' => 'get',
    ),
));

如果您一直密切关注,您会注意到“storeParams”与我们在内联时用于初始化数据存储的完全相同。不同之处在于,现在ComboBox视图助手将为您创建所有必要的Javascript。

视图脚本现在变得非常简单;我们不再需要设置任何javascript,并且可以从字面上简单地回应表单:

<?= $this->form ?>

希望现在应该清楚从长远来看哪种方法最简单。

后续步骤

dojox.data.QueryReadStore提供的不仅仅是简单地指定查询字符串。正如在介绍该组件时所指出的那样,它创建了一个JSON结构,该结构还包括用于排序的键、选择要显示的结果数量以及提取结果时的偏移量。这些也可以添加到您的查询字符串中,以允许更细粒度地选择结果——例如,您可以确保返回的结果不超过3或5个,以允许更易于管理的匹配列表,或指定排序顺序使得对用户更有意义。

总结

学习新工具可能很困难,Dojo和ZendFramework也不例外。但是,如果您使用ZendFramework,学习Dojo的一个令人信服的理由是它的结构和设计应该是熟悉的:它使用相同的1:1类名:文件名映射范例。此外,因为它是为利用强大的OOP原则而编写的,所以可以使用扩展类等熟悉的概念来自定义Dojo,以满足您站点的需求。

希望本教程能够对Dojo中的自动完成主题以及Dojo中的类扩展有所启发,并帮助您开始创建自己的自定义Dojo库以用于您的应用程序。

未经允许不得转载:我爱分享网 » 使用 Zend Framework 和 Dojo 自动补全

感觉很棒!可以赞赏支持我哟~

赞(0) 打赏