Practical symfony

第十八天:AJAX

You are currently browsing
the website for symfony 1

Visit the Symfony2 website


About

You are currently reading "Practical symfony" which is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License license.

Jobeet Links

Master symfony

Be trained by SensioLabs experts (2 to 6 day sessions -- French or English).
trainings.sensiolabs.com

Books on symfony

Learn more about symfony with the official guides.
books.sensiolabs.com

L'audit Qualité par SensioLabs

200 points de contrôle de votre applicatif web.
audit.sensiolabs.com

Chapter Content

安装jQuery

加载jQuery

Adding Behaviors

User Feedback

AJAX in an Action

测试AJAX

明天见

symfony training
Be trained by symfony experts
Feb 21: Köln (Getting Started with Symfony2 - English)
Feb 27: Köln (Mastering Symfony2 - English)
Mar 05: Köln (Web Development with Symfony2 - Deutsch)
Mar 05: Montreal (Web Development with Symfony2 - English)
Mar 05: Montreal (Getting Started with Symfony2 - English)
and more...

Search


powered by google
You are currently browsing "Practical symfony" in for the 1.2 version - Propel edition - Switch to ORM: - Switch to language:
Creative Commons License This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.
This version of symfony is not maintained anymore.
If some of your projects still use this version, consider upgrading as soon as possible.
Practical symfony (Propel edition)
Support symfony!
Buy this book
or donate.
Buy Practical symfony (Propel edition) from amazon.com

昨天,我们实现了一个非常强大的搜索引擎,感谢Zend Lucene库。

今天,我们要利用AJAX给搜索引擎增加实时响应 功能,加强搜索引擎的响应能力。

使用AJAX时,我们希望无论用户的浏览器是否支持JavaScript,搜索引擎都可以正常工作。 所有我们决定使用非侵入式 JavaScript 实现这个新功能。非侵入式JavaScript同时也可以很好的实现, CSS和JavaScript行为 与客户端HTML代码中分类。

安装jQuery

为了避免重复开发并做到浏览器兼容,我们将使用现有的JavaScript库——jQuery。 Symfony框架能与任何JavaScript库一起工作。

jQuery 网站,下载最新版本,将.js问放到web/js/目录中。

也可以使用sfJqueryReloadedPlugin 插件安装jQuery。

加载jQuery

因为所有页面都需要jQuery,所以我们将它放到layout的<head>标签中。注意, 使用include_javascripts()调用前,先插入use_javascript()函数:

<!-- apps/frontend/templates/layout.php -->
 
  <?php use_javascript('jquery-1.2.6.min.js') ?>
  <?php include_javascripts() ?>
</head>

我们可以直接用<script>标签调用jQuery,但使用use_javascript()辅助函数可以 保证同一个JavaScript文件不会被调用两次。

For performance reasons, you might also want to move the include_javascripts() helper call just before the ending </body> tag.

TIP 如果使用sfJqueryReloadedPlugin插件,在模板中使用use_helper(jQuery)调用jQuery。

Adding Behaviors

要实现实时搜索(live search),意味着每当用户在搜索框中有一个键入动作,程序 就要访问一次服务器;并将返回的内容更新到页面的选区,而不用刷新整个页面。

我们不需要使用on*()添加行为,jQuery可以在页面完全载入时,直接将行为 添加到DOM元素中。这样一来,如果浏览器不支持JavaScript,行为将不被添加, 搜索引擎还还会象以前那样工作。

首先,拦截用户在搜索框中的键入动作:

$('#search_keywords').keyup(function(key)
{
  if (this.value.length >= 3 || this.value == '')
  {
    // do something
  }
});

现在还不要添加代码,因为还要有做很多修改。最终的JavaScript代码,会在下一节添加到layout中。

每次键入内容,jQuery都会执行一次上面定义的匿名函数,但前提是用户键入内容超过3个 字符或input标签中内容被清空时。

要实现AJAX调用,只需在DOM元素上使用load()方法:

$('#search_keywords').keyup(function(key)
{
  if (this.value.length >= 3 || this.value == '')
  {
    $('#jobs').load(
      $(this).parents('form').attr('action'), { query: this.value + '*' }
    );
  }
});

因为AJAX调用和“正常”调用使用同一个动作,所以我们下面将对动作进行修改。

现在先来调整一下搜索按钮。当浏览器支持JavaScript时,让它隐藏起来:

$('.search input[type="submit"]').hide();

User Feedback

我们知道,从AJAX请求服务器到服务器返回响应(response)需要一段时间,所以页面内容都不会 马上更新。这段等待时间,你应该向用户显示一些提示信息(visual feedback),告诉用户请求正在执行。

常用的方法是在这段时间里,显示一个载入图标。下面我们在layout中加入载入图标,并在 不需要的时候隐藏该图标:

<!-- apps/frontend/templates/layout.php -->
<div class="search">
  <h2>Ask for a job</h2>
  <form action="<?php echo url_for('@job_search') ?>" method="get">
    <input type="text" name="query" value="<?php echo $sf_request->getParameter('query') ?>" id="search_keywords" />
    <input type="submit" value="search" />
    <img id="loader" src="/images/loader.gif" style="vertical-align: middle; display: none" />
    <div class="help">
      Enter some keywords (city, country, position, ...)
    </div>
  </form>
</div>

这个载入图标是专门为Jobeet设计的。你可以创建自己的图标,也有许多提供免费图标的网站,如 http://www.ajaxload.info/.

现在各部分都已经准备好了,创建一个search.js包含下面的JavaScript代码:

// web/js/search.js
$(document).ready(function()
{
  $('.search input[type="submit"]').hide();
 
  $('#search_keywords').keyup(function(key)
  {
    if (this.value.length >= 3 || this.value == '')
    {
      $('#loader').show();
      $('#jobs').load(
        $(this).parents('form').attr('action'),
        { query: this.value + '*' },
        function() { $('#loader').hide(); }
      );
    }
  });
});

你同样需要更新layout,引用这个新文件:

<!-- apps/frontend/templates/layout.php -->
<?php use_javascript('search.js') ?>

AJAX in an Action

如果浏览器支持JavaScript,jQuery将拦截搜索框的键盘输入,并调用search动作。如果 不支持,用户点击搜索按钮,程序也会调用这个search动作。

两种方式请求同一个动作,但需要返回的内容却不同,所以我们在search动作中使用 isXmlHttpRequest()进行判断。当AJAX调用时,isXmlHttpRequest()方法会返回true

isXmlHttpRequest()方法支持Prototype, Mootools和 jQuery这些主流JavaScript库。

// apps/frontend/modules/job/actions/actions.class.php
public function executeSearch(sfWebRequest $request)
{
  if (!$query = $request->getParameter('query'))
  {
    return $this->forward('job', 'index');
  }
 
  $this->jobs = JobeetJobPeer::getForLuceneQuery($query);
 
  if ($request->isXmlHttpRequest())
  {
    return $this->renderPartial('job/list', array('jobs' => $this->jobs));
  }
}

jQuery只更新#jobs DOM元素内容,不重新加载整个页面,页面不需要layout装饰。因此, 一般情况下AJAX请求动作时layout默认是关闭的。

此外,我们只需要返回job/list局部模板的内容,而不用返回整个模板。 renderPartial()方法将局部模板作为响应返回给客户端。

当用户清空搜索框,或没有匹配的结果时,我们需要显示一条提示信息。我们使用 renderText()方法设置一个简单的测试字符串:

// apps/frontend/modules/job/actions/actions.class.php
public function executeSearch(sfWebRequest $request)
{
  if (!$query = $request->getParameter('query'))
  {
    return $this->forward('job', 'index');
  }
 
  $this->jobs = JobeetJobPeer::getForLuceneQuery($query);
 
  if ($request->isXmlHttpRequest())
  {
    if ('*' == $query || !$this->jobs)
    {
      return $this->renderText('No results.');
    }
    else
    {
      return $this->renderPartial('job/list', array('jobs' => $this->jobs));
    }
  }
}

你也可以通过renderComponent()方法返回组件。

测试AJAX

因为Symfony浏览程序不能模拟JavaScript,你需要使用其它方法来测试AJAX。这意味着, 你需要手动添加jQuery或其它主流JavaScript库的请求头信息:

// test/functional/frontend/jobActionsTest.php
$browser->setHttpHeader('X_REQUESTED_WITH', 'XMLHttpRequest');
$browser->
  info('5 - Live search')->
 
  get('/search?query=sens*')->
  with('response')->begin()->
    checkElement('table tr', 2)->
  end()
;

setHttpHeader()方法为浏览器下一次请求(HTTP header)设置一个HTTP头。

明天见

昨天,我们使用Zend Lucene库实现了搜索引擎。今天,我们用jQuery提高了它的 响应能力。Symfony框架提供了所有轻松构建MVC程序的工具,也可以与其它组件 协调工作。总之,使用最好的工具,来完成这个工作。

明天,我们学习如果国际化Jobeet网站。

« 第十七天:搜索引擎

Questions & Feedback

If you find a typo or an error, please register and open a ticket.

If you need support or have a technical question, please post to the official user mailing-list.