reactivos - ¿Cómo se muestran los errores de entrada de formularios usando la información sobre herramientas de Bootstrap de UI de AngularJS?
validar formulario angular 4 (5)
Por ejemplo, tengo el formulario donde estoy mostrando errores de entrada de formulario .
Necesito mostrar la insignia roja (con ''hover para mostrar los errores'') cerca de la etiqueta de entrada si hay algunos errores. Si el usuario desplaza el cursor sobre esta insignia roja, verá la lista de errores usando la información sobre herramientas de la UI de Bootstrap de AngularJS . No quiero poner la lista de errores en el atributo tooltip-html-unsafe, porque no es conveniente editar y mantener.
Este código es más declarativo:
<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>
que este código:
<span tooltip-html-unsafe="{{<ul><li>This field is required;</li><li>...</li></ul>}}">hover to show errors</span>
¿Cómo puedo escribir una directiva de información de validación usando la información sobre herramientas de Bootstrap de UI de AngularJS?
¿O tal vez puede sugerir otro enfoque para mantener los mensajes de error de validación?
en realidad solo puede usar la propiedad enable tooltip:
<div class="showtooltip" tooltip-placement="left" tooltip-enable="$isValid" tooltip="tooltip message"></div>
Excelente respuesta de @pixelbits. Usé sus directivas y las modifiqué ligeramente para permitir que la información sobre herramientas se muestre sobre la entrada real como lo solicitaron algunos usuarios.
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);
});
}
});
});
}
}
}]);
El principal cambio es que la directiva utiliza jQuery para encontrar el elemento de destino (que debe ser una entrada) mediante el atributo de name
, e inicializa la información sobre herramientas en ese elemento en lugar del elemento de la directiva. También agregué una propiedad showWhen
al alcance, ya que es posible que no siempre desee que su información sobre herramientas aparezca cuando la entrada no es válida (vea el ejemplo a continuación).
La directiva validationMessage no ha cambiado
angular.module(''app'').directive(''validationMessage'', function () {
return {
restrict: ''A'',
priority: 1000,
require: ''^validationTooltip'',
link: function (scope, element, attr, ctrl) {
ctrl.$addExpression(attr.ngIf || true);
}
}
});
El uso en Html también es similar, con solo agregar showWhen
cuando lo desee:
<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>
Directiva de validación de información sobre herramientas
ValidationTooltip es la directiva principal. Tiene las siguientes responsabilidades:
- Definir la plantilla de punta de herramienta a través de su contenido transcluido
- Mantenga un registro de las expresiones de validación para que puedan ser evaluadas con cada ciclo de resumen.
- Exponer una API de controlador para permitir que las directivas de valiationMessage se registren
- Proporcione un atributo ''objetivo'' en la directiva para especificar a qué campo de formulario se vinculará la insignia (y la información sobre herramientas asociada)
Notas adicionales
La plantilla de información sobre herramientas utiliza la función de transclusión de la función de enlace para vincular la plantilla al alcance de la directiva. Hay dos propiedades que están dentro del alcance al que se puede vincular la plantilla:
- $ form : Vinculado al modelo de formulario definido en el alcance principal. es decir $ scope.myForm
- $ field : Vinculado al modelo form.name en el alcance principal. es decir $ scope.myForm.myInput
Esto permite que la plantilla se vincule a propiedades de validación como $ valid, $ invalid, $ pristine, $ dirty y $ error sin hacer referencia directamente al nombre del formulario o al nombre del campo de entrada. Por ejemplo, todas las siguientes expresiones son expresiones de enlace válidas:
$ propiedades de formulario:
- `$ form. $ valid`
- `$ form. $ invalid`
- `$ form. $ dirty`
- `$ form. $ pristine`
- `$ form. $ error.required` etc ...
$ propiedades de campo:
- `$ campo. $ válido`
- `$ campo. $ inválido`
- `$ campo. $ sucio`
- `$ campo. $ prístino`
- `$ field. $ error.required` etc ...
Implementación Directiva
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
});
});
});
}
}
});
Directiva de mensajes de validación
La directiva validationMessage realiza un seguimiento de los mensajes de validación para mostrar en la información sobre herramientas. Utiliza ng-if
para definir la expresión para evaluar. Si no se encuentra ng-if
en el elemento, entonces la expresión simplemente se evalúa como verdadera (siempre se muestra).
app.directive(''validationMessage'', function () {
return {
restrict: ''A'',
priority: 1000,
require: ''^validationTooltip'',
link: function (scope, element, attr, ctrl) {
ctrl.$addExpression(attr.ngIf || true );
}
}
});
Uso en HTML
- Agregue un formulario con un atributo de nombre
- Agregue uno o más campos de formulario, cada uno con un atributo de nombre y una directiva ng-model.
- Declare un elemento
<validation-tooltip>
con un atributo detarget
referencia al nombre de uno de los campos del formulario.- Aplique la directiva de
validation-message
a cada mensaje con una expresión de enlaceng-if
opcional.
<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>
La respuesta de @pixelbits es genial. Usé esto en su lugar:
<div class="form-group" ng-class="{ ''has-error'': form.name.$dirty && form.name.$invalid }">
<label for="name" class="col-sm-4 control-label">What''s 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>
La técnica es la información sobre herramientas de ui-bootstrap y establece el texto de la información sobre herramientas en '''' cuando sea válido.
Mi objetivo era aprovechar los mensajes ng y ui-bootstrap popover para obtener comentarios de validación. Prefiero el popover versus la información sobre herramientas, ya que muestra los estilos de bloque de ayuda más claramente.
Aquí está el código:
<!-- 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>
Aquí está el 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>
Nota: tuve que actualizar a jQuery 2.1.4 para que funcione la directiva uib-popover-template.
Dependencias: