AngularJS 组件嵌套

AngularJS component nesting

我创建了一个组件搜索上下文,效果很好。它是可配置的,它会做它应该做的事情。

<search-context context-name="Groups"
    compare-columns="['displayName']"
    search-manager="$ctrl"
    query-url="/group/search/{{contextId}}"
    icon="fa fa-users"
    on-resolve-item-url="resolveItemUrl(row)"></search-context>

这是独立运行的。

还有其他各种搜索上下文,我想创建一个搜索管理器组件,这样我就可以像这样编写标记:

<search-manager>
    <search-context context-name="Devices"
                    compare-columns="['displayName']"
                    search-manager="$ctrl"
                    query-url="/device/search/{{contextId}}"
                    icon="fa fa-laptop"></search-context>
    <search-context context-name="Groups"
                    compare-columns="['displayName']"
                    search-manager="$ctrl"
                    query-url="/group/search/{{contextId}}"
                    icon="fa fa-users"
                    on-resolve-item-url="resolveGroupEditUrl(row)"></search-context>
</search-manager>

搜索上下文的一般计划是检查它是否有搜索管理器,如果有,则抑制它自己的 input/button 控件,搜索管理器将提供输入控件并提供搜索词搜索上下文。

AngularJS 组件文档中的示例演示了在控件模板中使用 ng-repeat 的 dynamic 子控件,但尚不清楚如何进行设置以处理像我建议的那样的显式标记。如果可能的话,我宁愿不需要显式指定 search-manager="$ctrl" 父引用。

如何解决这个问题?必须研究和理解哪些支持主题?只是关键概念名称会有很大帮助,但概述和进一步阅读列表会很棒。

我第一次尝试 search-manager 的模板看起来像这样

<div>
    <div class="panel-heading">
        <h3 class="panel-title">Search</h3>
        <div class="input-group">
            <input class="form-control" ng-model="$ctrl.term" />
            <span class="input-group-btn" ng-click="$ctrl.search()">
                <button class="btn btn-default">
                    <i class="fa fa-search"></i>
                </button>
            </span>
        </div>
    </div>
    <div class="panel-body">
        <ng-transclude></ng-transclude>
    </div>

</div>

代码如下所示

function SearchManagerController($scope, $element, $attrs, $http) {
    var ctrl = this;
    ctrl.searchContext = [];
    ctrl.registerSearchContext = function (searchContext) {
        ctrl.searchContext.push(searchContext);
    }
    ctrl.search = function () {
        ctrl.searchContext.forEach(function (searchContext) {
            searchContext.search(ctrl.term);
        });
    };
}
angular.module("app").component("searchManager", {
    templateUrl: "/app/components/search-manager.html",
    controller: SearchManagerController,
    transclude: true,
    bindings: {
        term: "@"
    }
});

子组件已被嵌入,但它们需要对 search-manager 组件的引用,并且 $ctrl 不在范围内。

我们如何获得对父级的引用?

要获得对父级的引用,您需要做的就是 require search-context 声明中的父级。双脱字符前缀表示搜索父对象。单个插入符号从当前对象开始,该对象可以工作但效率稍低。问号表示找不到不要吐,只是 return 未定义。当组件可能不总是由搜索管理器作为父级时,这是必要的。

angular.module("app").component("searchContext", {
    templateUrl: "/app/components/search-context.html",
    controller: SearchContextController,
    require: {
        searchManagerCtrl: "?^^searchManager"
    },
    bindings: {
        ...
    }
});

但是,如果您需要父级引用子级怎么办?

SearchContextController 中,我们实现 $onInit 生命周期事件处理程序。

    ctrl.$onInit = function () {
        if (ctrl.searchManagerCtrl) {
            ctrl.searchManagerCtrl.registerSearchContext(ctrl);
        }
    };

registerSearchContext 是为此目的在父控制器中定义的方法。该实现实质上将每个已注册的控件推送到我们在其范围内定义的数组 属性 中,然后父项的方法可以枚举子项。

对于指令,这个 require 技巧的表达方式略有不同。您必须在指令范围内声明 属性 searchManagerCtrl,并直接提供表达式作为 require 的值。

require: "?^^searchManager",

您还必须提供 link 函数。 link 函数的参数之一是 controller 并且将在该参数中传递对 searchManager 的引用,此时您可以将其分配给 属性指导范围。 $onInit 生命周期事件仍然可用于向搜索管理器注册,但指的是 $scope 而不是 ctrl