AngularJS - 包装指令

时间:2016-01-26 13:59:36

标签: javascript angularjs angularjs-directive

似乎我对指令中孤立的范围感到困惑,希望你能帮助我。

我尝试将一段代码(包含一些自定义指令)包装到一个新指令中以减少代码重复。显然,我需要将一些属性(如ng-model)作为参数赋予我的新指令,以使指令可重用。 ng-model虽然不喜欢表达式(我最初尝试过ng-model="{{myVariableWhichContainsDesiredNgModelString}}"),因此我最终得到了这篇文章:AngularJS - Create a directive that uses ng-model

虽然接受的答案似乎适用于简单的设置,但我从接受的答案编辑了plunker以测试它是否也适用于嵌套指令:(在我的应用程序中,我需要包装来自第三方的指令 - 我无法编辑的图书馆)Plunker。在我的代码中,每个指令似乎都生成了自己的作用域,并且在作用域定义中使用=进行双向数据绑定似乎并没有按照需要进行。

编辑:由于我不知道我在问什么,我编辑了上面的Plunker并将重新解释这个问题:在Plunker中我有三个输入字段,它们应该绑定到同一个模型-值。这最初是有效的,但是一旦我编辑第三个输入字段,它就会在其隔离的范围内生成自己的变量,而不是更新初始值。显然,第三个输入字段是指从该点开始的新变量。如何避免这种行为并将输入保持链接到$scope.model.name

观察:从模板中删除isolated-scope-directive会使一切按预期工作......

template: '<div><my-input ng-model="myDirectiveVar"></my-input></div>',

而不是

template: '<div><my-isolated-scope-directive><my-input ng-model="myDirectiveVar"></my-input></my-isolated-scope-directive></div>',

Plunker

HTML:

<!-- this binds to the model which i would like all my inputs to bind to.-->
<input ng-model="name">

<!-- Example 1: This seems to generate a new modelvalue in the isolated-scope directive. Can I avoid this without modifying that directive?-->
<my-isolated-scope-directive><my-input ng-model="name"></my-input></my-isolated-scope-directive>

<!-- Example 2: This is what i would like my code to look like in the end: One directive which uses the code-snippet of Example 1 as template and passes some parameters into that template.-->
<my-wrapper-directive my-directive-var="name"></my-wrapper-directive>

指令:

my-input包含修改后的输入字段:

app.directive('myInput', function() {
    return {
        restrict: 'E',
        replace: true,
        require: 'ngModel',
        template: '<input class="some">',
        link: function($scope, elem, attr, ctrl) {
            console.debug($scope);
        }
    };
})

my-isolated-scope-directive是一个占位符指令,它有自己的独立范围来模拟嵌套指令的行为:

.directive('myIsolatedScopeDirective', function() {
    return {
        restrict: 'E',
        transclude: true,
        replace: true,
        scope: {
            something: '='
        },
        template: '<div ng-transclude></div>',
        link: function($scope, elem, attr, ctrl) {
            console.debug($scope);
        }
    };
})

my-wrapper-directive封装了前两个指令并接受了一个参数,该参数应该用作输入字段的ng-model值:

.directive('myWrapperDirective', function() {
    return {
        restrict: 'E',
        transclude: false,
        replace: true,
        scope: {
          myDirectiveVar: '='
        },
        template: '<div><my-isolated-scope-directive><my-input ng-model="myDirectiveVar"></my-input></my-isolated-scope-directive></div>',
        link: function($scope, elem, attr, ctrl) {
            console.debug($scope);
        }
    };
});

对我所缺少的任何建议和提示表示赞赏。我是否可以某种方式将ng-model链接到服务实例而不使我的指令依赖于该服务?

1 个答案:

答案 0 :(得分:2)

我不会这样做,因为它是使用范围的旧记法...我会使用controllerAs和bindToController

脚本:

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

app.controller('MainCtrl', function() {
  this.model = { name: 'World' };
  this.name = "Felipe";
});

app.directive('myInput', function() {
  return {
    restrict: 'E',
    replace: true,
    // controllerAs: 'app',
    require: 'ngModel',
    template: '<input class="some">',
    controller: function(){

    }
  };
})
.directive('myIsolatedScopeDirective', function() {
  return {
    restrict: 'E',
    transclude: true,
    controllerAs: 'app1',
    bindToController: {
      something: '='
    },
    template: '<div ng-transclude></div>',
    controller: function(){

    }
  };
})
.directive('myWrapperDirective', function() {
  return {
    restrict: 'E',
    transclude: false,
    controllerAs: 'app2',
    bindToController: {
      myDirectiveVar: '='
    },
    template: '<div><my-isolated-scope-directive>'+
      '<my-input ng-model="app2.myDirectiveVar"></my-input>'+
      '</my-isolated-scope-directive></div>',
    controller: function(){

    }

  };
});

指数:

<!doctype html>
<html ng-app="plunker" >
<head>
  <meta charset="utf-8">
  <title>AngularJS Plunker</title>
  <link rel="stylesheet" href="style.css">
  <script>document.write("<base href=\"" + document.location + "\" />");</script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.js"></script>
  <script src="app.js"></script>
</head>
<body ng-controller="MainCtrl as main">
  This scope value 
  <input ng-model="main.model.name">
  <my-isolated-scope-directive>
    <my-input ng-model="main.model.name"></my-input>
  </my-isolated-scope-directive>
  <my-wrapper-directive my-directive-var="main.model.name">
  </my-wrapper-directive>
</body>
</html>

查看plunker: http://plnkr.co/edit/VD0wXO1jivQc3JvfQFTh?p=preview

UPDATE 是的,好点,所以如果你想使用controllerAs,你需要角度1.2最小,对于bindToController你需要角度1.3