创建具有可变元素类型的指令 [英] Creating a directive with a variable element type

查看:22
本文介绍了创建具有可变元素类型的指令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个指令,通过使用大"、中"、小"的下拉选择器来更改 html 元素类型 (h1/h2/h3).我希望它也保留元素上的属性.我已经创建了这个例子的小提琴:http://jsfiddle.net/H63Z3/1/

角度:

angular.module('app', []).controller('example', function ($scope) {$scope.type = 'h2';}).directive('changeType', function ($compile) {返回 {限制:'A',链接:函数(范围、元素、属性){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);});}};});

HTM &L:

<select ng-model="type" ng-options="k as v for (k,v) in { h1: 'Large', h2: 'Medium', h3: 'Small' }"></选择><h1更改类型>文本</h1><div>{{ type }}</div>

我看到的问题是,在下拉列表进行更改后,元素属性没有在 Angular 中正确更新.似乎该指令没有重新应用于新元素.我不确定使用编译函数是否是正确的答案.

任何帮助将不胜感激.

解决方案

我只是花了一点时间研究我决定称之为变形"指令的东西.实际上这很有趣,我对结果非常满意.请注意,此解决方案是纯 Angular.

注意:我第一次发帖时没有注意到您需要持久属性.我已经添加了该功能.我在编译后添加了我的属性,但是如果您想将指令作为属性提供,则必须以相反的方式进行.

HTML

AngularJS'Morphling'指令

<div ng-app="app" ng-controller="morphTest"><strong>变形指令类型:</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>作品</morphling>

html, body {字体系列:无衬线;颜色:#111;}引用 {显示:块;边距:20px;字体样式:斜体;&:之前,&:在{之后内容: '"';}}attrDemo[attr="value"] {显示:内联块;颜色:蓝色;-webkit-transform:旋转(180度);-moz 变换:旋转(180 度);-ms-transform:旋转(180度);-o-变换:旋转(180度);变换:旋转(180度);}

Javascript

angular.module('app', []).controller('morphTest', function ($scope) {$scope.type = 'h2';$scope.bindingDemo = '绑定';}).directive('morphling', function ($compile) {返回 {限制:'E',替换:真的,链接:功能(范围,元素,属性){var e = 元素;scope.$watch(attributes.type, function(type){类型 = !!类型?类型:'跨度';var e2 = $compile('<' + type + '>' + e.html() + '</' + type + '>')(scope);for(var a in attributes.$attr) {if(a.toLowerCase() != 'type')e2.attr(a, 属性[a]);}e.replaceWith(e2);e = e2;});}};});

演示

CodePen 演示

I'm trying to create a directive that will change the html element type (h1/h2/h3) by using a drop down selector of "Large", "Medium", "Small". I want it to also retain attributes on the element. I have created a fiddle of this example: http://jsfiddle.net/H63Z3/1/

Angular:

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);
                    });
                }
            };
        });

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>

The problem I see is that the element property is not being updated properly in Angular after a change is made by the drop down. It seems that the directive is not reapplied to the new element. I'm unsure if using a compile function is the right answer.

Any help would be greatly appreciated.

解决方案

I just spent a little while working on what I decided to call a 'morphling' directive. It was pretty fun actually, and I'm quite pleased with the result. Note that this solution is pure Angular.

Note: I failed to notice when I first posted this that you required persistent attributes. I have since added that functionality. I add my attributes after compilation, but if you want to supply directives as attributes, you'd have to do it the other way around.

HTML

<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>

LESS

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);
}

Javascript

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;
        });
      }
    };
  });

Demo

CodePen Demo

这篇关于创建具有可变元素类型的指令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆