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(实际上,对于这种问题,这是你应该首先做的)
我目前正在尝试构建一个组件,该组件获取一个对象,该对象具有应呈现的指令规范。
所以这是我的 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(实际上,对于这种问题,这是你应该首先做的)