programing

Angular.js 및 Bootstrap 양식 유효성 검사 스타일 조정

nasanasas 2020. 10. 25. 12:25
반응형

Angular.js 및 Bootstrap 양식 유효성 검사 스타일 조정


Angular를 Bootstrap과 함께 사용하고 있습니다. 참조 용 코드는 다음과 같습니다.

<form name="newUserForm" ng-submit="add()" class="" novalidate>
    <input type="text" class="input" ng-model="newUser.uname" placeholder="Twitter" ng-pattern="/^@[A-Za-z0-9_]{1,15}$/" required></td>
    <button type="submit" ng-disabled="newUserForm.$invalid" class="btn btn-add btn-primary">Add</button>
</form>

부트 스트랩에는 형식이 잘못된 필드에 대한 스타일이 있습니다 input:invalid {.... }. 필드가 비어있을 때이 킥을합니다. 이제 Angular를 통해 몇 가지 패턴 일치가 있습니다. 이로 인해 ": invalid"가 꺼져 있지만 ".ng-invalid"가 켜져있는 경우 이상한 경우가 발생하여 ".ng-invalid"클래스에 대한 부트 스트랩 CSS 클래스를 다시 구현해야합니다.

두 가지 옵션이 표시되지만 둘 다 문제가 있습니다.

  • Angular가 "ng-valid"대신 사용자 지정 클래스 이름을 사용하도록합니다 (이 작업을 수행하는 방법을 모르겠습니다).
  • html5 유효성 검사를 비활성화합니다 (이게 양식 태그의 "novalidate"속성이해야 할 일이라고 생각했지만 어떤 이유로 작동하지 못했습니다).

Angular-Bootstrap 지시문은 스타일을 다루지 않습니다.


스타일링을 위해 Bootstrap의 "오류"클래스를 사용하십시오. 적은 코드를 작성할 수 있습니다.

<form name="myForm">
  <div class="control-group" ng-class="{error: myForm.name.$invalid}">
    <label>Name</label>
    <input type="text" name="name" ng-model="project.name" required>
    <span ng-show="myForm.name.$error.required" class="help-inline">
        Required</span>
  </div>
</form>

편집 : 다른 답변과 의견이 지적했듯이 부트 스트랩 3에서 클래스는 이제 "오류"가 아닌 "오류가 있음"입니다.


클래스는 Bootstrap 3에서 변경되었습니다.

<form class="form-horizontal" name="form" novalidate ng-submit="submit()" action="/login" method="post">
  <div class="row" ng-class="{'has-error': form.email.$invalid, 'has-success': !form.email.$invalid}">
    <label for="email" class="control-label">email:</label>
    <div class="col">
    <input type="email" id="email" placeholder="email" name="email" ng-model="email" required>
    <p class="help-block error" ng-show="form.email.$dirty && form.email.$error.required">please enter your email</p>
    <p class="help-block error" ng-show="form.email.$error.email">please enter a valid email</p>
  ...

주위에 따옴표를 참고 'has-error'하고 'has-success': 그를 찾기 위해 잠시했다 ...


또 다른 해결책 : has-error자식 입력에 따라 클래스 를 토글하는 지시문을 만듭니다 .

app.directive('bsHasError', [function() {
  return {
      restrict: "A",
      link: function(scope, element, attrs, ctrl) {
          var input = element.find('input[ng-model]'); 
          if (input.length) {
              scope.$watch(function() {
                  return input.hasClass('ng-invalid');
              }, function(isInvalid) {
                  element.toggleClass('has-error', isInvalid);
              });
          }
      }
  };
}]);

그런 다음 템플릿에서 간단히 사용

<div class="form-group" bs-has-error>
    <input class="form-control" ng-model="foo" ng-pattern="/.../"/>
</div>

@farincz의 답변이 약간 개선되었습니다 . 나는 지시 여기에 가장 좋은 방법은 동의하지만, 나는 모든 그것을 반복하고 싶지 않았다 .form-groupI가 중 하나를 추가 할 수 있도록 코드를 업데이트 있도록 요소 .form-group부모 나에 <form>모두 포함에 추가 할 (요소 .form-group요소 ) :

angular.module('directives', [])
  .directive('showValidation', [function() {
    return {
        restrict: "A",
        link: function(scope, element, attrs, ctrl) {

            if (element.get(0).nodeName.toLowerCase() === 'form') {
                element.find('.form-group').each(function(i, formGroup) {
                    showValidation(angular.element(formGroup));
                });
            } else {
                showValidation(element);
            }

            function showValidation(formGroupEl) {
                var input = formGroupEl.find('input[ng-model],textarea[ng-model]');
                if (input.length > 0) {
                    scope.$watch(function() {
                        return input.hasClass('ng-invalid');
                    }, function(isInvalid) {
                        formGroupEl.toggleClass('has-error', isInvalid);
                    });
                }
            }
        }
    };
}]);

@Andrew Smith의 답변이 약간 개선되었습니다. 입력 요소를 변경하고 require키워드를 사용 합니다.

.directive('showValidation', [function() {
    return {
        restrict: "A",
        require:'form',
        link: function(scope, element, attrs, formCtrl) {
            element.find('.form-group').each(function() {
                var $formGroup=$(this);
                var $inputs = $formGroup.find('input[ng-model],textarea[ng-model],select[ng-model]');

                if ($inputs.length > 0) {
                    $inputs.each(function() {
                        var $input=$(this);
                        scope.$watch(function() {
                            return $input.hasClass('ng-invalid');
                        }, function(isInvalid) {
                            $formGroup.toggleClass('has-error', isInvalid);
                        });
                    });
                }
            });
        }
    };
}]);

좋은 답변을 위해 @farincz에게 감사드립니다. 다음은 사용 사례에 맞게 수정 한 몇 가지 사항입니다.

이 버전은 세 가지 지시문을 제공합니다.

  • bs-has-success
  • bs-has-error
  • bs-has (다른 두 가지를 함께 사용하고 싶을 때 편리함)

내가 수정 한 사항 :

  • 양식 필드가 더러울 때만 has 상태를 표시하는 체크를 추가했습니다. 즉, 누군가가 상호 작용할 때까지 표시되지 않습니다.
  • Angular의 jQLite에서 태그 이름으로 요소 찾기 만 지원하므로 element.find()jQuery를 사용하지 않는 사람들 위해 전달 된 문자열이 변경 element.find()되었습니다.
  • 선택 상자 및 텍스트 영역에 대한 지원이 추가되었습니다.
  • 요소가 DOM에 아직 렌더링되지 않은 경우 (예 : 요소의 자식이로 표시된 경우)를 지원하기 위해 element.find()래핑 되었습니다 .$timeoutng-if
  • 변경 if(표현은 반환 된 배열의 길이를 확인하기 if(input)에서 @ farincz의 대답 에서 항상 수익으로, true를 돌려 element.find()JQuery와 배열입니다).

누군가 이것이 유용하다고 생각하기를 바랍니다!

angular.module('bs-has', [])
  .factory('bsProcessValidator', function($timeout) {
    return function(scope, element, ngClass, bsClass) {
      $timeout(function() {
        var input = element.find('input');
        if(!input.length) { input = element.find('select'); }
        if(!input.length) { input = element.find('textarea'); }
        if (input.length) {
            scope.$watch(function() {
                return input.hasClass(ngClass) && input.hasClass('ng-dirty');
            }, function(isValid) {
                element.toggleClass(bsClass, isValid);
            });
        }
      });
    };
  })
  .directive('bsHasSuccess', function(bsProcessValidator) {
    return {
      restrict: 'A',
      link: function(scope, element) {
        bsProcessValidator(scope, element, 'ng-valid', 'has-success');
      }
    };
  })
  .directive('bsHasError', function(bsProcessValidator) {
    return {
      restrict: 'A',
      link: function(scope, element) {
        bsProcessValidator(scope, element, 'ng-invalid', 'has-error');
      }
    };
  })
  .directive('bsHas', function(bsProcessValidator) {
    return {
      restrict: 'A',
      link: function(scope, element) {
        bsProcessValidator(scope, element, 'ng-valid', 'has-success');
        bsProcessValidator(scope, element, 'ng-invalid', 'has-error');
      }
    };
  });

용법:

<!-- Will show success and error states when form field is dirty -->
<div class="form-control" bs-has>
  <label for="text"></label>
  <input 
   type="text" 
   id="text" 
   name="text" 
   ng-model="data.text" 
   required>
</div>

<!-- Will show success state when select box is anything but the first (placeholder) option -->
<div class="form-control" bs-has-success>
  <label for="select"></label>
  <select 
   id="select" 
   name="select" 
   ng-model="data.select" 
   ng-options="option.name for option in data.selectOptions"
   required>
    <option value="">-- Make a Choice --</option>
  </select>
</div>

<!-- Will show error state when textarea is dirty and empty -->
<div class="form-control" bs-has-error>
  <label for="textarea"></label>
  <textarea 
   id="textarea" 
   name="textarea" 
   ng-model="data.textarea" 
   required></textarea>
</div>

이 모든 것을 함께 번들로 제공하는 Guilherme의 bower 패키지설치할 수도 있습니다.


스타일링이 문제이지만 네이티브 유효성 검사를 비활성화하고 싶지 않다면 스타일을 좀 더 구체적인 스타일로 재정의하는 것이 어떻습니까?

input.ng-invalid, input.ng-invalid:invalid {
   background: red;
   /*override any styling giving you fits here*/
}

CSS 선택기 특이성으로 문제를 해결하세요!


Jason Im의 답변에 대한 개선 사항은 다음 두 가지 새로운 지시문 show-validation-errors 및 show-validation-error를 추가합니다.

'use strict';
(function() {

    function getParentFormName(element,$log) {
        var parentForm = element.parents('form:first');
        var parentFormName = parentForm.attr('name');

        if(!parentFormName){
            $log.error("Form name not specified!");
            return;
        }

        return parentFormName;
    }

    angular.module('directives').directive('showValidation', function () {
        return {
            restrict: 'A',
            require: 'form',
            link: function ($scope, element) {
                element.find('.form-group').each(function () {
                    var formGroup = $(this);
                    var inputs = formGroup.find('input[ng-model],textarea[ng-model],select[ng-model]');

                    if (inputs.length > 0) {
                        inputs.each(function () {
                            var input = $(this);
                            $scope.$watch(function () {
                                return input.hasClass('ng-invalid') && !input.hasClass('ng-pristine');
                            }, function (isInvalid) {
                                formGroup.toggleClass('has-error', isInvalid);
                            });
                            $scope.$watch(function () {
                                return input.hasClass('ng-valid') && !input.hasClass('ng-pristine');
                            }, function (isInvalid) {
                                formGroup.toggleClass('has-success', isInvalid);
                            });
                        });
                    }
                });
            }
        };
    });

    angular.module('directives').directive('showValidationErrors', function ($log) {
        return {
            restrict: 'A',
            link: function ($scope, element, attrs) {
                var parentFormName = getParentFormName(element,$log);
                var inputName = attrs['showValidationErrors'];
                element.addClass('ng-hide');

                if(!inputName){
                    $log.error("input name not specified!")
                    return;
                }

                $scope.$watch(function () {
                    return !($scope[parentFormName][inputName].$dirty && $scope[parentFormName][inputName].$invalid);
                },function(noErrors){
                    element.toggleClass('ng-hide',noErrors);
                });

            }
        };
    });

    angular.module('friport').directive('showValidationError', function ($log) {
        return {
            restrict: 'A',
            link: function ($scope, element, attrs) {
                var parentFormName = getParentFormName(element,$log);
                var parentContainer = element.parents('*[show-validation-errors]:first');
                var inputName = parentContainer.attr('show-validation-errors');
                var type = attrs['showValidationError'];

                element.addClass('ng-hide');

                if(!inputName){
                    $log.error("Could not find parent show-validation-errors!");
                    return;
                }

                if(!type){
                    $log.error("Could not find validation error type!");
                    return;
                }

                $scope.$watch(function () {
                    return !$scope[parentFormName][inputName].$error[type];
                },function(noErrors){
                    element.toggleClass('ng-hide',noErrors);
                });

            }
        };
    });

})();

show-validation-errors는 오류 컨테이너에 추가되어 양식 필드 유효성에 따라 컨테이너를 표시하거나 숨길 수 있습니다.

그리고 show-validation-error는 주어진 유형에 대한 해당 양식 필드 유효성을 기반으로 요소를 표시하거나 숨 깁니다.

용도의 예 :

        <form role="form" name="organizationForm" novalidate show-validation>
            <div class="form-group">
                <label for="organizationNumber">Organization number</label>
                <input type="text" class="form-control" id="organizationNumber" name="organizationNumber" required ng-pattern="/^[0-9]{3}[ ]?[0-9]{3}[ ]?[0-9]{3}$/" ng-model="organizationNumber">
                <div class="help-block with-errors" show-validation-errors="organizationNumber">
                    <div show-validation-error="required">
                        Organization number is required.
                    </div>
                    <div show-validation-error="pattern">
                        Organization number needs to have the following format "000 000 000" or "000000000".
                    </div>
                </div>
            </div>
       </form>

답장하기에는 너무 늦었다 고 생각하지만 마음에 들기를 바랍니다.

CSS 선택, 날짜, 비밀번호 등과 같은 다른 유형의 컨트롤을 추가 할 수 있습니다.

input[type="text"].ng-invalid{
    border-left: 5px solid #ff0000;
    background-color: #FFEBD6;
}
input[type="text"].ng-valid{
    background-color: #FFFFFF;
    border-left: 5px solid #088b0b;
}
input[type="text"]:disabled.ng-valid{
    background-color: #efefef;
    border: 1px solid #bbb;
}

HTML: no need to add anything in controls except ng-required if it is

<input type="text"
       class="form-control"
       ng-model="customer.ZipCode"
       ng-required="true">

Just try it and type some text in your control, I find it really handy and awesome.


It's hard to tell for sure without a fiddle but looking at the angular.js code it does not replace classes - it just adds and removes its own. So any bootstrap classes (added dynamically by bootstrap UI scripts) should be untouched by angular.

That said, it does not make sense to use Bootstrap's JS functionality for validation at the same time as Angular - only use Angular. I would suggest you employ the bootstrap styles and the angular JS i.e. add the bootstrap css classes to your elements using a custom validation directive.


<div class="form-group has-feedback" ng-class="{ 'has-error': form.uemail.$invalid && form.uemail.$dirty }">
  <label class="control-label col-sm-2" for="email">Email</label>
  <div class="col-sm-10">
    <input type="email" class="form-control" ng-model="user.email" name="uemail" placeholder="Enter email" required>
    <div ng-show="form.$submitted || form.uphone.$touched" ng-class="{ 'has-success': form.uemail.$valid && form.uemail.$dirty }">
    <span ng-show="form.uemail.$valid" class="glyphicon glyphicon-ok-sign form-control-feedback" aria-hidden="true"></span>
    <span ng-show="form.uemail.$invalid && form.uemail.$dirty" class="glyphicon glyphicon-remove-circle form-control-feedback" aria-hidden="true"></span>
    </div>
  </div>
</div>

I know this is a very old question answer thread when I haven't heard the name of AngularJS itself :-)

But for others who land to this page looking for Angular + Bootstrap form validation in a clean and automated way, I've written a pretty small module for achieving the same without altering the HTML or Javascript in any form.

Checkout Bootstrap Angular Validation.

Following are the three simple steps:

  1. Install via Bower bower install bootstrap-angular-validation --save
  2. Add the script file <script src="bower_components/bootstrap-angular-validation/dist/bootstrap-angular-validation.min.js"></script>
  3. Add the dependency bootstrap.angular.validation to your application and that's it!!

This works with Bootstrap 3 and jQuery is not required.

This is based on the concept of jQuery validation. This module provides some additional validation and common generic messages for validation error.

참고URL : https://stackoverflow.com/questions/14348384/reconcile-angular-js-and-bootstrap-form-validation-styling

반응형