2016-07-14 19 views
0

マイセットアップ:角度検証問題

<div ng-controller="MyCtrl3"> 
    <datepick ng-model="model.carA" foo3="model.carB"></datepick> 

    <datepick ng-model="model.carB" foo3="model.carA"></datepick> 
    <pre> {{ model | json }} </pre> 
</div> 

datepickディレクティブは次のようになります:

myApp.directive('datepick', function() { 
    return { 
    restrict: 'E', 
    scope: { 
     ngModel: '=' 
    }, 
    template: '<div ng-if="true"><input type="text" ng-model="ngModel.bar"/></div>' 
    }; 
}); 
アンギュラ1.4.4

私はこのようになります簡単なフォームを持っています

したがって、ng-model属性を使用して、プロパティbarのオブジェクトを渡します。今まではすべてが期待通りに機能します。モデルはレンダリングされた形式の変更と同期されます。

次のステップMyCtrl3 - modelに他のオブジェクトを含む現在のディレクティブの基になるモデルのプロパティbarを検証するための検証を導入したいと考えています。私は、この目的のために属性ディレクティブfoo3を作成しました:

myApp.directive('foo3', function() { 
    return { 
    restrict: 'A', 
    require: "ngModel", 
    link: function(scope, element, attrs, controller) { 

     scope.$watch(attrs.foo3, function(newValue, oldValue) { 
     // New Value of comparison field 
     console.log("New valued for comparison model: " + JSON.stringify(newValue)); 
     // Current value of undelying movelValue 
     console.log("Current value for undelying model" + JSON.stringify(controller.$modelValue)); 

     controller.$validate(); 
     }, true); 

     var validateMoreThanDate = function(modelValue, viewValue) { 
     let viewValueObject = modelValue; 
     var comparisonModel = scope.$eval(attr.moreThanDateObject); 

     if ((!viewValueObject && !viewValueObject.bar) || 
      (!comparisonModel && !comparisonModel.bar)) { 
      // It's valid because we have nothing to compare against 
      return true; 
     } 
     // It's valid if model is lower than the model we're comparing against 
     return viewValueObject.bar > comparisonModel.bar; 
     }; 

     controller.$validators['moreThanDateObject'] = validateMoreThanDate; 
    } 
    }; 
}); 

あなたは私がfoo3をディレクティブの引数として比較するためのモデルを渡している見ることができるように。ウォッチャーはすべての変更を追跡しますが、モデルが変更されるとバリデータはトリガーされません。

質問:私のケースではどのようにフィールドを検証できますか? (ここでは、ライブコードを検査するためにjsFiddleを使用しています:https://jsfiddle.net/ichyr/b1jqfkj1/

N.B.私は、オブジェクト内のモデルと、このオブジェクトのプロパティが変更されたときに$パーサと$フォーマッタパイプラインがトリガされていないことを知っている:

は、新しい値がオブジェクト(というよりも、文字列または数値)がある場合は、我々 は$ setViewValueに渡す前にオブジェクトのコピーを作成する必要があります。 これは、ngModelはオブジェクトの深い監視を実行しないため、 はIDの変更のみを検索します。オブジェクトの のプロパティのみを変更すると、ngModelはオブジェクトが を変更したことを認識せず、$ parsersおよび$ validatorsパイプラインを起動しません。

ので、多分$バリもトリガされませんが、controller.$validate()の添加は$のウォッチ式に役立っていませんでした。

答えて

0

N.B.私の同僚は、これを行うためのよりよい方法を提案しました。

この解決策を改善することができます。私たちは、このようにそこ$watchersの使用を省略するカスタムゲッター/セッター機能をdatepickディレクティブの内側に人工物を使用することができます。

myApp.directive('datepick', function() { 
    return { 
    restrict: 'E', 
    scope: { 
     ngModel: '=' 
    }, 
    template: '<div ng-if="model.open"><input type="text" ng-model="model.value"/></div>', 
    link: function(scope) { 
     scope.model = { 
     get value() { 
      return scope.ngModel; 
     }, 
     set value(newValue) { 
      scope.ngModel = parseInt(newValue); 
     }, 
     open: true 
     }; 
    } 
    }; 
}); 

我々は原始的な、そこにオブジェクトをしませ渡し、これはng-ifスコープ内の変数のshaddowingを克服します。

この方法は、次のような利点を紹介します:

  1. たちはネイティブのJS functionlityをleveregingているようdatepickディレクティブ
  2. にオブジェクトを渡す必要が
  3. ができます(これによりパフォーマンスが向上します)いくつかの$watch表現を削除削除angle.jsを利用できるようにするための引数(モデル)としてdatepickerを使用する$パーサ$フォーマッタまたはの$バリ(彼らは/作業オブジェクトのプロパティの変更を検出しません/モデルがオブジェクトである場合)
  4. ゲッターとセッターは角$パーサ$フォーマッタの代わりに使用することができるではない

結果のフィドルはここにあります:https://jsfiddle.net/ichyr/suncp2gf/

0

$ parsers、$ formatters、$ validatorsを使わずに、$ watch ersを使ってこの仕事を成功させました。プロパティーが変更された場合、最初の2つは複雑なモデルでは正しく機能しません。最後のものもうまくいかないようです。

私はng-modelfoo3 +小さな検証機能を介してdatepickディレクティブで参照している両方のモデルの2つの時計を作成しました。だから、foo3検証属性ディレクティブは次のようになります。また、私は、フォーマットのための小さな飾りディレクティブを作成し、入力の値を解析しました

myApp.directive('foo3', function() { 
    return { 
    restrict: 'A', 
    require: "ngModel", 
    link: function(scope, element, attrs, controller) { 

     scope.$watch(attrs.foo3, function(newValue, oldValue) { 
       var isValid = validateMoreThanDate(controller.$modelValue, newValue); 
     controller.$setValidity('moreThanDateObject', isValid); 
     }, true); 

     scope.$watch(attrs.ngModel, function(newValue, oldValue) { 
       var isValid = validateMoreThanDate(newValue, scope.$eval(attrs.foo3)); 
     controller.$setValidity('moreThanDateObject', isValid); 
     }, true); 

     var validateMoreThanDate = function(underlyingModel, comparisonModel) { 
     if ((!underlyingModel && !underlyingModel.bar) || 
      (!comparisonModel && !comparisonModel.bar)) { 
      // It's valid because we have nothing to compare against 
      return true; 
     } 
     // It's valid if model is lower than the model we're comparing against 
     return underlyingModel.bar > comparisonModel.bar; 
     }; 
    } 
    }; 
}); 

inself(テストタイプは、文字列値の結果):

// Directive to format the data in the text inputs 
myApp.directive('numberInputParser', function() { 
    return { 
    restrict: 'A', 
    require: "ngModel", 
    link: function(scope, element, attrs, controller) { 
     debugger; 
     controller.$parsers.unshift(function(data) { 
     return parseInt(data); 
     }); 

     controller.$formatters.unshift(function(data) { 
     debugger; 
     return data; 
     }); 
    } 
    }; 
}); 

そしてdatepick指令のコードは丁重に変更(追加number-input-parserディレクティブ):

myApp.directive('datepick', function() { 
    return { 
    restrict: 'E', 
    scope: { 
     ngModel: '=' 
    }, 
    template: '<div ng-if="true"><input type="text" ng-model="ngModel.bar" number-input-parser/></div>' 
    }; 
}); 

ここにコードが表示されます:https://jsfiddle.net/ichyr/f1qeey37/