Javascript 如何在指令中执行递归?

Javascript 如何在指令中执行递归?,javascript,angularjs,Javascript,Angularjs,我们有一个接收字典的指令 我们认为directivy可以递归地调用自己,但它不起作用 我们目前的数据结构是: var cubicApp = angular.module('CubicApp', ['autocomplete']).controller('PreviewForecastCtrl', function ($scope, $http) { $scope.name = 'Thiago'; $scope.performance = { headers: [

我们有一个接收字典的指令

我们认为directivy可以递归地调用自己,但它不起作用

我们目前的数据结构是:

var cubicApp = angular.module('CubicApp', ['autocomplete']).controller('PreviewForecastCtrl', function ($scope, $http) {
    $scope.name = 'Thiago';

    $scope.performance = {
        headers: [{ name: '', colspan: 1 }, { name: 'Week result', colspan: 6 }, { name: '2017', colspan: 13 }, { name: 'General', colspan: 4 }],
        subheaders: [
            { name: 'Product', colspan: 1 },
            { name: '29-May', colspan: 1 },
            { name: '30-May', colspan: 1 },
            { name: '31-May', colspan: 1 },
            { name: '01-Jun', colspan: 1 },
            { name: '02-Jun', colspan: 1 },
            { name: 'Total', colspan: 1 },
            { name: 'Jan', colspan: 1 },
            { name: 'Feb', colspan: 1 },
            { name: 'Mar', colspan: 1 },
            { name: 'Apr', colspan: 1 },
            { name: 'May', colspan: 1 },
            { name: 'Jun', colspan: 1 },
            { name: 'Jul', colspan: 1 },
            { name: 'Aug', colspan: 1 },
            { name: 'Sep', colspan: 1 },
            { name: 'Oct', colspan: 1 },
            { name: 'Nov', colspan: 1 },
            { name: 'Dec', colspan: 1 },
            { name: 'Year', colspan: 1 },
            { name: '1M', colspan: 1 },
            { name: '6M', colspan: 1 },
            { name: '12M', colspan: 1 },
            { name: 'Accum.', colspan: 1 }
        ],
        books: [
            {
                name: 'Renda Variável',
                css: 'primary',
                totals: Array.from({length: 23}, () => Math.random()),
                books: [
                    {
                        name: 'Ibovespa Ativo',
                        css: 'active',
                        totals: Array.from({ length: 23 }, () => Math.random()),
                        books: [
                            {
                                name: 'BOVA11 (Equity)',
                                css: '',
                                totals: Array.from({ length: 23 }, () => Math.random()),
                                books: []
                            },
                            {
                                name: 'Cash BRL (Cash)',
                                css: '',
                                totals: Array.from({ length: 23 }, () => Math.random()),
                                books: []
                            }
                        ]
                    }
                ]
            }
        ]
    };

    $scope.loadInfo = function () {

    };
});
这些指示是:

cubicApp.directive('drillDownTable', function ($document) {
    return {
        restrict: 'E',
        transclude: true,
        scope: {
            data: '=',
        },
        templateUrl: '../../Scripts/app/templates/drill-down-table.html'
    };
}).directive('inner', function ($document, $compile) {
    return {
        restrict: 'A',
        transclude: true,
        scope: {
            inner: '=',
        },
        templateUrl: '../../Scripts/app/templates/drill-down-inner-table.html'
    };
});;
向下钻取表格.html

<table class="table table-hover table-bordered jambo_table">
    <thead>
        <tr>
            <th ng-repeat="h in data.headers" colspan="{{h.colspan}}" style="text-align:center !important">{{h.name}}</th>
        </tr>
        <tr>
            <th ng-repeat="h in data.subheaders" colspan="{{h.colspan}}" style="text-align:center !important">{{h.name}}</th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="book in data.books" inner="book"></tr>
    </tbody>
</table>
<tr>
    <td>{{inner.name}}</td>
    <td ng-repeat="t in inner.totals">{{t | number : 2}}</td>
</tr>
<tr ng-repeat="book in inner.books" inner="book"></tr>
<table class="table table-hover table-bordered jambo_table">
    <thead>
        <tr>
            <th ng-repeat="h in data.headers" colspan="{{h.colspan}}" style="text-align:center !important">{{h.name}}</th>
        </tr>
        <tr>
            <th ng-repeat="h in data.subheaders" colspan="{{h.colspan}}" style="text-align:center !important">{{h.name}}</th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="book in data.books">
            <td colspan="{{data.subheaders.length}}">
                <inner inner="book"></inner>
            </td>
        </tr>
    </tbody>
</table>
<table>
    <tbody>
        <tr>
            <td colspan="{{ inner.totals.length }}">{{inner.name}}</td>
        </tr>
        <tr>
            <td ng-repeat="t in inner.totals">{{t | number : 2}}</td>
        </tr>
        <tr ng-repeat="book in inner.books" >
            <td colspan="{{ inner.totals.length }}">
                <inner inner="book" ng-if="book"></inner>
            </td>
        </tr>
    </tbody>
</table>

我认为,将指令类型限制为
A
,并将其放在与
ng repeat
相同的元素上是导致问题的原因。当我创建指令类型
E
,并更改模板时,它工作正常(参见下面的Plunker)

当然,将指令移动到ng repeat中的元素会导致表中所有内容保持对齐的问题,因为您试图递归地遍历对象并输出

我的建议是编写一个递归函数,将递归的
data.books
结构转换为一个数组,该数组可以很好地处理单个
ng repeat
。您可能能够让您的原始方法工作,但我怀疑将其转换为数组比创建正确工作的递归指令花费的时间要少。主要的缺点是,如果
data.books
发生更改,则保持递归结构最新。为了解决这个问题,我的建议是提前弄清楚是什么原因导致
data.books
发生更改(因此您不必
$watch
它),并在每次更改时调用递归函数

另一种选择可能是使用一些CSS将我下面的内容设计成您想要的视觉效果(为所有列提供适当的宽度,担心边框等)

HTML:

指令:

cubicApp.directive('drillDownTable', function ($document) {
    return {
        restrict: 'E',
        transclude: true,
        scope: {
            data: '=',
        },
        templateUrl: 'drill-down-table.html'
    };
}).directive('inner', function ($document, $compile) {
    return {
        restrict: 'E',
        transclude: true,
        scope: {
            inner: '=',
        },
        templateUrl: 'drill-down-inner-table.html'
    };
});;
向下钻取表格.html

<table class="table table-hover table-bordered jambo_table">
    <thead>
        <tr>
            <th ng-repeat="h in data.headers" colspan="{{h.colspan}}" style="text-align:center !important">{{h.name}}</th>
        </tr>
        <tr>
            <th ng-repeat="h in data.subheaders" colspan="{{h.colspan}}" style="text-align:center !important">{{h.name}}</th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="book in data.books" inner="book"></tr>
    </tbody>
</table>
<tr>
    <td>{{inner.name}}</td>
    <td ng-repeat="t in inner.totals">{{t | number : 2}}</td>
</tr>
<tr ng-repeat="book in inner.books" inner="book"></tr>
<table class="table table-hover table-bordered jambo_table">
    <thead>
        <tr>
            <th ng-repeat="h in data.headers" colspan="{{h.colspan}}" style="text-align:center !important">{{h.name}}</th>
        </tr>
        <tr>
            <th ng-repeat="h in data.subheaders" colspan="{{h.colspan}}" style="text-align:center !important">{{h.name}}</th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="book in data.books">
            <td colspan="{{data.subheaders.length}}">
                <inner inner="book"></inner>
            </td>
        </tr>
    </tbody>
</table>
<table>
    <tbody>
        <tr>
            <td colspan="{{ inner.totals.length }}">{{inner.name}}</td>
        </tr>
        <tr>
            <td ng-repeat="t in inner.totals">{{t | number : 2}}</td>
        </tr>
        <tr ng-repeat="book in inner.books" >
            <td colspan="{{ inner.totals.length }}">
                <inner inner="book" ng-if="book"></inner>
            </td>
        </tr>
    </tbody>
</table>

注意
ng if=“book”
可能没有必要;我在排除故障时补充了这一点。

为什么不简单地迭代“data.internal”??就像
ng repeat=data.internal.totals中的total,因为每个
book
孩子可能都有
book
Oh!!没错。控制台向您显示错误?不,没有错误。我找到了一些,但它不是为我工作。这可能是有用的(实现一个服务,我测试了朋克添加“儿童到内部儿童”),我花了一些时间让它工作,但它工作得令人惊讶!非常感谢你!我很高兴你不客气!我很高兴能帮上忙!您是否最终使用了递归指令?如果是的话,我印象深刻。嗯,到目前为止它还在使用,但我想知道ux的人是否会把它留在那里