4

angular jsで検証する必要がある3つの部分の日付フィールドがあります。カスタム検証関数の作成までは完了しましたが、フィールドが互いのステータスを更新する方法のロジックを設計するのに問題があります。

3 つのフォーム フィールドすべてで同じ賛美歌シートを歌い、他のフィールドに応じてすべてのステータスを有効または無効として表示するにはどうすればよいですか?

これがフィドルです:http://jsfiddle.net/4GsMm/1/

そしてコード:

<div ng-app="myApp" ng-controller="myCtrl">
    <form action="" name="myForm">
        <div class="date-group">
            <input type="text" name="day" ng-model="day" ng-valid-func="validator" />
            <input type="text" name="month" ng-model="month" ng-valid-func="validator" />
            <input type="text" name="year" ng-model="year" ng-valid-func="validator" />
        </div>
    </form>
</div>

と...

input.ng-invalid{
    background-color: #fdd !important;    
}

input.ng-valid{
    background-color: #dfd !important;    
}

input{
    display: inline;
    width: 3em;
}

と...

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

var myCtrl = function($scope){

    $scope.day = "01"
    $scope.month = "01"
    $scope.year = "2000"

    $scope.validator = function(val){
        var day = $('[name=day]').val()
        var month = $('[name=month]').val()
        var year = $('[name=year]').val()
        var d = new Date([year,month,day].join('-'))
        console.log(d, [year,month,day].join('-'))
        return d > new Date('2000-01-01')
    }

}

app.directive('ngValidFunc', function() {
  return {
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {
      ctrl.$parsers.unshift(function(viewValue) {
        if (attrs.ngValidFunc && scope[attrs.ngValidFunc] && scope[attrs.ngValidFunc](viewValue, scope, elm, attrs, ctrl)) {
          ctrl.$setValidity('custom', true);
        } else {
          ctrl.$setValidity('custom', false);
        }
        return elm.val()
      });
    }
  };
});
4

4 に答える 4

4

私もAngularJSで3つの部分の日付フィールドの検証を探していました.これが私がやったことです(私のために働いています)

HTML:

<form name="myForm" method="post" novalidate ng-submit="somefuncion()" ng-controller="Controller" ng-app="testModule">
    Date (MM-DD-YYYY): <input id="partnerDOBmm" name="partnerDOBmm" class="ddinput" type="text" value="" size="2" maxlength="2" ng-model="partnerDOBmm" required only-digits ng-minlength="2" ng-change="validateDOB(partnerDOBmm,partnerDOBdd,partnerDOByyyy)"  />
    -
    <input id="partnerDOBdd" name="partnerDOBdd" class="ddinput" type="text" value="" size="2" maxlength="2" ng-model="partnerDOBdd" required only-digits ng-minlength="2" ng-change="validateDOB(partnerDOBmm,partnerDOBdd,partnerDOByyyy)" />
    -
    <input id="partnerDOByyyy" name="partnerDOByyyy" class="yyyyinput" type="text" value="" size="4" maxlength="4" ng-model="partnerDOByyyy" required only-digits ng-minlength="4" ng-change="validateDOB(partnerDOBmm,partnerDOBdd,partnerDOByyyy)" />
    <br />
    <span class="error" ng-show="submitted && (myForm.partnerDOBmm.$error.required || myForm.partnerDOBdd.$error.required || myForm.partnerDOByyyy.$error.required)"> Required! </span>
    <span class="error" ng-show="submitted && (myForm.partnerDOBmm.$error.minlength || myForm.partnerDOBdd.$error.minlength || myForm.partnerDOByyyy.$error.minlength)"> Too Short! </span>
    <span class="error" ng-show="notValidDate && !(myForm.partnerDOBmm.$error.required || myForm.partnerDOBdd.$error.required || myForm.partnerDOByyyy.$error.required || myForm.partnerDOBmm.$error.minlength || myForm.partnerDOBdd.$error.minlength || myForm.partnerDOByyyy.$error.minlength)"> Not a Valid Date! </span>
    <br />
    <button type="submit" class="btnSubmit" ng-click="submitted=true">Submit</button>
</form>

脚本:

function Controller ($scope) {
    $scope.notValidDate = false;
    $scope.somefuncion = function(event) {
        if ($scope.myForm.$valid) {
            alert("Form is working as expected");
            return true;
        }
        else
        {
            alert("Something is not correct");
            return false;
        }
    };
    $scope.validateDOB  = function(mm,dd,yyyy)
    {
        var flag = true;
        var month = mm;
        var date = dd;
        var year = yyyy;
        if(month == null || date == null || year == null || month.length != 2 || date.length!= 2 || year.length!= 4)
            flag = false;
        if(month < 1 || month > 12)
            flag = false;
        if(year < 1900 || year > 2100)
            flag = false;
        if(date < 1 || date > 31)
            flag = false;

        if((month == 04 || month == 06 || month == 9 || month == 11) && (date >= 31))
            flag = false;

        if(month == 02)
        {
            if(year % 4 != 0)
            {
                if(date > 28)
                    flag = false;
            }
            if(year % 4 == 0)
            {
                if(date > 29)
                    flag = false;
            }
        }

        var dob = new Date();
        dob.setFullYear(year, month - 1, date);
        var today = new Date();
        if(dob > today)
            flag = false;

        if(flag)
        {
            $scope.notValidDate = false;
            $scope.myForm.$valid = true;
        }
        else
        {
            $scope.notValidDate = true;
            $scope.myForm.$valid = false;
            form.partnerDOBmm.focus();
        }
    }
}

angular.module('testModule', [])
.directive('onlyDigits', function () {

    return {
        restrict: 'A',
        require: '?ngModel',
        link: function (scope, element, attrs, ngModel) {
            if (!ngModel) return;
            ngModel.$parsers.unshift(function (inputValue) {
                var digits = inputValue.replace(/[^\d]/g, "");
                ngModel.$viewValue = digits;
                ngModel.$render();
                return digits;
            });
        }
    };
});

自由に即興で答えてください。うまくいけば、「validateDOB」関数で「else」を使用できます

于 2014-02-04T12:30:46.957 に答える
2

現実的には、バリデーターとバリデーターを使用input type="number"し、関数を呼び出して日付を更新するディレクティブを追加した方がよいでしょう。maxminng-change

入力の内容が無効な場合は変更が発生しないため、「悪い」日付になることはありません。

<input type="number" name="year" ng-model="year" min="2000" ng-change="updateDate()"/>
<input type="number" name="month" ng-model="month" min="1" max="12" ng-change="updateDate()" />
<input type="number" name="day" ng-model="day" min="1" max="31" ng-change="updateDate()" />

これは、このソリューションを示すプランクです。

ただし、月と日のテキスト ボックスを使用すると、日の値がコーシャであることを確認するよりもはるかに複雑になるため、悪い解決策になる可能性があります。(たとえば、2 月と閏年について考えてみてください)。このソリューション全体では、少なくとも日、おそらく月にもドロップダウンを使用することをお勧めします...必要な結果の固定セットがあり、日オプションを表示または非表示にすることができます。月オプションの値。

その例を次に示します。

<form name="myForm">
    <input type="number" name="year" ng-model="year" min="2000" ng-change="updateDate()"/>
    <select name="month" ng-model="month" ng-change="updateDate()">
      <option value="1">Jan</option>
      <option value="2">Feb</option>
      <option value="3">Mar</option>
      <option value="4">Apr</option>
      <option value="5">May</option>
      <option value="6">Jun</option>
      <option value="7">Jul</option>
      <option value="8">Aug</option>
      <option value="9">Sep</option>
      <option value="10">Oct</option>
      <option value="11">Nov</option>
      <option value="12">Dec</option>
    </select>
    <select name="day" ng-model="day" ng-change="udpateDate()">
      <option>1</option>
      <option>2</option>
      <option>3</option>
      <!-- ... SNIP!... -->
      <option>27</option>
      <option>28</option>
      <option ng-show="month != 2 || !(year % 4)")>
        29
      </option>
      <option ng-show="month != 2">
        30
      </option>
      <option ng-show="month == 1 || month == 3 || month == 5 || month == 7 || 
          month == 8 || month == 10 || month == 12">
        31
      </option>
    </select>
    <p>
      {{date | date: 'yyyy-MMM-dd'}}
    </p>
  </form>

しかし、なぜそれらの選択を動的に作成しないのでしょうか?

上記の選択を動的に作成できますか? もちろん。その価値はありますか?多分?おそらくそうではありません。オプションと show/hyde ロジックを入力するのに 30 秒しかかかりませんでした。

そして、これがプランクの例です。

上記の両方のシナリオで、2001 年の検証で検証できます。

<span ng-show="myForm.year.$error.min">Must be after January 1, 2001</span>
于 2013-09-27T16:38:54.383 に答える
1

私は非常によく似た問題を抱えていました。問題は、おそらくフィールド同士の関係をチェックしたくないということです。これを行うと、たとえば 2 月 30 日でない場合など、日付が実際に有効かどうかを確認するのが非常に難しくなります。やりたいことは、中間要素を介して日付全体をチェックすることです。

補足として、設計上、コントローラーはこの種のアクティビティに関与するべきではありません。検証はディレクティブ レベルで実行する必要があるため、再利用可能で Angular と一貫性があり、バリデータ チェーンの利点が得られます。たとえば、有効な日付だけをチェックする必要があるが、別の日付では生年月日を年齢でチェックする必要がある場合、コードを「濡らす」ことになります:)

私は、Angular の哲学にうまく適合する、合理的に単純な解決策を思いつきました。トリックは、3 つのドロップダウンすべてをまとめて、日付全体の検証を一度に実行する中間フォーム要素 (たとえば、非表示の入力) を使用することです。

フォーカスを設定するための HTML は次のとおりです。

<form name="dateForm" novalidation>
  <input type="hidden"
      ng-model="modelDate"
      date-type-multi="viewDate"
      ng-init="viewDate = {}"
      class="form-control"
  />
  <select ng-model="viewDate.day">
    <option value="">select day</option>
    <option value="1">1</option>
    <option value="2">2</option>
    <option value="3">3</option>
    <option value="4">4</option>
    <option value="5">5</option>
    <option value="6">6</option>
    <option value="7">7</option>
    <option value="8">8</option>
    <option value="9">9</option>
    <option value="10">10</option>
    <option value="11">11</option>
    <option value="12">12</option>
    <option value="13">13</option>
    <option value="14">14</option>
    <option value="15">15</option>
    <option value="16">16</option>
    <option value="17">17</option>
    <option value="18">18</option>
    <option value="19">19</option>
    <option value="20">20</option>
    <option value="21">21</option>
    <option value="22">22</option>
    <option value="23">23</option>
    <option value="24">24</option>
    <option value="25">25</option>
    <option value="26">26</option>
    <option value="27">27</option>
    <option value="28">28</option>
    <option value="29">29</option>
    <option value="30">30</option>
    <option value="31">31</option>
  </select>
  <select ng-model="viewDate.month">
    <option value="">select month</option>
    <option value="1">1</option>
    <option value="2">2</option>
    <option value="3">3</option>
    <option value="4">4</option>
    <option value="5">5</option>
    <option value="6">6</option>
    <option value="7">7</option>
    <option value="8">8</option>
    <option value="9">9</option>
    <option value="10">10</option>
    <option value="11">11</option>
    <option value="12">12</option>
  </select>
  <select ng-model="viewDate.year">
    <option value="">select year</option>
    <option value="1981">1981</option>
    <option value="1982">1982</option>
    <option value="1983">1983</option>
    <option value="1984">1984</option>
    <option value="1985">1985</option>
    <option value="1986">1986</option>
    <option value="1987">1987</option>
    <option value="1988">1988</option>
    <option value="1989">1989</option>
    <option value="1990">1990</option>
    <option value="1991">1991</option>
    <option value="1992">1992</option>
  </select>
</form>

そしてJSコード:

angular.module('dateApp', []).
  directive('dateTypeMulti', function() {
    return {
      priority: -1000,
      require: 'ngModel',
      link: function(scope, elem, attrs, ngModel) {
        ngModel.$render = function() {
          angular.extend(scope.$eval(attrs.dateTypeMulti), ngModel.$viewValue);
        };

        scope.$watch(attrs.dateTypeMulti, function(viewValue) {
          ngModel.$setViewValue(viewValue);
        }, true);

        ngModel.$formatters.push(function(modelValue) {
          if (!modelValue) return;

          var parts = String(modelValue).split('/');

          return {
            year: parts[0],
            month: parts[1],
            day: parts[2]
          };
        });

        ngModel.$parsers.unshift(function(viewValue) {
          var isValid = true,
            modelValue = '',
            date;

          if (viewValue) {
            date = new Date(viewValue.year, viewValue.month - 1, viewValue.day);
            modelValue = [viewValue.year, viewValue.month, viewValue.day].join('/');

            if ('//' === modelValue) {
              modelValue = '';
            } else if (
              date.getFullYear() != viewValue.year ||
              date.getMonth() != viewValue.month - 1 ||
              date.getDate() != viewValue.day) {
              isValid = false;
            }
          }

          ngModel.$setValidity('dateTypeMulti', isValid);

          return isValid ? modelValue : undefined;
        });
      }
    };
  });

ディレクティブの優先度を低く設定することが重要です。そうすると、パーサーが最初のパーサーとして起動され (フォーマッターとは逆の順序で動作)、このフィールドの他のバリデーターが解析された日付を取得するためです。

ここで遊ぶことができます: http://codepen.io/jciolek/pen/oxBch

ここで詳細に説明した思考プロセス: http://float-middle.com/multiple-fields-validation-in-angularjs/

役に立てば幸いです、Jacek

于 2014-10-10T22:15:28.820 に答える
1

最後のフィールドにディレクティブを追加し、以下のようにディレクティブで $watchCollection を使用します (例は coffeescript です)。

@validateDateDirective = ->
    require: "ngModel"
    link: (scope, elem, attr, ngModel) ->
        # Get the base model name without the _day _month _year appended
        # e.g for field 'birth_date_year', this would equal 'birth_date'
        modelName = attr.ngModel.replace('_day', '').replace('_month', '').replace('_year', '')

        # use base model name to watch all models in target fieldset
        scope.$watchCollection '['+modelName+'_day, '+modelName+'_month, '+modelName+'_year]', ->
            # Set global value
            value = [scope.$eval(modelName+'_year'),
                    scope.$eval(modelName+'_month'), 
                    scope.$eval(modelName+'_day')]

            # << do your validation here >>
于 2014-11-08T04:22:54.803 に答える