基于动态数据的ng-repeat中用于不同AngularJS指令的模式

时间:2021-05-30 19:44:23

I'm building a dashboard dynamically from an array of data. The gauges are D3.

我正在从一组数据动态构建仪表板。仪表是D3。

I have a selection of different D3 gauges defined in AngularJS directives. On my page I have an ng-repeat iterating over the metrics array.

我在AngularJS指令中定义了一系列不同的D3测量仪。在我的页面上,我有一个ng-repeat迭代度量数组。

The question I have is what is the best way to dynamically select the right directive based on an attribute of data in the ng-repeat array?

我的问题是什么是基于ng-repeat数组中的数据属性动态选择正确指令的最佳方法?

Is there a way to create a factory pattern where the Directive used is based on an input value from the array? Or is there a way to achieve the result using only Directives by dynamically including other Directives in a Directive?

有没有办法创建工厂模式,其中使用的指令是基于数组的输入值?或者有没有办法通过动态地在指令中包含其他指令来仅使用指令来实现结果?

HTML

<div ng-controller="DashboardCtrl">
<div id="oppChart">
    <div>
        <gh-visualization ng-repeat="item in metrics" val="item[0]"></gh-visualization>
    </div>
</div>
</div>

Metrics array (will be dynamic):

度量数组(将是动态的):

$scope.list = [
        { 'title': 'XYX','data-type':'', 'query':'SELECT ...' },
        { 'title': 'Revenue', 'data-type':'', 'query':'SELECT ...'  }
      ];

D3 Directive based on this - http://briantford.com/blog/angular-d3.html

D3指令基于此 - http://briantford.com/blog/angular-d3.html

3 个解决方案

#1


6  

That would be ng-switch

这将是ng-switch

<div ng-repeat="item in metrics">
  <div ng-switch on="item.type">
    <div ng-switch-when="optionA">..include </div>
    <div ng-switch-when="optionA">..include </div>
  </div>
</div>

#2


1  

Yup I've done this as you describe in your second option.

是的,我已经按照你在第二个选项中描述的那样做了。

I created a directive that loads a particular template that then has other directives in them based on a type attribute of the data.

我创建了一个指令,它加载一个特定的模板,然后根据数据的类型属性在其中包含其他指令。

    directive("dynamicFormInput", ['$http', '$templateCache', function($http, $templateCache){
    return {
        restrict: 'E',
        //currently need model for map center otherwise can be removed, need to set default in map directive
        scope: {model: '=', section: '='},
        template: '<ng:include src="tpl"></ng:include>',
        link: function(scope, iElement, iAttrs) {
            var sectionToLoad = "";
            switch(scope.section.sectionTypeId)
            {
                case 1:
                    sectionToLoad ='partials/survey/textInput.html';
                  break;
                case 2:
                    sectionToLoad = 'partials/survey/selectOneOption.html';
                  break;
                case 3:
                    sectionToLoad = 'partials/survey/multiSelectOption.html';
                  break;
                case 4:
                    sectionToLoad = 'partials/survey/boolean.html';
                  break;
                case 5:
                    sectionToLoad = 'partials/survey/textInput.html';
                  break;
                case 6:
                    if(scope.section.sectionId == 13)
                        sectionToLoad = 'partials/survey/addressSelection.html';
                    else if(scope.section.sectionId == 24)
                        sectionToLoad = 'partials/survey/contactForm.html'
                break;
            }
            if(sectionToLoad!="")
            {
                $http.get(sectionToLoad, {cache:$templateCache});
                scope.tpl=sectionToLoad;
            }
        }
    }
}])

Usage is then like:

用法如下:

<accordion
    close-others="true">
    <accordion-group
        ng-repeat="section in sections"
        ng-class="{'isGroundTruthed':section.userId==73}"
        heading="{{section.sectionName}} ({{displaySelection(section)}})">

        <dynamic-form-input
            section="section">
        </dynamic-form-input>

    </accordion-group>
</accordion>

You can ignore the accordion I just happened to use that as my item to repeat so each section would fold up.

你可以忽略我刚刚碰巧使用的手风琴作为我的项目重复,所以每个部分都会折叠起来。

Edit Just cleaned up my directive code some.

编辑刚刚清理了我的指令代码。

#3


0  

Your second solution sound more angular-apropriate. So if its just a single directive that is added dynamically

你的第二个解决方案听起来更有棱角。因此,如果它只是一个动态添加的指令

app.directive('dynamically',function(){ 
  return {
    restrict: 'A',
    compile: function(element,attrs){
      var directives = [];
      if (attrs.dynamically.indexOf(' ') > -1){
        directives = attrs.dynamically.split(' ')
      } else {
        directives.push(attrs.dynamically)
      };
      var html = '<ANY ';
      for (var i in directives){
        html += directives[i] + '="true" ';
      };
      html += '></ANY>';
      element.replaceWith(html)
    }
  }
})

That's one way to do it.

这是一种方法。

1) if (attrs.dynamically.indexOf(' ') is so that you could implement multiple directives into one instance, seperated by a space char (' ') in this example.

1)if(attrs.dynamically.indexOf('')是这样你可以在一个实例中实现多个指令,在本例中用空格char('')分隔。

2) I add '="true"' to attribute that i work with by asking if (attrs.x) {...}, if attribute x doesn't have a value, it doesn't exist even if stated and located on the DOM.

2)我通过询问if(attrs.x){...}来添加'=“true”'属性,如果属性x没有值,即使声明和定位它也不存在在DOM上。

#1


6  

That would be ng-switch

这将是ng-switch

<div ng-repeat="item in metrics">
  <div ng-switch on="item.type">
    <div ng-switch-when="optionA">..include </div>
    <div ng-switch-when="optionA">..include </div>
  </div>
</div>

#2


1  

Yup I've done this as you describe in your second option.

是的,我已经按照你在第二个选项中描述的那样做了。

I created a directive that loads a particular template that then has other directives in them based on a type attribute of the data.

我创建了一个指令,它加载一个特定的模板,然后根据数据的类型属性在其中包含其他指令。

    directive("dynamicFormInput", ['$http', '$templateCache', function($http, $templateCache){
    return {
        restrict: 'E',
        //currently need model for map center otherwise can be removed, need to set default in map directive
        scope: {model: '=', section: '='},
        template: '<ng:include src="tpl"></ng:include>',
        link: function(scope, iElement, iAttrs) {
            var sectionToLoad = "";
            switch(scope.section.sectionTypeId)
            {
                case 1:
                    sectionToLoad ='partials/survey/textInput.html';
                  break;
                case 2:
                    sectionToLoad = 'partials/survey/selectOneOption.html';
                  break;
                case 3:
                    sectionToLoad = 'partials/survey/multiSelectOption.html';
                  break;
                case 4:
                    sectionToLoad = 'partials/survey/boolean.html';
                  break;
                case 5:
                    sectionToLoad = 'partials/survey/textInput.html';
                  break;
                case 6:
                    if(scope.section.sectionId == 13)
                        sectionToLoad = 'partials/survey/addressSelection.html';
                    else if(scope.section.sectionId == 24)
                        sectionToLoad = 'partials/survey/contactForm.html'
                break;
            }
            if(sectionToLoad!="")
            {
                $http.get(sectionToLoad, {cache:$templateCache});
                scope.tpl=sectionToLoad;
            }
        }
    }
}])

Usage is then like:

用法如下:

<accordion
    close-others="true">
    <accordion-group
        ng-repeat="section in sections"
        ng-class="{'isGroundTruthed':section.userId==73}"
        heading="{{section.sectionName}} ({{displaySelection(section)}})">

        <dynamic-form-input
            section="section">
        </dynamic-form-input>

    </accordion-group>
</accordion>

You can ignore the accordion I just happened to use that as my item to repeat so each section would fold up.

你可以忽略我刚刚碰巧使用的手风琴作为我的项目重复,所以每个部分都会折叠起来。

Edit Just cleaned up my directive code some.

编辑刚刚清理了我的指令代码。

#3


0  

Your second solution sound more angular-apropriate. So if its just a single directive that is added dynamically

你的第二个解决方案听起来更有棱角。因此,如果它只是一个动态添加的指令

app.directive('dynamically',function(){ 
  return {
    restrict: 'A',
    compile: function(element,attrs){
      var directives = [];
      if (attrs.dynamically.indexOf(' ') > -1){
        directives = attrs.dynamically.split(' ')
      } else {
        directives.push(attrs.dynamically)
      };
      var html = '<ANY ';
      for (var i in directives){
        html += directives[i] + '="true" ';
      };
      html += '></ANY>';
      element.replaceWith(html)
    }
  }
})

That's one way to do it.

这是一种方法。

1) if (attrs.dynamically.indexOf(' ') is so that you could implement multiple directives into one instance, seperated by a space char (' ') in this example.

1)if(attrs.dynamically.indexOf('')是这样你可以在一个实例中实现多个指令,在本例中用空格char('')分隔。

2) I add '="true"' to attribute that i work with by asking if (attrs.x) {...}, if attribute x doesn't have a value, it doesn't exist even if stated and located on the DOM.

2)我通过询问if(attrs.x){...}来添加'=“true”'属性,如果属性x没有值,即使声明和定位它也不存在在DOM上。