将控制器/服务中的数据转换为指令?

时间:2014-05-05 23:25:13

标签: angularjs angularjs-directive angularjs-controller

我是AngularJS的初学者,我正在编写一个具有各种可重用组件的应用程序(例如,同一个表格可能会在屏幕上出现5次,列数略有不同 - 如有必要,我可以详细介绍)。其他人也想编写使用这些组件的代码。类似地,多个组件将希望从相同的源中提取数据,并且多个人将希望进行相同的REST调用以获取数据。

我想到的一般架构:

  • 可重用UI组件的指令;这些代码不会直接编辑
  • 获取相关数据的服务 - 例如,“AnimalService”会发出一些HTTP请求,获取JSON数据,并通过它定义的方法使调用者可以使用它。服务将是控制器的依赖性。我基本上将服务视为应该在控制器中使用以获取数据的“公共API”。使用它们的人不会修改这些内容。
  • 控制器和HTML将由使用上述指令和服务的人员编写,以便进行应用。

举一个简单的例子,一个指令会使用ng-repeat打印一个名单。服务将具有“公共”函数getNames(),该函数返回名称列表。我正在编写一个应用程序 - 我使用“canned”指令和服务,我编写了一个将服务作为依赖项的控制器,调用getNames()函数并将结果输出到指令。我的HTML页面只使用该指令,就像任何其他HTML元素一样。

我的主要问题 - 将数据导入指令的最佳方法是什么?我知道范围有很多选择,但是在我的控件中创建一个具有特定名称的变量并让它“神奇地”工作似乎是错误的。

在更广泛的层面上,这是一种合理的方法吗?我基本上将指令和服务视为开发人员将使用的公共API。

1 个答案:

答案 0 :(得分:5)

听起来你正在寻找的是隔离范围。在指令内定义了隔离范围,在视图中使用该指令时,隔离范围中的变量被指定为属性。

例如,请考虑以下指令:

myApp.directive('myTable', function () {
    return {
        restrict: 'E',
        replace: true,
        templateUrl: 'MyTable.html',
        scope: {
            foo: '=items'
        }
    };
});

该指令有几个属性。在这里,我将讨论范围属性,但您可以阅读其余内容(以及一般的指令)here

scope属性定义了隔离范围。隔离范围允许您映射来自外部控制器范围的值,允许您绑定它们而不必担心外部范围中实际存在的内容。这是一个抽象层,允许您的指令更灵活和可重用。

scope对象中的每个属性都定义了隔离范围内的某个内部属性与某个外部控制器的范围对象之间的映射。在上面的示例中,我们有一个名为foo的属性。属性定义的右侧("=items")声明了变量映射。这实际上是说,"在实例化该指令时,查找名为" items"的属性。在html元素上并将其值赋给名为" foo"的属性。关于隔离范围。

因此,例如,如果我们的指令模板(由上面的templateUrl属性指定)如下:

// MyTable.html

<table style="width:300px">
  <tr>
    <td ng-repeat="item in foo">{{item}}</td>
  </tr>
</table>

然后我们可以在我们的主html页面中使用这个指令,如下所示:

<div ng-controller="SomeGenericController">
  <my-table items="ourItems" />
</div>

请注意,我们已将items属性添加到指令中,并为其指定了值ourItems。现在,这里有一个澄清;当我们分配items="ourItems"时,我们必须在我们的控制器的名为ourItems的范围内拥有一些属性。因此,例如,我们的控制器可能如下所示:

myApp.controller('SomeGenericController', ['$scope', function ($scope) {
  $scope.ourItems = ['ball', 'shovel', 'towel'];
});

以上用法将显示一个表格,其中包含SomeGenericController项目数组中的项目。

使用此模式,我们可以指定任何旧数组来使用此表指令。假设我们有一些其他控制器,它有一个我们想要放在表中的项目数组:

myApp.controller('AccountsController', ['$scope', function ($scope) {
  $scope.names = ['john', 'jill', 'ted'];
  ...
  // some more stuff down here specific to this controller
});

现在,我们可以使用我们的table指令以及此控制器,方法是使用names属性将foo数组映射到隔离范围的items属性:

<div ng-controller="AccountsController">
  <my-table items="names" />
</div>

因此,这是创建可重用指令背后的总体思路。我们可以使用一些技巧来使它更清洁。例如,如果我们的属性映射的名称和隔离范围属性的名称相同,我们可以使用简写=而不是=items。在定义映射时我们还可以使用其他一些运算符,即@&,但是我可以让你自己查看这些运算符:)你也可以定义控制器内部包含并在指令定义中指定,以及我将留给您的更多信息:)

无论如何,希望这有帮助!