angularjs: 动态构建带绑定的可编译指令

angularjs: Dynamically build a compileable directive with bindings

我目前正在尝试构建一个组件,该组件获取一个对象,该对象具有应呈现的指令规范。

所以这是我的 angular 组件 componentRenderer.js

angular
    .module('app.core')
    .component('componentRenderer', {
        templateUrl: '/component-renderer/component-renderer.tpl.html',
        controller: ComponentRendererController,
        bindings: {
            data: '='
        }
    });

function ComponentRendererController($scope, $element, $timeout, $compile) {
    var vm = this;

    // Called when component is ready
    vm.$onInit = function () {
        if (vm.data.type !== 'plain') {
            var html = '<' + vm.data.type + ' ';
            if (vm.data.hasOwnProperty('options')) {
                angular.forEach(vm.data.options, function (value, key) {
                    if(typeof value === 'object') {
                        html += (key+'="value" ');
                    } else {
                        html += (key+'="'+value+'" ');
                    }
                });
            }

            html += '></' + vm.data.type + '>';

            var el = $compile(html)($scope);
            $element.find('.widget__content').append(el);
        }
    };
}

/component-renderer/component-renderer.tpl.html:

<div class="widget">
<div class="widget__header">
    <h2>{{ $ctrl.data.title }}</h2>
</div>
<div class="widget__content">
    <h3>{{ $ctrl.data.subtitle }}</h3>
</div>

例如,数据对象可以如下所示:

{
    "type": "activity-widget",
    "options": {
      "type": "simple",
    }
    "title": "Activity"
  }

我的 componentRenderer 现在应该构建相应的 html,这样就可以得到以下结果:

<activity-widget type="simple"></activity-widget>

因此,先前显示的对象的选项应该呈现为组件的属性。最后 activity-widget 组件应该呈现最终的 html 结构。

deviceActivity.js

angular
    .module('app.core')
    .component('deviceActivity', {
        templateUrl: '/device-activity/device-activity.tpl.html',
        controller: DeviceActivityController,
        bindings: {
            data: "="
        }
    });

到这里为止一切正常!但是不,我也希望能够将选项用作对象。

{
    "type": "activity-widget",
    "options": {
      "jsonObject": {
        "surveillance": [
          {
            "name": "location",
            "value": 25,
            "max": 100
          },
          {
            "name": "reporting",
            "value": 58,
            "max": 80
          },
          {
            "name": "reporting",
            "value": 9,
            "max": 120
          }
        ]
      }
    },
    "title": "Activity"
  }

我的 componentRenderer 现在应该构建相应的 html,这样就可以得到以下结果:

<activity-widget object="jsonObject"></activity-widget>

遗憾的是它不起作用,它没有将 jsonObject 绑定到我的组件。我不知道我做错了什么...非常感谢任何帮助!

提前致谢!

为什么它不起作用

所以你想得到这个

<activity-widget object="jsonObject"></activity-widget> 

相反,生成的是:

<activity-widget jsonObject="value"></activity-widget>  

(这完全对应于 componentRenderer.js 应该根据它包含的代码输出的内容)

并且正在生成的小部件显然无法工作,原因有两个:

  • jsonObject="value":属性名称是驼峰式的,但应该像 json-object
  • jsonObject="value":我没看到你试图将 jsonObject 的值注入到范围。所以值为undefined
  • 也就不足为奇了

如何修复

如果你坚持认为这确实是你想要得到的

 <activity-widget object="jsonObject"></activity-widget> 

鉴于您指定的对象,这里是您应该如何更改componentRenderer.js

angular.forEach(vm.data.options, function (value, key) {
  if(typeof value === 'object') {

    // providing attribute=value pair correctly
    html += ('object="' + key + '" ');
    // adding object's value to the scope  
    // so that it is passed to the widget during compile below
    $scope[key] = value;

  } else {
    html += (key+'="'+value+'" ');
  }
});

请注意,通过这种方式,每个小部件只能拥有一个对象类型属性(所有其他属性都将被覆盖)。

尝试像上面显示的那样更改您的代码,对我来说它似乎工作正常。如果还是不行,请创建一个fiddle(实际上,对于这种问题,这是你应该首先做的)