Angularjs 创建具有可变元素类型的指令
我试图创建一个指令,通过使用“大”、“中”、“小”下拉选择器来更改html元素类型(h1/h2/h3)。我希望它还保留元素上的属性。我创建了一个小提琴的例子: 角度:Angularjs 创建具有可变元素类型的指令,angularjs,angularjs-directive,Angularjs,Angularjs Directive,我试图创建一个指令,通过使用“大”、“中”、“小”下拉选择器来更改html元素类型(h1/h2/h3)。我希望它还保留元素上的属性。我创建了一个小提琴的例子: 角度: angular.module('app', []) .controller('example', function ($scope) { $scope.type = 'h2'; }) .directive('changeType', function ($co
angular.module('app', [])
.controller('example', function ($scope) {
$scope.type = 'h2';
})
.directive('changeType', function ($compile) {
return {
restrict: 'A',
link: function (scope, element, attributes) {
scope.$watch('type', function () {
var attrs = element[0].attributes;
var newElement = $('<' + scope.type + '>').text(element.text());
for (var i = 0; i < attrs.length; i++) {
newElement.attr(attrs.item(i).name, attrs.item(i).value);
}
element.replaceWith(newElement);
$compile(element.contents())(scope);
});
}
};
});
angular.module('app',[])
.controller('示例',函数($scope){
$scope.type='h2';
})
.directive('changeType',函数($compile){
返回{
限制:“A”,
链接:功能(范围、元素、属性){
范围:$watch('类型',函数(){
var attrs=元素[0]。属性;
var newElement=$('').text(element.text());
对于(变量i=0;i
HTM&L:
<div ng-app="app" ng-controller="example">
<select ng-model="type" ng-options="k as v for (k,v) in { h1: 'Large', h2: 'Medium', h3: 'Small' }"></select>
<h1 change-type>Text</h1>
<div>{{ type }}</div>
</div>
正文
{{type}}
我看到的问题是,在下拉列表进行更改后,元素属性没有在Angular中正确更新。该指令似乎没有重新应用于新元素。我不确定使用编译函数是否是正确的答案
任何帮助都将不胜感激。我只是花了一点时间研究我决定称之为“变形”指令的东西。实际上这很有趣,我对结果很满意。请注意,此解是纯角度解 注意:我第一次发布这篇文章时没有注意到您需要持久属性。此后,我添加了该功能。我在编译之后添加属性,但是如果您想提供作为属性的指令,则必须以另一种方式进行 HTML Javascript
angular.module('app',[])
.controller('morphTest',函数($scope){
$scope.type='h2';
$scope.bindingDemo='Binding';
})
.directive('morphing',函数($compile){
返回{
限制:'E',
替换:正确,
链接:功能(范围、元素、属性){
var e=元素;
范围.$watch(attributes.type,function(type){
类型=!!类型?类型:'span';
var e2=$compile(“”+e.html()+“”)(范围);
for(属性中的变量a.$attr){
if(a.toLowerCase()!='type')
e2.属性(a,属性[a]);
}
e、 替换为(e2);
e=e2;
});
}
};
});
演示
@Michael Mroz
我想指出,你提出的解决方案打破了约束:
angular.module('app',[])
.controller('morphTest',函数($scope,$interval){
$scope.type='h2';
$scope.bindingDemo='Binding';
var i=0;
$interval(函数(){
$scope.bindingDemo='Binding'++i;
}, 1000);
})
.directive('morphing',函数($compile){
返回{
限制:'E',
替换:正确,
链接:功能(范围、元素、属性){
//return;//在此处取消注释
var e=元素;
范围.$watch(attributes.type,function(type){
类型=!!类型?类型:'span';
var e2=$compile(“”+e.html()+“”)(范围);
for(属性中的变量a.$attr){
if(a.toLowerCase()!='type')
e2.属性(a,属性[a]);
}
e、 替换为(e2);
e=e2;
});
}
};
});
您应该看到,[number]递增时“正常绑定[number]工作”,但它没有显示
取消对报税表的注释;在link函数中,您将看到绑定工作。这与您要查找的内容接近吗?[AngularJS-如何更改包含数据绑定的模板中的元素?][1][1]:为什么不创建一个元素指令,根据输入属性更改模板?i、 e.@EdMeacham链接中的解决方案有效,但它将更改的元素嵌套在原始元素中,看起来像:“Text”。我希望页面上只有一个header元素可以更改,以便提取干净的输出标记。这样做的复杂之处在于,必须销毁并重新创建元素,而指令仍然应用于单个标头元素。这是我不确定是否可能的部分,但使用element.replaceWith()似乎应该考虑到这一点。我不确定我的示例中有什么错误。关于@FLoG的“答案”指出了此解决方案中的缺陷:如果在指令中放入一个范围变量并设置一个向上爬行的间隔,它将向上爬行,直到第一次更改为
类型
。是的,这是个问题。如果您需要考虑这种行为,则必须对$compile
行进行大量修改。此解决方案非常适合我,但当其他属性是对象文本时,我很难让它们正常工作。我对angular在作为属性传递时如何处理对象有点困惑。知道为什么会发生这种情况吗?正如弗洛格指出的,绑定并不完全有效。请注意,我在编译后重新添加了属性。。。这需要在之前完成,但我不知道Angular是否支持使其正常工作所需的反射。每次调用指令都需要访问整个字符串。如果你能从指令中得到,这个解决方案可以改进。事实上,这是绝对可能的,因为否则ngRepeat就不是一件事了。我想我应该能解决这个问题。等我还没醒过来的时候,我会看一看:)好的,我想好了。只需将实际字符串添加到$compile内的元素声明中,就像您暗示的
<h1>AngularJS 'Morphling' Directive</h1>
<div ng-app="app" ng-controller="morphTest">
<strong>Morphling directive type:</strong> <select ng-model="type" ng-options="tag as caption for (tag, caption) in { h1: 'Heading 1', h2: 'Heading 2', h3: 'Heading 3', li: 'List Item', quote: 'Quote', attrDemo: 'Attribute Persistence Demo' }"></select><br />
<morphling type="type" attr="value">Normal <span style="color: red">{{bindingDemo}}</span> Works</morphling>
</div>
html, body {
font-family: sans-serif;
color: #111;
}
quote {
display: block;
margin: 20px;
font-style: italic;
&:before,
&:after {
content: '"';
}
}
attrDemo[attr="value"] {
display: inline-block;
color: blue;
-webkit-transform: rotate(180deg);
-moz-transform: rotate(180deg);
-ms-transform: rotate(180deg);
-o-transform: rotate(180deg);
transform: rotate(180deg);
}
angular.module('app', [])
.controller('morphTest', function ($scope) {
$scope.type = 'h2';
$scope.bindingDemo = 'Binding';
})
.directive('morphling', function ($compile) {
return {
restrict: 'E',
replace: true,
link: function(scope, element, attributes) {
var e = element;
scope.$watch(attributes.type, function(type){
type = !!type ? type : 'span';
var e2 = $compile('<' + type + '>' + e.html() + '</' + type + '>')(scope);
for(var a in attributes.$attr) {
if(a.toLowerCase() != 'type')
e2.attr(a, attributes[a]);
}
e.replaceWith(e2);
e = e2;
});
}
};
});
angular.module('app', [])
.controller('morphTest', function ($scope, $interval) {
$scope.type = 'h2';
$scope.bindingDemo = 'Binding';
var i = 0;
$interval(function() {
$scope.bindingDemo = 'Binding ' + ++i;
}, 1000);
})
.directive('morphling', function ($compile) {
return {
restrict: 'E',
replace: true,
link: function(scope, element, attributes) {
// return; // uncomment here
var e = element;
scope.$watch(attributes.type, function(type){
type = !!type ? type : 'span';
var e2 = $compile('<' + type + '>' + e.html() + '</' + type + '>')(scope);
for(var a in attributes.$attr) {
if(a.toLowerCase() != 'type')
e2.attr(a, attributes[a]);
}
e.replaceWith(e2);
e = e2;
});
}
};
});