簡體   English   中英

如何在 AngularJS 的遞歸指令中傳遞函數引用?

[英]How to pass a function reference in a recursive directive in AngularJS?

我有這個指令:

app.directive('recursiveListItem', ['$http', 'RecursionHelper', function ($http, RecursionHelper) {
    return {
        restrict: 'E',
        scope: {
            parent: '=',
            onNodeClick: '&',
        },
        compile: function (element, attributes) {
            return RecursionHelper.compile(element);
        },
        template:
            '<div class="list-group-item-heading text-muted parent "> \
                <input type="checkbox" data-ng-click="visible = !visible" id="{{parent.Name}}">\
                <label for="{{parent.Name}}">&nbsp;&nbsp;</label>\
                <a href="javascript:void(0)" data-ng-click="onNodeClick({node: parent})">{{parent.Name}}</a> \
            </div> \
            <ul data-ng-if="parent.Children.length > 0" data-ng-show="visible"> \
                <li ng-repeat="child in parent.Children"> \
                    <recursive-list-item data-parent="child" data-on-node-click="onNodeClick"></recursive-list-item> \
                </li> \
            </ul>',     
    };
}]);

這是幫手:

app.factory('RecursionHelper', ['$compile', function ($compile) {
    var RecursionHelper = {
        compile: function (element) {
            var contents = element.contents().remove();
            var compiledContents;
            return function (scope, element) {
                if (!compiledContents) {
                    compiledContents = $compile(contents);
                }
                compiledContents(scope, function (clone) {
                    element.append(clone);
                });
            };
        }
    };

    return RecursionHelper;
}]);

一切都像一個魅力,但我沒有讓我on-node-click工作。 對於所有根項目,“回調”工作正常,但從那時起,所有子項都不會觸發回調。 我認為這與將函數引用傳遞給模板中的下一個孩子有關。

我也試過data-on-node-click="onNodeClick(node)" ,但這也不起作用。

有人知道如何將函數引用傳遞給子節點嗎?

潛在問題

作為查看文檔以這種方式描述的 '&' 的幫助的引導:

& 或 &attr - 提供了一種在父作用域的上下文中執行表達式的方法。

通常希望通過表達式將數據從隔離作用域傳遞到父作用域,這可以通過將局部變量名稱和值的映射傳遞到表達式包裝器 fn 中來完成。 例如,如果表達式是 increment(amount) 那么我們可以通過將 localFn 調用為 localFn({amount: 22}) 來指定數量值

為了實現這一點,通過&傳遞的函數被包裝在另一個函數parentGet() 我們可以通過查看點擊處理函數變量的內容來看到這一點。 首先,在它被傳遞到&之前,正如我們所期望的:

function (node) {
    console.log("called with ",node);
} 

但是,然后,在您的指令中,通過 '&' 后,它看起來像這樣:

function (locals) {
     return parentGet(scope, locals);
} 

因此,現在不是直接引用您的單擊處理程序函數,而是使用父作用域和您傳入的任何locals變量來應用您的函數的調用

問題是,據我所知,當我們嵌套該作用域變量時,它會不斷更新到新的嵌套父作用域。 那對我們不利。 我們希望執行上下文是您的點擊處理程序所在的頂級范圍。 否則,我們將失去對您的功能的引用——正如我們所看到的那樣。

解決方案

為了解決這個問題,我們保留對原始函數的引用parentGet()當我們嵌套時,它不受parentGet() )。 然后當我們傳入時, parentGet()使用的作用域就是上面有點擊處理函數的作用域。

首先,讓我們為實際函數使用與用於參數不同的名稱。 我像這樣設置函數$scope.onNodeClickFn = function(node) {...}

然后我們做3個改變:

1)添加第二個作用域變量 ( topFunc ):

scope: {
          onNodeClick: '&',
          topFunc: '='
       }

onNodeClick是包裝函數(包括范圍參數)。 topFunc是對解包函數的引用(請注意,我們在 using =傳遞了它,因此它是對缺少&應用的包裝器的函數的引用)。

2)在頂層,我們傳入兩個函數引用。

<recursive-list-item on-node-click="onNodeClickFn(node)" top-func="onNodeClickFn" parent=parent ></recursive-list-item>

(注意top-func參數上缺少 ()。)

3)將新的topFunc參數傳遞給模板:

<recursive-list-item data-parent="child" data-on-node-click="topFunc(node)" top-func="topFunc"></recursive-list-item> \

所以我們現在在每個嵌套范圍內維護一個對原始函數的引用,並在模板中使用它

你可以看到它在這個小提琴中工作: http : //jsfiddle.net/uf6Dn/9/

我只是用一個問卷應用程序做同樣的事情,我保持函數在隔離范圍內通過所有級別傳遞的方式是將函數放在每個項目中的 function({param:param}) 表示法

在你也可以是:

 <ul data-ng-if="parent.Children.length > 0" data-ng-show="visible"> \
            <li ng-repeat="child in parent.Children"> \
                <recursive-list-item data-parent="child" data-on-node-click="onNodeClick({param:param})"></recursive-list-item> \
            </li> \
        </ul>',  

從主控制器(正在添加指令的頁面) onNodeClick具有將設置到指令中的參數,您必須在根指令的 on-node-click 屬性中指定名稱,類似這樣

on-node-click="onNodeClick(param1,param2)"

在指令控制器中,您也可以調用它:

onNodeClick({param1: value1, param2:value2})

否則,如果 onNodeClick 僅影響主控制器(添加指令的頁面)中的變量,您可以將函數的名稱傳遞給指令,該函數的名稱存在於主控制器范圍內,並在指令控制器中不帶參數的情況下使用它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM