首页 > 解决方案 > AngularJS 组件嵌套

问题描述

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

<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>

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

AngularJS 组件文档中的示例演示了在控件模板中使用 ng-repeat 的动态子控件,但不清楚如何设置以处理我建议的显式标记。如果可能的话,我宁愿不需要明确指定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不在范围内。

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

标签: angularjsangular-componentsangularjs-ng-transclude

解决方案


要获得对父级的引用,您需要做的就是声明require中的父search-context级。双插入符号前缀意味着搜索父母。单个插入符号从当前对象开始,它可以工作但效率稍低。问号的意思是如果找不到就不要吐槽,直接返回 undefined。当组件可能并不总是由搜索管理器作为父级时,这是必要的。

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.


推荐阅读