1

我需要在标签单击时在单个页面中显示多个 angularjs 指令。它可以是 c3 图表指令和 ng 网格指令的组合。我正在控制器中准备具有所有这些相关参数的模型,然后形成模板,然后在控制器本身中编译,这完全可以正常工作。当我意识到在控制器中进行 DOM 操作不是一个好习惯时,我正在尝试在自定义指令中进行操作。

该指令应支持以下功能:

  1. 模板应该是 C3 图表指令的组合。
  2. 该模板还可以具有 Angularjs ng Grid 指令以及 c3 图表指令。
  3. 将来我还想使用 Good Map 指令以及 C3 图表和 ng 网格指令。
  4. 并且其中一些指令应该支持自定义下拉菜单。

现在我已经在我的控制器中使用了以下代码,它运行良好。

   var template = '<div class= "chartsDiv">';

    var dashletteId = 0;
    var dashletterName = "chart";
    var chartName = "";

    for (var dashVar = 0; dashVar < data.tabDetails.length; dashVar++) {
        dashletteId = data.tabDetails[dashVar].dashletteId; // Added
        dashletterName = data.tabDetails[dashVar].dashletteName;
        var axisType = data.tabDetails[dashVar].axisType;
        var dataType = data.tabDetails[dashVar].dataType;

        chartName = "chart" + eachTab.tabName.replace(/ +/g, "") + dashletteId ;

        $scope[chartName] = {};


        if (axisType == "timeseries") {

            var xticksClassiffication = data.tabDetails[dashVar].xticksClassification;
            var tickFormatFunction = {};               
            $scope[chartName] = {

                data: {
                    x: 'x',
                    columns: data.tabDetails[dashVar].columns,
                    type: data.tabDetails[dashVar].dataType
                },
                axis: {
                    x: {
                        type: data.tabDetails[dashVar].axisType,                          
                        tick: {
                            format: data.tabDetails[dashVar].xtickformat
                                // '%Y-%m-%d'

                        }
                    }
                },
                subchart: {
                    show: true
                }

            };

        }

        if (dashletteId == 7) {

            template += ' <div class="col"> <p class="graphtitle">' + dashletterName + '  </p> <span class="nullable">  <select ng-model="chartTypeSel" ng-options="eachChartType.name for eachChartType in chartTypeOptions" ng-change="transformChart(chartTypeSel, \'' + chartName + '\')"> </select> </span> <c3-simple id = "' + chartName + '" config="' + chartName + '"></c3-simple>  </div>'

        } else {

            template += ' <div class="col"> <p class="graphtitle">' + dashletterName + ' </p> <c3-simple id = "' + chartName + '" config="' + chartName + '"></c3-simple> </div>';
        }


    }

    template += ' </div>';
    angular.element(document.querySelectorAll('.snap-content')).append($compile(template)($scope));

为了简单起见,我只提供了一些示例代码。基于dashletteId,我有一些特定的要求,我根据dashletteId动态创建模板,所有这些代码对我来说都很好。现在我的目标是将所有这些模板形成和编译代码从控制器移动到自定义指令,我正在为此寻找最佳解决方案,任何人都可以建议我一些指向最佳解决方案的指针。

对于特定用户,当他单击任何选项卡时,必须为编译形成什么模板是预定义的。所以我可以在 ng-init 函数调用或选项卡的单击(即选择)函数调用期间得到它。

以下是我的 ng 网格模板形成的示例代码。

if (axisType == "table") {

        var config = {
            9: {
                gridOptions: 'gridOptionsOne',
                data: 'dataOne',
                columnDefs: 'colDefsOne'
            },
            10: {
                gridOptions: 'gridOptionsTwo',
                data: 'dataTwo',
                columnDefs: 'colDefsTwo'
            },
            11: {
                gridOptions: 'gridOptionsThree',
                data: 'dataThree',
                columnDefs: 'colDefsThree'
            },
            18: {
                gridOptions: 'gridOptionsFour',
                data: 'dataFour',
                columnDefs: 'colDefsFour'
            }
        };

        $scope.getColumnDefs = function(columns) {
            var columnDefs = [];

            columnDefs.push({
                field: 'mode',
                displayName: 'Mode',
                enableCellEdit: true,
                width: '10%'
            });
            columnDefs.push({
                field: 'service',
                displayName: 'Service',
                enableCellEdit: true,
                width: '10%'
            });

            angular.forEach(columns, function(value, key) {
                columnDefs.push({
                    field: key,
                    displayName: value,
                    enableCellEdit: true,
                    width: '10%'
                })
            });

            return columnDefs;
        };

        if (dataType == "nggridcomplex") {

            $scope.serverResponse = {
                columns: data.tabDetails[dashVar].columns,
                data: data.tabDetails[dashVar].data

            };

            $scope[config[dashletteId].columnDefs] = $scope.serverResponse.columns;
            $scope[config[dashletteId].data] = $scope.serverResponse.data;

        } else {
            if (dashletteId == 18) {
                $scope.serverResponse = {
                    columns: data.tabDetails[dashVar].timespans[0], // This is for column headers.
                    data: data.tabDetails[dashVar].columns
                };

            } else {
                $scope.serverResponse = {
                    columns: data.tabDetails[dashVar].timespans[0], // This is for column headers.
                    data: data.tabDetails[dashVar].columns
                };
            }


            $scope[config[dashletteId].columnDefs] = $scope.getColumnDefs($scope.serverResponse.columns);
            $scope[config[dashletteId].data] = $scope.serverResponse.data;
        }

        $scope[config[dashletteId].gridOptions] = {
            data: config[dashletteId].data,
            showGroupPanel: true,
            jqueryUIDraggable: false,
            columnDefs: config[dashletteId].columnDefs
        };

        template += ' <div class="col"> <p class="graphtitle">' + dashletterName + ' </p> <div class="gridStyle" ng-grid="' + config[dashletteId].gridOptions + '"></div>';

    }

所以在一个页面中我需要显示四个指令,它可以是 3 个 c3 图表和 1 个 ng 网格表指令,或者 2 个 C3 图表和 2 个 ng 网格表等,这取决于用户做出的预定义选择。

以下是我的自定义指令的初步代码,在进一步研究之前,我想从其他人那里获得更好的方法。在我的链接功能中,我需要在选项卡单击或 ng-init 阶段等时从控制器动态获取模板。

app.directive('customCharts', ['$compile', function($compile) {
    return {
        restrict: 'EA',
        scope: {
            chartName: '='
        },
        link: function(scope, element) {
            var template = ' <div class="col"> <p class="graphtitle">' + dashletterName + ' </p> <c3-simple id = "' + chartName + '" config="' + chartName + '"></c3-simple> </div>'
            var parent = angular.element(document.querySelectorAll('.chartsDiv')) // DOM element where the compiled template can be appended
            var linkFn = $compile(template);
            var content = linkFn(scope);
            parent.append(content);
        }

    }


}]);

如果我需要进一步澄清我的问题,请告诉我。请提供一些示例代码的任何说明。

4

1 回答 1

1

我建议创建一个或多个指令,每个指令都向 DOM 添加一个组件- 所以 1,2 和 3 应该是单独的指令。以我的经验,如果你创建一个添加多个组件的指令,你最终可能会用一个笨拙的控制器来换一个笨拙的指令。

至于 config 和 columnDefs 之类的东西,我会在控制器中定义配置,或者在传递给控制器​​的单独服务/工厂中定义,如果你想让你的控制器真的很轻,然后将配置传递给指令范围。这将允许您在应用程序内或跨应用程序重用指令。

要监视控制器更改,请在指令scope.$watch()中适当的属性,然后在指令中调用适当的更新函数。我相信这就是您所说的 4。这在我的示例中的下拉列表中得到了证明。

我在不使用$compile的情况下取得了成功,但也许其他人可以为此争论。

注意事项:如果您使用的第三方库使用 Angular 不知道的异步功能,您可能需要将指令的更新行为放在scope.$apply() 内,否则 DOM 不会更新到下一个 Angular 摘要周期。

如果您的 HTML 超过一两行,我建议使用templateUrl

这是一个以简单的方式使用 jQuery 的玩具示例。

app.directive('chart', function() {
    return {
        restrict: 'EA',
        scope: {config: '='},
        templateUrl: 'chart.html',
        link: function(scope, element) {
            var el = element[0];

            function update() {
                $(el).html('<h4>' + scope.config.chartType + '</h4>');
            }

            scope.$watch('config', update, true);
        }
    }
});
于 2015-07-12T14:09:47.540 回答