角动态多态指令

时间:2014-01-15 23:01:55

标签: angularjs dynamic directive polymorphism

我是Angular的初学者,但我正在探索一些稍高级的角落以确保它具有我需要的功能。

具体来说我需要:

  • 呈现一系列不同类型的小部件,每个小部件都实现为独立的Angular指令
  • 小部件类型是根据数据确定的,而不是通过标记
  • 确定的
  • 小部件均在单独的文件中定义
  • 将指令的范围设置为该窗口小部件实例的数据

我想我已经解决了下面描述的要求,并在http://jsfiddle.net/cUTt4/5/

实施

问题:

  1. 这是正确的,最佳的做法,而且速度相当快?
  2. 我应该添加哪些改进?
  3. 如果widget指令没有显式引用{item:'='}来获取它们的隔离范围会更好,但它们的子范围应该由renderform指令构建。我怎么做?
  4. 我的解决方案: HTML (注意,由于jsfiddle的限制,Angular模板在这里是脚本)

    <div ng-app="myApp">
    
        <script type="text/ng-template" id="widget-type-a">
            <div>
                <label>{{ item.label}} </label> 
                <input type="text" ng-model="item.val" >
            </div>
        </script>
    
        <script type="text/ng-template" id="widget-type-b">
            <div>
                <label>{{ item.label}}</label> 
                <input type="text" ng-model="item.val" >
            </div>
        </script>
    
        <div ng-controller="FormCtrl">
            <renderform></renderform>
        </div>
    </div>
    

    main.js:

    var app = angular.module('myApp', []);
    
    function FormCtrl($scope) {
        items = [
            {
                type: 'widget-type-a',
                label : 'Widget A instance 1',
                val: 1
            },
            {
                type: 'widget-type-b',
                label : 'Widget B instance 1',      
                val : 2
            },
            {
                type: 'widget-type-a',
                label : 'Widget A instance 2',
                val : 3
            }
        ];
        $scope.items = items
    
    }
    
    app.directive('renderform', function($compile) {
        function linkFn(scope, element) {
            var item, 
                itemIdx,
                templStr = '',
                newParent,
                data,
                newEl;
    
            newParent = angular.element('<div></div>')
            for(itemIdx in scope.items) {
                item = items[itemIdx];
                templStr += '<div ' + item.type + ' item="items[' + itemIdx + ']"></div>';
            }
            newEl = angular.element(templStr);
            $compile(newEl)(scope);
            element.replaceWith(newEl);
        }
    
        return {
            restrict: 'E',
            link:linkFn
    
        };
    
    });
    
    app.directive('widgetTypeA', function() {
        return {
            restrict: 'A',
            templateUrl: 'widget-type-a',
            scope: { item: '=' } 
        };
    
    });
    
    app.directive('widgetTypeB', function() {
        return {
            restrict: 'A',
            templateUrl: 'widget-type-b',
            scope: { item: '='}
        };
    
    });
    

2 个答案:

答案 0 :(得分:3)

抱歉快速回答,未经测试:

<div data-ng-repeat="item in items">
  <div data-ng-switch data-on="item.type">
    <div data-ng-switch-when="widget-type-a" data-widget-type-a="item"></div>
    <div data-ng-switch-when="widget-type-b" data-widget-type-b="item"></div>
  </div>
</div>

如果这是您正在寻找的,请改进此答案。

答案 1 :(得分:2)

我一直在考虑这个问题,虽然ng-switch选项适用于简单的情况,但它会带来相当大的维护开销。

我提出了一个允许单点维护的解决方案。请考虑以下事项:

var app = angular.module('poly', []);


app.controller('AppController', function ($scope) {
    $scope.items = [
        {directive: 'odd-numbers'},
        {directive: 'even-numbers'},
        {directive: 'odd-numbers'}
    ];
});


app.directive('component', function ($compile) {
    return {
        restrict: 'E',
        controller: function () {

        },
        controllerAs: 'component_ctrl',
        link: function (scope, element, attrs) {
            var child_directive = scope.$eval(attrs.directive);
            var child_element = $compile('<' + child_directive + ' data="data"></' + child_directive + '>')(scope);
            element.append(child_element);
        }
    }
});


app.directive('oddNumbers', function ($interval) {
    return {
        restrict: 'E',
        link: function (scope) {
            scope.number = 0;
            $interval(function () {
                scope.number += 2;
            }, 1000);
        },
        template: '<h1>{{ number }}</h1>'
    }
});


app.directive('evenNumbers', function ($interval) {
    return {
        restrict: 'E',
        link: function (scope) {
            scope.number = 1;
            $interval(function () {
                scope.number += 2;
            }, 1000);
        },
        template: '<h1>{{ number }}</h1>'
    };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<section ng-app="poly" ng-controller="AppController">
  <div ng-repeat="item in items">
    <component directive="item.directive" data="item.data"></component>
  </div>
</section>

这允许以临时方式在控制器中指定组件,并且转发器不必通过交换机委派责任。

NB我没有实现如何在组件之间传递数据