为了账号安全,请及时绑定邮箱和手机立即绑定

AngularJS-创建使用ng-model的指令

/ 猿问

AngularJS-创建使用ng-model的指令

倚天杖 2019-10-05 11:00:42

我正在尝试创建一个指令,该指令将创建与创建指令的元素具有相同ng-model的输入字段。


到目前为止,这是我想到的:


的HTML


<!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.0.2/angular.js"></script>

  <script src="app.js"></script>

</head>

<body ng-controller="MainCtrl">

  This scope value <input ng-model="name">

  <my-directive ng-model="name"></my-directive>

</body>

</html>

的JavaScript


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


app.controller('MainCtrl', function($scope) {

  $scope.name = "Felipe";

});


app.directive('myDirective', function($compile) {

  return {

    restrict: 'E',

    scope: {

      ngModel: '='

    },

    template: '<div class="some"><label for="{{id}}">{{label}}</label>' +

      '<input id="{{id}}" ng-model="value"></div>',

    replace: true,

    require: 'ngModel',

    link: function($scope, elem, attr, ctrl) {

      $scope.label = attr.ngModel;

      $scope.id = attr.ngModel;

      console.debug(attr.ngModel);

      console.debug($scope.$parent.$eval(attr.ngModel));

      var textField = $('input', elem).

        attr('ng-model', attr.ngModel).

        val($scope.$parent.$eval(attr.ngModel));


      $compile(textField)($scope.$parent);

    }

  };

});

但是,我不确定这是处理这种情况的正确方法,并且存在一个错误,即我的控件未使用ng-model target字段的值初始化。


这是上面代码的简称:http ://plnkr.co/edit/IvrDbJ


处理此问题的正确方法是什么?


编辑:ng-model="value"从模板中删除后,这似乎工作正常。但是,我将继续公开这个问题,因为我想再次确认这是正确的方法。


查看完整描述

3 回答

?
呼唤远方

这个答案是旧的,可能已经过时。只需抬起头,这样就不会使人们误入歧途。我不再使用Angular,因此无法进行改进。


这实际上是相当不错的逻辑,但是您可以稍微简化一下。


指示

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


app.controller('MainCtrl', function($scope) {

  $scope.model = { name: 'World' };

  $scope.name = "Felipe";

});


app.directive('myDirective', function($compile) {

  return {

    restrict: 'AE', //attribute or element

    scope: {

      myDirectiveVar: '=',

     //bindAttr: '='

    },

    template: '<div class="some">' +

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

    replace: true,

    //require: 'ngModel',

    link: function($scope, elem, attr, ctrl) {

      console.debug($scope);

      //var textField = $('input', elem).attr('ng-model', 'myDirectiveVar');

      // $compile(textField)($scope.$parent);

    }

  };

});

带有指令的HTML

<body ng-controller="MainCtrl">

  This scope value <input ng-model="name">

  <my-directive my-directive-var="name"></my-directive>

</body>

的CSS

.some {

  border: 1px solid #cacaca;

  padding: 10px;

}

您可以在此Plunker上看到它的实际效果。


这是我看到的:


我了解您为什么要使用“ ng-model”,但在您的情况下则没有必要。ng-model用于将现有 html元素与范围中的值链接。由于您自己创建指令,因此要创建“新” html元素,因此不需要ng-model。

编辑正如Mark在其评论中提到的那样,没有理由您不能使用ng-model,只是为了遵守约定。


通过在指令中显式创建一个作用域(“隔离”作用域),该指令的作用域无法访问父作用域上的“名称”变量(这就是为什么我想使用ng-model的原因)。

我从指令中删除了ngModel,并将其替换为可以更改为任何名称的自定义名称。

使一切仍然起作用的是在范围内使用“ =”符号。在“ scope”标题下签出docs docs。

通常,如果您希望指令中的值始终映射到父级作用域中的值,那么您的指令应使用隔离的作用域(您已正确执行)并使用'='类型作用域。


查看完整回答
反对 回复 2019-10-05
?
慕盖茨9453107

我对所有答案进行了组合,现在有两种使用ng-model属性的方法:

  • 具有复制ngModel的新作用域

  • 具有在链接上进行编译的相同作用域

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


app.controller('MainCtrl', function($scope) {

  $scope.name = "Felipe";

  $scope.label = "The Label";

});


app.directive('myDirectiveWithScope', function() {

  return {

    restrict: 'E',

    scope: {

      ngModel: '=',

    },

    // Notice how label isn't copied

    template: '<div class="some"><label>{{label}}: <input ng-model="ngModel"></label></div>',

    replace: true

  };

});

app.directive('myDirectiveWithChildScope', function($compile) {

  return {

    restrict: 'E',

    scope: true,

    // Notice how label is visible in the scope

    template: '<div class="some"><label>{{label}}: <input></label></div>',

    replace: true,

    link: function ($scope, element) {

      // element will be the div which gets the ng-model on the original directive

      var model = element.attr('ng-model');

      $('input',element).attr('ng-model', model);

      return $compile(element)($scope);

    }

  };

});

app.directive('myDirectiveWithoutScope', function($compile) {

  return {

    restrict: 'E',

    template: '<div class="some"><label>{{$parent.label}}: <input></label></div>',

    replace: true,

    link: function ($scope, element) {

      // element will be the div which gets the ng-model on the original directive

      var model = element.attr('ng-model');

      return $compile($('input',element).attr('ng-model', model))($scope);

    }

  };

});

app.directive('myReplacedDirectiveIsolate', function($compile) {

  return {

    restrict: 'E',

    scope: {},

    template: '<input class="some">',

    replace: true

  };

});

app.directive('myReplacedDirectiveChild', function($compile) {

  return {

    restrict: 'E',

    scope: true,

    template: '<input class="some">',

    replace: true

  };

});

app.directive('myReplacedDirective', function($compile) {

  return {

    restrict: 'E',

    template: '<input class="some">',

    replace: true

  };

});

.some {

  border: 1px solid #cacaca;

  padding: 10px;

}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>

<div ng-app="model" ng-controller="MainCtrl">

  This scope value <input ng-model="name">, label: "{{label}}"

  <ul>

    <li>With new isolate scope (label from parent):

      <my-directive-with-scope ng-model="name"></my-directive-with-scope>

    </li>

    <li>With new child scope:

      <my-directive-with-child-scope ng-model="name"></my-directive-with-child-scope>

    </li>

    <li>Same scope:

      <my-directive-without-scope ng-model="name"></my-directive-without-scope>

    </li>

    <li>Replaced element, isolate scope:

      <my-replaced-directive-isolate ng-model="name"></my-replaced-directive-isolate>

    </li>

    <li>Replaced element, child scope:

      <my-replaced-directive-child ng-model="name"></my-replaced-directive-child>

    </li>

    <li>Replaced element, same scope:

      <my-replaced-directive ng-model="name"></my-replaced-directive>

    </li>

  </ul>

  <p>Try typing in the child scope ones, they copy the value into the child scope which breaks the link with the parent scope.

  <p>Also notice how removing jQuery makes it so only the new-isolate-scope version works.

  <p>Finally, note that the replace+isolate scope only works in AngularJS >=1.2.0

</div>

我不确定我是否喜欢在链接时进行编译。但是,如果您只是用另一个替换元素,则不需要这样做。


总而言之,我更喜欢第一个。只需将范围{ngModel:"="}设置为ng-model="ngModel",并在模板中设置所需位置即可。


更新:我内联了代码片段,并针对Angular v1.2对其进行了更新。事实证明,隔离范围仍然是最佳的,尤其是在不使用jQuery时。因此归结为:


您是否要替换单个元素:只需替换它,不理会范围,但请注意,v2.0不推荐使用replace:


app.directive('myReplacedDirective', function($compile) {

  return {

    restrict: 'E',

    template: '<input class="some">',

    replace: true

  };

});

否则使用此:


app.directive('myDirectiveWithScope', function() {

  return {

    restrict: 'E',

    scope: {

      ngModel: '=',

    },

    template: '<div class="some"><input ng-model="ngModel"></div>'

  };

});


查看完整回答
反对 回复 2019-10-05
?
12345678_0001

它并不那么复杂:在命令中,使用别名: scope:{alias:'=ngModel'}


.directive('dateselect', function () {

return {

    restrict: 'E',

    transclude: true,

    scope:{

        bindModel:'=ngModel'

    },

    template:'<input ng-model="bindModel"/>'

}

在您的html中,照常使用


<dateselect ng-model="birthday"></dateselect>


查看完整回答
反对 回复 2019-10-05

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信