基于Drupal的AngularJS应用开发

作者:Will Vincent
译者:理查

AngularJS可以和Drupal一起使用,更确切的说法是可以很容易的建立在Drupal之上。

最近我有一些机会接触一些使用JS处理和显示数据的任务,Angular非常适合这个场景。不仅仅如此,而且Drupal也很容易的构建各种内容类型,然后为Angular应用准备数据。Drupal和Angular一起使用是高效和有趣的。

你以前可能听说过,Drupal网站的慢主要是因为主题层,我是支持这个观点的。所以当你第一次碰到建立于Drupal之上的Angular项目时,你可能会说Drupal这么重,应该会很慢吧,实际上不是的,特别是你的数据请求不会经过它的主题层的时候。

因此,我们终于回到了本文的主题,将Drupal用于后端作为数据源,AngularJS作为前端表现层。然而这有点超出我对他们的实践。本文假定这是可行的,但不在本文的讨论范围之内。

本文不会特别深入到每个细节,只是站在比较高的层次说一说我的几个观点和看法。

下面,我们正式开始。

AngularJS项目由来自Google的几个大神领导,是尽年来我最喜欢的框架和工具,它很难理解,但是一旦你使用它,它真的非常的强大,非常的灵活。和大多数JS框架和库一样,Angular也通过JSON传递数据。

非常幸运的是,用PHP生成JSON数据也很简单,尤其是对Drupal来说。

我们需要自定义一个menu回调,其只输出JSON,不经过主题层。这完全没有问题,只需要在hook_menu()里简单的使用下面一句代码即可。

'delivery callback' => 'drupal_json_output',

这句话的意思是,我们不把menu回调返回的值传递给Drupal主题层,而是通过json_encode处理数据,设置适合的响应头,然后输出编码后的数据,最后执行exit。这将大大提高请求的响应速度,因为我们不必经过主题层的循环遍历数组和渲染元素。

Angular真正强大的地方在于其双向绑定的能力,以及非常快的处理数据,无论是过滤,排序还是遍历,总之就是一个字:快。

其也具有非常强大的可扩展性的,其内置了一个简化版的jQuery(对Drupal来说,这不是很重要的特性,因为Drupal默认就加载完整版的jQuery了)。

许多没做过Drupal下Javascript开发的人可能不知道,Drupal提供了几个非常有用的JS函数,典型的例子是t()和formatPlural()。他们的作用和PHP版本的函数是一样的。

因为我正在讨论的是Angular与Drupal配合,我将主要说说t(),并分享一个最近在我另一个Angular应用中实现的一个使用t()的方法。显然在Drupal 7里,t()是Drupal对象的一部分,但是更专业的做法不是直接用,而是将其引入Angular作用域。

下面是一个Angular控制器的例子,其将Drupal的t函数暴露给本地作用域变量。

app.controller('MainCtrl', function($scope, $window) {
  $scope.t = function(str) {
    return $window.Drupal.t(str);
  };
});

这里最重要的就是注入$window到你的控制器,然后你才能在里面访问全局的Drupal对象。虽然你不这么做也是可以访问全局对象的,但这么做的好处是你可以更好的写单元测试。(译者注:单元测试也是Angular的一大特色)

然后可以在作用域里传一些值给作用域变量,然后这些变量可以在模板里直接使用或传递给Drupal函数,而且不需要带这个奇怪作用域变量,例如:

<p>By exposing Drupal's t() function to Angular, now we can have:</p>
<ul>
  <li>{{ t('Translatable Titles!') }}</li>
  <li>{{ t('Translatable form labels') }}</li>
  <li>{{ t(some_var) }}</li><!-- even translatable variable values! -->
</ul>

非常简洁,不是么?

你可以用Angular和Drupal配合做许多事情,他们不是一个完美的组合,但是如果你能用好它们,它们就能在一起良好的为你工作。

接下来是原文作者的两个作品,就不议了,直接看看就行了。

补充一个原文中Howard Tyson的回复内容:

可以用Angular filter机制封装t函数,做法如下:

app.filter('t', function($window) {
  return function(input) {
    return $window.Drupal.t(input);
  };
};

然后只需要

<li>{{ 'Translatable Titles!' | t }}</li>