【问题标题】:Angular directives collaborationAngular 指令协作
【发布时间】:2013-05-02 15:19:10
【问题描述】:

所以我在这里尝试使用 Angular 实现自动完成建议,我需要您的专业知识。

这里是html:

<div my-autosuggest>
    <input type="text" my-autosuggest-input>
    <ol>
         <li ng-repeat"item in items" my-autosuggest-list>...</li>
    </ol>
</div>

我不想使用模板来生成&lt;li&gt; 元素。 (我希望它可以灵活地以任何顺序使用任何类型的元素,并且可能在列表和下拉列表之间使用一些其他额外元素)

困难的部分是响应输入上的箭头键以突出显示列表中的下一个/上一个元素。如何让另一个指令my-autosuggest-list 知道它应该从my-autosuggest-input 指令中选择下一个元素。

请注意,我可能在一个控制器中有多个自动建议,如下所示:

<div ng-controller="MyController">
   <div my-autosuggest>
       <input type="text" my-autosuggest-input>
       <ol>
            <li ng-repeat"item in items" my-autosuggest-list>...</li>
       </ol>
   </div>
   <div my-autosuggest>
       <ol>
            <li ng-repeat"item in items" my-autosuggest-list>...</li>
       </ol>
       <input type="text" my-autosuggest-input>
   </div>
</div>

到目前为止,我已尝试通过$watch 更改索引,但有时不会为列表中的某些元素调用手表(也许这是一个错误)。 $broadcast 不起作用,因为输入可能被包装在另一个控制器或另一个元素中,因此列表不会听到广播。

我还尝试在根范围内为每个自动建议放置一个变量,但指令的调用顺序并不总是从父级到子级,因此我无法初始化该变量并在每次 my-autosuggest 时创建一个新变量调用是因为 my-autosuggest-input 或其他可能在此之前调用。

感谢任何有关如何使用 Angular 进行设计的建议。

【问题讨论】:

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


    【解决方案1】:

    假设my-autosuggest-inputmy-autosuggest-list 总是在my-autosuggest 内。您可以使用一系列$emitted$broadcast 事件来完成此操作。

    my-autosuggest-input的链接函数中,当按下箭头键时添加一个$emit

    element.on('keyup', function () {
       // Figure out if this is an arrow key, if so:
       $scope.$emit('listSelect', { message: 'prevItem' }); // Or 'nextItem'
    });
    

    my-autosuggest链接函数或者控制器里面添加:

    // Add a controllerId, so that the listener doesn't handle its own events.
    $scope.controllerId = Math.random().toString();
    $scope.$on('listSelect', function (e, data) {
        if ($scope.controllerId !== data.controllerId) {
            $scope.$broadcast('listSelect', { 
                controllerId: $scope.controllerId,
                message: data.message 
            });
        }
    });
    

    最后,在my-autosuggest-list的链接函数或控制器里面添加:

    $scope.$on('listSelect', function (e, data) {
        if (data.message === 'nextItem') {
            // Highlight next item.
        } else {
            // Highlight previous item.
        }
    });
    

    在这种情况下,my-autosuggest 将任何 listSelect 事件从其任何子级路由到其所有子级。

    【讨论】:

    • 谢谢,这样就可以了,唯一的问题是主指令my-autosuggest 会以许多样板代码结束。对于由输入、下拉列表或列表触发的每个事件(如显示下拉列表、隐藏下拉列表、选择列表项,...),我需要将侦听器添加到 my-autosuggest 指令并重新广播它。如果您能想到任何其他解决方案来避免额外的样板代码,请告诉我。
    • 好像这样不行,$scope.$on('listSelect', function (e, data) { $scope.$broadcast('listSelect', data); });会导致无限循环
    • 我会使用不同的事件名称/数据值来减少样板文件。例如,您可以有一个名为“toList”的事件,该事件被发送到列表组件,并且与该事件一起发送的数据对象可能包含实际消息,例如“选择下一项”。您可以使用事件“routeAutoSuggest”和{ target: 'list', action: 'show next item' } 之类的数据对象使其非常通用。那么my-autosuggest 只需要有一个监听器。
    • 我刚刚更新了我的示例以避免无限循环。因为my-autosuggest 是re-$broadcasting 它正在侦听的同一事件,它需要能够判断该事件是否来自它自己并忽略它。该示例通过检查范围上的随机字符串来完成此操作。我相信还有其他方法可以做到这一点。
    • 谢谢,这样可以。我相信我需要将my-autosuggest 指令设置为scope: true 以创建一个新范围,除非可以为我在问题中遇到的第二个html sn-p 在同一范围内注册侦听器。为了处理我使用$emit 事件名称从子到父和父到子的无限循环。例如,当按下箭头键时,我$emit 一个selectNext_ 事件并在my-autosuggest 中收听selectNext_ 并重新广播selectNext(末尾没有下划线)。然后在列表中我只听selectNext
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-17
    • 2014-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-09
    • 2018-04-12
    相关资源
    最近更新 更多