Подтвердить что ты не робот

Как показать входные ошибки формы с помощью всплывающей подсказки UTU для AngularJS?

Например, у меня есть форма, где я показывает ошибки ввода формы.

Мне нужно показать красный значок (при наведении указателя на ошибки) возле метки ввода, если есть некоторые ошибки. Если пользователь наведет этот красный значок - он увидит список ошибок, используя подсказку AngularJS UT Bootstrap. Я не хочу помещать список ошибок в атрибут tooltip-html-unsafe, потому что это не удобно редактировать и поддерживать.

Этот код более декларативный:

<validation-tooltip ng-show="appForm.number.$invalid && appForm.number.$dirty">
    <ul>
        <li ng-show="appForm.number.$error.required">this field is required</li>
        <li ng-show="appForm.number.$error.number">should be number</li>
        <li ng-show="appForm.number.$error.min">minimum - 5</li>
        <li ng-show="appForm.number.$error.max">miximum - 20</li>
    </ul>
</validation-tooltip>

чем этот код:

<span tooltip-html-unsafe="{{<ul><li>This field is required;</li><li>...</li></ul>}}">hover to show errors</span>

Как я могу написать такую ​​директиву-подсказку-подсказку с помощью всплывающей подсказки AngularJS UI Bootstrap?

Или, может быть, вы можете предложить другой подход для поддержания сообщений об ошибках проверки?

4b9b3361

Ответ 1

Демо-скрипт

Директива подсказки по проверке

ВалидацияTooltip является основной директивой. Он несет следующие обязанности:

  • Определите шаблон подсказки инструмента через его переведенное содержимое.
  • Следите за выражениями проверки, чтобы их можно было оценивать с каждым циклом дайджест.
  • Откройте API-интерфейс контроллера, чтобы позволить директивам valiationMessage регистрироваться
  • Предоставить атрибут "target" в директиве, чтобы указать, какое поле формы означает, что значок (и связанная с ним подсказка) будет привязан к

Дополнительные примечания

В шаблоне всплывающей подсказки используется функция перехода из функции привязки для привязки шаблона к области действия директивы. Существует два свойства, которые могут быть связаны с шаблоном:

  • $form. Связано с моделью формы, определенной в родительской области. то есть $scope.myForm
  • $field. Связано с моделью form.name в родительской области. то есть $scope.myForm.myInput

Это позволяет шаблону привязываться к свойствам проверки, таким как $valid, $invalid, $pristine, $dirty и $error без прямого обращения к имени формы или имени поля ввода. Например, все следующие выражения являются допустимыми выражениями привязки:

$свойства формы:

  •  
  • `$ форма. $Valid` 
  • `$ форма. $Invalid` 
  • `$ форма. $Dirty` 
  • `$ форма. $Pristine` 
  • `$ form. $error.required` и т.д.

$свойства поля:

  •  
  • `$ поле. $Valid` 
  • `$ поле. $Invalid` 
  • `$ поле. $Dirty` 
  • `$ поле. $Pristine` 
  • `$. $error.required` и т.д.

Реализация директивы

app.directive('validationTooltip', function ($timeout) {
    return {
        restrict: 'E',
        transclude: true,
        require: '^form',
        scope: {},
        template: '<span class="label label-danger span1" ng-show="errorCount > 0">hover to show err</span>',
        controller: function ($scope) {
            var expressions = [];
            $scope.errorCount = 0;
            this.$addExpression = function (expr) {
                expressions.push(expr);
            }
            $scope.$watch(function () {
                var count = 0;
                angular.forEach(expressions, function (expr) {
                    if ($scope.$eval(expr)) {
                        ++count;
                    }
                });
                return count;

            }, function (newVal) {
                $scope.errorCount = newVal;
            });

        },
        link: function (scope, element, attr, formController, transcludeFn) {
            scope.$form = formController;

            transcludeFn(scope, function (clone) {
                var badge = element.find('.label');
                var tooltip = angular.element('<div class="validationMessageTemplate tooltip-danger" />');
                tooltip.append(clone);
                element.append(tooltip);
                $timeout(function () {
                    scope.$field = formController[attr.target];
                    badge.tooltip({
                        placement: 'right',
                        html: true,
                        title: clone
                    });

                });
            });
        }
    }
});

Директива о проверке сообщений

Директива validationMessage отслеживает сообщения проверки, отображаемые в подсказке. Он использует ng-if для определения выражения для оценки. Если в элементе нет ng-if, выражение просто оценивается как true (всегда показано).

app.directive('validationMessage', function () {
    return {
        restrict: 'A',
        priority: 1000,
        require: '^validationTooltip',
        link: function (scope, element, attr, ctrl) {
            ctrl.$addExpression(attr.ngIf || true );
        }
    }
});

Использование в HTML

  • Добавить форму с атрибутом name
  • Добавьте одно или несколько полей формы - каждый с атрибутом имени и директивой ng-model.
  • Объявить элемент <validation-tooltip> с атрибутом target, относящимся к имени одного из полей формы.
  • Примените директиву validation-message к каждому сообщению с необязательным выражением привязки ng-if.
<div ng-class="{'form-group': true, 'has-error':form.number.$invalid}">
    <div class="row">
        <div class="col-md-4">
            <label for="number">Number</label>
            <validation-tooltip target="number">
                <ul class="list-unstyled">
                    <li validation-message ng-if="$field.$error.required">this field is required </li>
                    <li validation-message ng-if="$field.$error.number">should be number</li>
                    <li validation-message ng-if="$field.$error.min">minimum - 5</li>
                    <li validation-message ng-if="$field.$error.max">miximum - 20</li>
                </ul>
            </validation-tooltip>
        </div>
    </div>
    <div class="row">
        <div class="col-md-4">
            <input type="number" min="5" max="20" ng-model="number" name="number" class="form-control" required />
        </div>
    </div>
</div>

Ответ 2

@pixelbits ответ велик. Вместо этого я использовал это:

  <div class="form-group" ng-class="{ 'has-error': form.name.$dirty && form.name.$invalid }">
    <label for="name" class="col-sm-4 control-label">What your name?</label>
    <div class="col-sm-6">
      <input class="form-control has-feedback" id="name" name="name" 
        required
        ng-minlength="4"
        ng-model="formData.name"
        tooltip="{{form.name.$valid ? '' : 'How clients see your name.  Min 4 chars.'}}"  tooltip-trigger="focus" 
        tooltip-placement="below">
      <span class="glyphicon glyphicon-ok-sign text-success form-control-feedback" aria-hidden="true"
        ng-show="form.name.$valid"></span>
    </div>
  </div>

Этот метод является подсказкой ui-bootstrap и устанавливает текст всплывающей подсказки на "", когда он действителен.

http://jsbin.com/ditekuvipa/2/edit

Ответ 3

Отличный ответ от @pixelbits. Я использовал его директивы и слегка изменил их, чтобы всплывающая подсказка отображалась над фактическим вводом, как это требовалось некоторым пользователям.

angular.module('app')
    .directive('validationTooltip', ['$timeout', function ($timeout) {

    function toggleTooltip(scope) {
        if (!scope.tooltipInstance) {
            return;
        }

        $timeout(function() {
            if (scope.errorCount > 0 && (scope.showWhen == undefined || scope.showWhen())) {
                scope.tooltipInstance.enable();
                scope.tooltipInstance.show();
            } else {
                scope.tooltipInstance.disable();
                scope.tooltipInstance.hide();
            }
        });
    }

    return {
        restrict: 'E',
        transclude: true,
        require: '^form',
        scope: {
            showWhen: '&',
            placement: '@',
        },
        template: '<div></div>',
        controller: ['$scope', function ($scope) {
            var expressions = [];
            $scope.errorCount = 0;
            this.$addExpression = function (expr) {
                expressions.push(expr);
            }
            $scope.$watch(function () {
                var count = 0;
                angular.forEach(expressions, function (expr) {
                    if ($scope.$eval(expr)) {
                        ++count;
                    }
                });
                return count;

            }, function (newVal) {
                $scope.errorCount = newVal;

                toggleTooltip($scope);
            });

        }],
        link: function (scope, element, attr, formController, transcludeFn) {
            scope.$form = formController;

            transcludeFn(scope, function (clone) {

                var tooltip = angular.element('<div class="validationMessageTemplate" style="display: none;"/>');
                tooltip.append(clone);
                element.append(tooltip);
                $timeout(function () {
                    scope.$field = formController[attr.target];

                    var targetElm = $('[name=' + attr.target + ']');
                    targetElm.tooltip({
                        placement: scope.placement != null ? scope.placement : 'bottom',
                        html: true,
                        title: clone,
                    });

                    scope.tooltipInstance = targetElm.data('bs.tooltip');
                    toggleTooltip(scope);

                    if (scope.showWhen) {
                        scope.$watch(scope.showWhen, function () {
                            toggleTooltip(scope);
                        });
                    }
                });
            });
        }
    }
}]);

Основное изменение заключается в том, что директива использует jQuery для поиска целевого элемента (который должен быть вводом) с помощью атрибута name и инициализирует всплывающую подсказку для этого элемента, а не элемент директивы. Я также добавил свойство showWhen в область видимости, поскольку вы не всегда можете, чтобы ваша подсказка отображалась, когда вход недействителен (см. Пример ниже).

Директива validationMessage не изменяется

angular.module('app').directive('validationMessage', function () {
    return {
        restrict: 'A',
        priority: 1000,
        require: '^validationTooltip',
        link: function (scope, element, attr, ctrl) {
            ctrl.$addExpression(attr.ngIf || true);
        }
    }
});

Использование в Html также похоже, с добавлением showWhen, если вы хотите:

<div class="form-group" ng-class="{ 'has-error' : aForm.note.$invalid && (aForm.note.$dirty) }">
    <label class="col-md-3 control-label">Note</label>
    <div class="col-md-15">
        <textarea
            name="note"
            class="form-control"
            data-ng-model="foo.Note"
            ng-required="bar.NoteRequired"></textarea>
        <validation-tooltip target="note" show-when="aForm.note.$invalid && (aForm.note.$dirty)">
            <ul class="validation-list">
                <li validation-message ng-if="$field.$error.required">Note required</li>
            </ul>
        </validation-tooltip>
    </div>
</div>

Ответ 4

вы можете просто использовать свойство всплывающей подсказки:

<div class="showtooltip" tooltip-placement="left" tooltip-enable="$isValid" tooltip="tooltip message"></div>

Ответ 5

Моя цель состояла в том, чтобы использовать как ng-сообщения, так и ui-bootstrap popover для обратной связи с проверкой. Я предпочитаю popover vs. tooltip, поскольку он более четко отображает стили справки.

Здесь код:

<!-- Routing Number -->
<div class="form-group-sm" ng-class="{ 'has-error' : form.routingNumber.$invalid && !form.routingNumber.$pristine }">
    <label class="control-label col-sm-4" for="routing-number">Routing #</label>
    <div class="col-sm-8">
        <input class="form-control input-sm text-box"
            id="routing-number"
            name="routingNumber"
            ng-model="entity.ROUTINGNUM"                        
            popover-class="help-block"
            popover-is-open="form.routingNumber.$invalid"
            popover-trigger="none"
            required
            uib-popover-template="'routing-number-validators'"
            string-to-number
            type="number" />
    </div>                
    <!-- Validators -->
    <script type="text/ng-template" id="routing-number-validators">
        <div ng-messages="form.routingNumber.$error">
            <div ng-messages-include="/app/modules/_core/views/validationMessages.html"></div>
        </div>
    </script>
</div>

Вот пример validationMessages.html

<span ng-message="required">Required</span>
<span ng-message="max">Too high</span>
<span ng-message="min">Too low</span>
<span ng-message="minlength">Too short</span>
<span ng-message="maxlength">Too long</span>
<span ng-message="email">Invalid email</span>

Примечание. Мне нужно было перейти на jQuery 2.1.4, чтобы получить директиву uib-popover-template.

Зависимости: