javascript - 自定义 Angular Directive(指令)中的 ng-switch 打破了双向绑定(bind)

标签 javascript angularjs datepicker

我创建了自定义指令来封装 uib-datepicker-popup:

'use strict';
angular.module( 'frontendApp' )
.directive( 'inputDate', function(){

var controller = function(){

  var vm = this;

  function init() {
    vm.formats = [ 'dd.MMMM yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate' ];
    vm.format = vm.formats[ 0 ];
    vm.altInputFormats = [ 'M!/d!/yyyy' ];

    vm.dateOptions = {
      datepickerMode: 'day',
      formatYear: 'yy',
      maxDate: new Date(),
      minDate: new Date( 1900, 1, 1 ),
      startingDay: 1
    };

    vm.datepicker = {
      opened: false
    };
  };

  init();

  vm.showDatePicker = function(){
    vm.datepicker.opened = true;
  };
};

var template = '<div ng-switch on="readonly" >' +
    '<div ng-switch-when="true" class="form-control" readonly>' +
      '<div readonly name="readonlyText">{{ngModel | date : \'d.MMMM yyyy\'}}</div>' +
    '</div>' +
    '<div ng-switch-default class="input-group">' +
      '<input class="form-control" type="text" uib-datepicker-popup="{{vm.format}}" ng-model="ngModel" ng-model-options="{timezone:\'UTC\'}" is-open="vm.datepicker.opened" datepicker-options="vm.dateOptions" ng-required="true" show-button-bar="false" alt-input-formats="vm.altInputFormats" />' +
      '<span class="input-group-btn">' +
        '<button type="button" class="btn btn-default" ng-click="vm.showDatePicker()"><i class="glyphicon glyphicon-calendar"></i></button>' +
      '</span>' +
    '</div>' +
  '</div>';


return{
  controller: controller,
  controllerAs: 'vm',
  bindToController: true,
  template: template,
  restrict: 'EA',
  scope           :true,
  require:'ngModel',
  link: function( scope, element, attrs, ngModel ){
    // Bring in changes from outside:
    scope.$watch( 'ngModel', function(){
      if( ngModel ) {
        scope.$eval( attrs.ngModel + ' = ngModel' );
      }
    } );

    // Send out changes from inside:
    scope.$watch( attrs.ngModel, function( val ){
      if( val ) {
        scope.ngModel = val;
      }
    } );

    if( attrs.readonly === 'true' ) {
      scope.readonly = true;
    }
  }
};

} );

html 部分是:

<input-date ng-model="form.flight.date"></input-date>

问题:如果出现弹出窗口,则表明scope.ngModel已从attrs.ngModel正确初始化。我在观察器内有一个日志,它向我显示观看 attrs.ngModel 工作得很好,但是观看“ngModel”或scope.ngModel 只能在我使用日期选择器之前工作。只要不触发日期选择器,它就可以完美工作。 刚刚发现,如果我删除它,它会完美地工作 “ng-switch-default”。将其替换为 ng-show/ng-hide 可使指令完全按预期工作。

谁能解释一下为什么吗?

最佳答案

您看到的行为绝对正确。当您使用 ng-ifng-switchng-repeat 等结构指令时,它会创建一个新作用域并复制父范围的所有属性。您的模型是一个基元(字符串),因此它会完全复制到新范围并在此范围内进行更改,而不会传播到父级模型。

你能做的是:

  1. 使用对象而不是字符串来传递ng-model,我个人觉得这里很尴尬
  2. 从 Controller 对象而不是范围中使用 ng-model

继续使用第二种方法:您已经使用了 bindToController 和一个通过 scope: true 隔离的作用域,因此不必使用观察者跟踪模型,而是将其绑定(bind)到 Controller :

return {
  bindToController: true,
  scope: {
    ngModel: '='
  },
  ...

所以理想情况下,您甚至不需要链接功能并在模板中代替

'<div readonly name="readonlyText">{{ngModel | date : \'d.MMMM yyyy\'}}</div>'

使用

'<div readonly name="readonlyText">{{vm.ngModel | date : \'d.MMMM yyyy\'}}</div>'

为什么 ng-hide 仍然有效?它不会创建新的范围。

关于javascript - 自定义 Angular Directive(指令)中的 ng-switch 打破了双向绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36665000/

相关文章:

javascript - Extjs 4.1.1 在 Datepicker 中添加了新按钮,但其处理程序不起作用

c# - Silverlight SDK 日期选取器未将所选日期重置为今天

javascript - 使用 JavaScript 访问本地文件

javascript - 使用 ng-src 访问对象内部的数组

javascript - 在建立TLS连接时,如何传递其他信息?

javascript - 禁用对 UI-Grid 中特定列的过滤

javascript - 如何在 AngularJS 中动态更改 $http 服务 URL?

JavaScript 日期和时间选择器

javascript - 谷歌地图 API v3 : Custom styles for infowindow

javascript - 递归查找 JSON 值并返回对象