如何将$ scope变量传递给custom指令的字符串模板?

时间:2014-02-05 10:38:28

标签: javascript angularjs angularjs-directive angularjs-ng-repeat

问题

  • 我有一个项目列表,使用ng-repeat
  • 构建
  • 每个项目都有一个上下文菜单,其中包含编辑/删除项目链接。
  • 上下文菜单是使用dropdown-list等对象数组中的自定义{title: "Link title", href: "/some-href"}指令构建的。

我需要将ng-href(在我的情况下为project.id)的动态参数传递到我在ng-repeat中使用的指令模板中。我怎样才能做到这一点?

这是我的一般性问题。我觉得我在这里对Angular JS概念有很大的误解,并依靠你的帮助。

我尝试了什么

我已经尝试将字符串数组传递到我的指令中,并且我得到了像这样的未解析的href:

/projects/%7B%7B%20project.id%20%7D%7D/edit

为什么?

项目-template.html

<li ng-repeat="project in data.projects">
    <a ng-href="/projects/{{ project.id }}">{{ project.title }}</a>
    <a dropdown-list="projectContextMenu"></a>

projects.controller.js

$scope.projectContextMenu = [
    {
      text: "Edit",
      href: "/projects/{{ project.id }}/edit"
    }, {
      text: "Delete",
      href: "/projects/{{ project.id }}/delete"
    }
  ];

我也试过

传递一个函数返回一个已解析的字符串数组,但得到一个无限的递归错误:

10 $digest() iterations reached. Aborting!

怎么回事?

项目-template.html

<li ng-repeat="project in data.projects">
    <a ng-href="/projects/{{ project.id }}">{{ project.title }}</a>
    <a dropdown-list="projectGetContextMenu(project.id)"></a>       

projects.controller.js

$scope.projectGetContextMenu = function(projectID){
    return [
        {
          text: "Edit",
          href: "/projects/" + projectID + "/edit"
        }, {
          text: "Delete",
          href: "/projects/" + projectID + "/delete"
        }
      ];
}

下拉指令代码

angular.module("ngDropdowns", []).directive("dropdownList", [
    "$compile", "$document", function($compile, $document) {
      var template;
      template =
        "<ul>"+
        "  <li ng-repeat='dropdownItem in dropdownList' ng-class='{ \"active\": dropdownModel && dropdownModel.value == dropdownItem.value }'>"+
        "    <a href='' ng-href='{{ dropdownItem.href }}' ng-click='itemSelect(dropdownItem)'>{{ dropdownItem.text }}</a>"+
        "</ul>";
      return {
        restrict: "A",
        replace: false,
        scope: {
          dropdownList: "=",
          dropdownModel: "="
        },
        controller: [
          "$scope", "$element", "$attrs", function($scope, $element, $attrs) {
            var $template, $wrap;
            $template = angular.element(template);
            $template.data("$dropdownListController", this);
            $element.addClass("dropdown_selected").wrap("<div></div>");
            $wrap = $element.parent();
            $wrap.append($compile($template)($scope));
            $scope.itemSelect = function(dropdownItem) {
              if (dropdownItem.href) {
                return;
              }
              angular.copy(dropdownItem, $scope.dropdownModel);
              $wrap.removeClass("dropdown__active");
            };
            $document.find("body").on("click", function() {
              $wrap.removeClass("dropdown__active");
            });
            $element.on("click", function(event) {
              event.stopPropagation();
              $wrap.toggleClass("dropdown__active");
            });
            $wrap.on("click", function(event) {
              event.stopPropagation();
            });
          }
        ]
      };
    }
  ])

1 个答案:

答案 0 :(得分:1)

您的第二种方法更正确,因为您需要根据上下文构建不同的URL。但就像你看到的那样,你会进入一个无休止的消化周期。

这是因为您每次都会返回不同的数组引用

Angular认为它是不同的,所以需要另一个曲柄转动,再次调用你的函数,返回一个新的数组等等。

您的projectGetContextMenu函数需要缓存结果,并返回相同的引用。像这样:

var contextMenus = {};

$scope.projectGetContextMenu = function(projectID){
    if(!contextMenus[projectId]) {

      contextMenus[projectId] = [
        {
          text: "Edit",
          href: "/projects/" + projectID + "/edit"
        }, {
          text: "Delete",
          href: "/projects/" + projectID + "/delete"
        }
      ];
    }

    return contextMenus[projectId];
};