javascript - 将自定义指令添加到已有 Angular Directive(指令)的现有输入 [ng-model/ng-required]

标签 javascript angularjs angularjs-directive

我想使用一个用 ng-modelng-required 修饰的标准输入控件,然后添加我自己的自定义属性指令以提供 uib-typeahead 控件的功能。

我使用此链接使我的指令部分起作用。

Add directives from directive in AngularJS

PLUNKR - The Version 2 of the directive does not work correctly with ng-model

我的指令确实添加了预输入功能并且效果很好,但它没有在选择项目后将模型绑定(bind)到控件上。

我有两个版本的指令。

版本 1:是一个元素样式指令,我已经成功使用它一段时间了,但是当我不想对输入元素有更多控制时,它就不够用了,尤其是当我想使用 ng-required='true' 和其他 ng-message 指令时。

版本 2:是一个属性样式指令,我选择它是因为我觉得将我想要的预输入功能添加到任何可以选择使用 ng 的标准 HTML 中会更好-required='true', ng-model 等...

虽然这个指令大部分都在工作,但它不能与 ng-model 正确交互,我不确定如何让它工作

angular.module(APP)

.directive('wkLocationSuggest', ['$compile', function ($compile) {
  return {
    restrict: 'A',
    require: 'ngModel',
    replace: false,
    //terminal: true,
    //priority: 0,
    scope: {
      wkApiModel: '=' // Provide access to the internal data that is returned via the API lookup
    },
    controller: 'LocationSuggestController',
    link: function (scope, element, attrs, ngModelCtrl) {
      if (!ngModelCtrl) {
        return;
      }

      element.attr('typeahead', 'location as row.location for row in typeAhead($viewValue)');
      element.attr('typeahead-wait-ms', '750');
      element.attr('typeahead-on-select', 'onSelectInternal($item, $model, $label)');
      element.attr('typeahead-min-length', '2');
      element.attr('typeahead-focus-first', 'true');

      element.removeAttr("wk-location-suggest");        //remove the location-suggest to avoid indefinite loop
      element.removeAttr("data-wk-location-suggest");   //also remove the same attribute with data- prefix if it exists

      // None of this is working
      //// invoked when model changes from the outside
      //ngModelCtrl.$render = function () {
      //  //scope.innerModel = ngModelCtrl.$modelValue;
      //};

      ////// invoked when model changes from the inside
      //scope.onChange = function (value) {
      //  ngModelCtrl.$setViewValue(scope.innerModel);
      //};

      scope.onSelectInternal = function ($item, $model, $label) {

        // This fires, but it effects the ng-model on the first input, 
        // but not the input that this directive is attached too
        ngModelCtrl.$setViewValue($item.location);

      };

      $compile(element)(scope);

    }
  };
}]);

这两张图说明了部分问题,自己用上面的PLUNKR测试一下可能会更好

Version 1 & 2 of the directive in action

Version 2 not working correctly

最佳答案

我最初尝试通过在输入元素上组合实现 blur动态添加验证器到您的 wk-location-suggest-new 指令使用 ngModel$setValidity 方法;但不知道究竟是什么阻止了事件的触发。

因此,我转向另一个指令 wk-location-suggest-old 并对其进行了一些调整以适应两种所需的行为。

There, I noticed that you were missing a couple of things:

  • First of all, in order for a form element to glue with the form itself (wkProfileCompany in your case), and to work with ng-model, the element (in the directive template) needs a name.
  • Secondly, ng-required (or required) would work with the form only if it is added as an attribute to the element in the directive template, not the directive which compiles to the template containing the element.

指令定义

您可能会注意到,我已经将两个属性从外部作用域传递到指令的内部作用域,即:

  • 输入元素的名称
  • 和一个 isRequired 标志,用于指定输入是否必需

.

.directive('wkLocationSuggestOld', [function () {
  return {
    restrict: 'E',
    require: '?ngModel',
    scope: {
      name: '@',      // <==
      isRequired: '=' // <==
    },
    template: '<input name="{{name}}" type="text" class="{{innerClass}}" ng-model="innerModel"'
       + ' ng-change="onChange()" uib-typeahead="location as row.location for row in typeAhead($viewValue)" '
       + ' typeahead-wait-ms="750" typeahead-on-select="onSelectInternal($item, $model, $label)" '
       + ' typeahead-min-length="2" typeahead-focus-first="true" '
       + ' ng-required="isRequired">',  // <== added ng-required here
    controller: 'LocationSuggestController',
    link: function (scope, element, attrs, ngModel) {
      if (!ngModel) {
          return;
      }          
      ...
}])

HTML

最后,您可以在您的 HTML 中使用 tweaked 指令:

<wk-location-suggest-old class="form-control" type="text" name="location2" ng-model="location2" is-required="true"></wk-location-suggest-old>

Plunker


更新

ng-model 未在 wk-location-suggest-new 指令中正确绑定(bind)到提供的值的可能原因之一(location3) 是您将整个 DOM 元素替换为新的自定义 DOM 元素,该元素是编译的与指令本身的 isolated scope

由于指令 wk-location-suggest-new 有一个隔离作用域,该作用域完全不知道 location3,因为 location3 ( 和所有其他位置值) 是在MainCtrl 的范围内定义的,而不是指令本身的范围;因此,您最终会将输入的值绑定(bind)到 undefined 属性。

link: function (scope, element, attrs, ngModelCtrl) {
   if (!ngModelCtrl) {
     return;
   }
 ...
$compile(element)(scope); // <== here

关于javascript - 将自定义指令添加到已有 Angular Directive(指令)的现有输入 [ng-model/ng-required],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37454631/

相关文章:

javascript - angularjs指令+在许多 Controller 中应用范围值

javascript - 如何在行中没有任何按钮的情况下在 Angular Js 中使用内联编辑

javascript - AngularJS:创建映射到 REST 资源的对象(ORM 样式)

javascript - 使用 AngularJs 仅允许文本框中的字符

javascript - Angular js指令在表单中未保存数据时显示浏览器后退按钮的警报

angularjs - 使用通过 angular.module().controller() 创建的 AngularJS Controller

javascript - CSS 打印媒体查询删除空格

javascript - 停止多个 setTimeout 实例

javascript - 正则表达式从javascript中的字符串中删除特殊和重复的字符?

javascript - javascript 中的 3d 数组