J'ai un formulaire qui est câblé dans angular, l'utilisant pour la validation. Je suis capable d'afficher des messages d'erreur en utilisant les directives ng-show comme ceci:
<span ng-show="t3.f.needsAttention(f.fieldName)" ng-cloak>
<span ng-show="f.fieldName.$error.required && !f.fieldName.$viewValue">
This field is required.
</span>
</span>
.. où f
est le formulaire et t3
provient d'une directive personnalisée du formulaire, qui détecte si une soumission a été tentée et contient des fonctions permettant de vérifier la validité des champs.
Ce que je cherche à faire est d’afficher des messages de validation dans un popover. Popover natif de bootstrap, ou le popover de I Bootstrap , je les ai tous les deux chargés. Je peux aussi envisager AngularStrap s'il est plus facile de le faire en utilisant cette bibliothèque.
Ce qui me pose problème à l’heure actuelle, c’est la nature des popovers en général - ils affichent automatiquement l’affichage en fonction d’événements tels que les clics, le mouseenter, le flou, etc. fonctions dans les attributs ng-show ci-dessus. Ainsi, lorsque l'expression renvoie false, masquez-la et, lorsqu'elle renvoie true, affichez-la.
Je sais que bootstrap a le .popover ('show') pour cela, mais je ne suis pas supposé dire à angular rien à propos du dom, alors je ' Je ne sais pas comment j'aurais accès à $ (élément) .popover () si je le faisais avec une fonction de contrôleur de formulaire personnalisée.
Mettre à jour
La solution mentionnée dans le vote en double ne montre toujours que le popover sur mouseenter. Je veux le forcer à s'afficher, comme si je faisais $('#popover_id').popover('show')
.
En fait, il n’est pas très difficile de décorer l’info-bulle ui-bootstrap ou le popover avec une directive personnalisée. Ceci est écrit en TypeScript, mais les parties javascript devraient être évidentes. Ce code unique décore une info-bulle ou un popover:
'use strict';
module App.Directives.TooltipToggle {
export interface DirectiveSettings {
directiveName: string;
directive: any[];
directiveConfig?: any[];
}
export function directiveSettings(tooltipOrPopover = 'tooltip'): DirectiveSettings {
var directiveName = tooltipOrPopover;
// events to handle show & hide of the tooltip or popover
var showEvent = 'show-' + directiveName;
var hideEvent = 'hide-' + directiveName;
// set up custom triggers
var directiveConfig = ['$tooltipProvider', ($tooltipProvider: ng.ui.bootstrap.ITooltipProvider): void => {
var trigger = {};
trigger[showEvent] = hideEvent;
$tooltipProvider.setTriggers(trigger);
}];
var directiveFactory = (): any[] => {
return ['$timeout', ($timeout: ng.ITimeoutService): ng.IDirective => {
var d: ng.IDirective = {
name: directiveName,
restrict: 'A',
link: (scope: ng.IScope, element: JQuery, attr: ng.IAttributes) => {
if (angular.isUndefined(attr[directiveName + 'Toggle'])) return;
// set the trigger to the custom show trigger
attr[directiveName + 'Trigger'] = showEvent;
// redraw the popover when responsive UI moves its source
var redrawPromise: ng.IPromise<void>;
$(window).on('resize', (): void => {
if (redrawPromise) $timeout.cancel(redrawPromise);
redrawPromise = $timeout((): void => {
if (!scope['tt_isOpen']) return;
element.triggerHandler(hideEvent);
element.triggerHandler(showEvent);
}, 100);
});
scope.$watch(attr[directiveName + 'Toggle'], (value: boolean): void => {
if (value && !scope['tt_isOpen']) {
// tooltip provider will call scope.$apply, so need to get out of this digest cycle first
$timeout((): void => {
element.triggerHandler(showEvent);
});
}
else if (!value && scope['tt_isOpen']) {
$timeout((): void => {
element.triggerHandler(hideEvent);
});
}
});
}
};
return d;
}];
};
var directive = directiveFactory();
var directiveSettings: DirectiveSettings = {
directiveName: directiveName,
directive: directive,
directiveConfig: directiveConfig,
};
return directiveSettings;
}
}
Avec ce morceau de code unique, vous pouvez configurer le masquage et l’affichage programmés d’une info-bulle ou d’un popover de la manière suivante:
var tooltipToggle = App.Directives.TooltipToggle.directiveSettings();
var popoverToggle = App.Directives.TooltipToggle.directiveSettings('popover');
var myModule = angular.module('my-mod', ['ui.bootstrap.popover', 'ui.bootstrap.tpls'])
.directive(tooltipToggle.directiveName, tooltipToggle.directive)
.config(tooltipToggle.directiveConfig)
.directive(popoverToggle.directiveName, popoverToggle.directive)
.config(popoverToggle.directiveConfig);
Usage:
<span tooltip="This field is required."
tooltip-toggle="formName.fieldName.$error.required"
tooltip-animation="false" tooltip-placement="right"></span>
ou
<span popover="This field is required."
popover-toggle="formName.fieldName.$error.required"
popover-animation="false" popover-placement="right"></span>
Nous réutilisons donc tout ce qui vient avec l'infobulle ui-bootstrap ou popover, et implémentons uniquement le -toggle
attribut. La directive décorative surveille cet attribut et déclenche des événements personnalisés à afficher ou à masquer, qui sont ensuite gérés par le fournisseur d'info-bulle ui-bootstrap.
Mise à jour:
Puisque cette réponse semble aider les autres, voici le code écrit en javascript (le typeScript ci-dessus se compile plus ou moins en javascript):
'use strict';
function directiveSettings(tooltipOrPopover) {
if (typeof tooltipOrPopover === "undefined") {
tooltipOrPopover = 'tooltip';
}
var directiveName = tooltipOrPopover;
// events to handle show & hide of the tooltip or popover
var showEvent = 'show-' + directiveName;
var hideEvent = 'hide-' + directiveName;
// set up custom triggers
var directiveConfig = ['$tooltipProvider', function ($tooltipProvider) {
var trigger = {};
trigger[showEvent] = hideEvent;
$tooltipProvider.setTriggers(trigger);
}];
var directiveFactory = function() {
return ['$timeout', function($timeout) {
var d = {
name: directiveName,
restrict: 'A',
link: function(scope, element, attr) {
if (angular.isUndefined(attr[directiveName + 'Toggle']))
return;
// set the trigger to the custom show trigger
attr[directiveName + 'Trigger'] = showEvent;
// redraw the popover when responsive UI moves its source
var redrawPromise;
$(window).on('resize', function() {
if (redrawPromise) $timeout.cancel(redrawPromise);
redrawPromise = $timeout(function() {
if (!scope['tt_isOpen']) return;
element.triggerHandler(hideEvent);
element.triggerHandler(showEvent);
}, 100);
});
scope.$watch(attr[directiveName + 'Toggle'], function(value) {
if (value && !scope['tt_isOpen']) {
// tooltip provider will call scope.$apply, so need to get out of this digest cycle first
$timeout(function() {
element.triggerHandler(showEvent);
});
}
else if (!value && scope['tt_isOpen']) {
$timeout(function() {
element.triggerHandler(hideEvent);
});
}
});
}
};
return d;
}];
};
var directive = directiveFactory();
var directiveSettings = {
directiveName: directiveName,
directive: directive,
directiveConfig: directiveConfig,
};
return directiveSettings;
}
Vous pouvez également créer vos propres déclencheurs étendus. Cela s'appliquera à la fois à l'infobulle et au popover.
Tout d'abord, étendez les déclencheurs de l'info-bulle comme suit:
// define additional triggers on Tooltip and Popover
app.config(['$tooltipProvider', function($tooltipProvider){
$tooltipProvider.setTriggers({
'show': 'hide'
});
}]);
Définissez ensuite le déclencheur sur la balise HTML comme suit:
<div id="RegisterHelp" popover-trigger="show" popover-placement="left" popover="{{ 'Login or register here'}}">
Et maintenant, vous pouvez appeler masquer et afficher à partir de JavaScript. Il s'agit d'un spectacle en 3 secondes.
$("#RegisterHelp").trigger('show');
//Close the info again
$timeout(function () {
$("#RegisterHelp").trigger('hide');
}, 3000);
ui.bootstrap
0.13.4 et plus récent:Un nouveau paramètre (popover-is-open
) a été introduit pour contrôler les popovers dans le jeu officiel ui.bootstrap
repo. Voici comment vous l'utilisez dans la dernière version:
<a uib-popover="Hello world!" popover-is-open="isOpen" ng-click="isOpen = !isOpen">
Click me to show the popover!
</a>
ui.bootstrap
0.13.3 et plus ancien:Je viens de publier une petite directive qui ajoute plus de contrôle sur les popovers sur GitHub:
https://github.com/Elijen/angular-popover-toggle
Vous pouvez utiliser une variable d’étendue pour afficher/masquer la popover à l’aide de popover-toggle="variable"
directive comme ceci:
<span popover="Hello world!" popover-toggle="isOpen">
Popover here
</span>
Voici une démo de Plunkr:
http://plnkr.co/edit/QeQqqEJAu1dCuDtSvomD?p=preview
À partir de la version 0.13.4, nous avons ajouté la possibilité d'ouvrir et de fermer par programmation des popovers via le *-is-open
attribut sur les info-bulles et les popovers dans la bibliothèque Angular UI Bootstrap. Il n’ya donc plus de raison de lancer votre propre code/solution) .
Mon approche:
L'idée étant de laisser la manipulation du DOM aux directives.
J'ai monté un violon qui, je l'espère, donne une meilleure explication, mais vous trouverez des solutions beaucoup plus sophistiquées dans l'interface utilisateur Bootstrap dont vous avez parlé.
Balisage:
<div ng-repeat="element in elements" class="element">
<!-- Only want to show a popup if the element has an error and is being hovered -->
<div class="popover" ng-show="element.hovered && element.error" ng-style>Popover</div>
<div class="popoverable" ng-mouseEnter="popoverShow(element)" ng-mouseLeave="popoverHide(element)">
{{ element.name }}
</div>
</div>
JS:
function DemoCtrl($scope)
{
$scope.elements = [
{name: 'Element1 (Error)', error: true, hovered: false},
{name: 'Element2 (no error)', error: false, hovered: false},
{name: 'Element3 (Error)', error: true, hovered: false},
{name: 'Element4 (no error)', error: false, hovered: false},
{name: 'Element5 (Error)', error: true, hovered: false},
];
$scope.popoverShow = function(element)
{
element.hovered = true;
}
$scope.popoverHide = function(element)
{
element.hovered = false
}
}
D'après la réponse de Michael Stramel, mais avec une solution angularJS complète:
// define additional triggers on Tooltip and Popover
app.config(['$tooltipProvider', function($tooltipProvider){
$tooltipProvider.setTriggers({
'show': 'hide'
});
}])
Ajoutez maintenant cette directive:
app.directive('ntTriggerIf', ['$timeout',
function ($timeout) {
/*
Intended use:
<div nt-trigger-if={ 'triggerName':{{someCodition === SomeValue}},'anotherTriggerName':{{someOtherCodition === someOtherValue}} } ></div>
*/
return {
restrict: 'A',
link: function (scope, element, attrs) {
attrs.$observe('ntTriggerIf', function (val) {
try {
var ob_options = JSON.parse(attrs.ntTriggerIf.split("'").join('"') || "");
}
catch (e) {
return
}
$timeout(function () {
for (var st_name in ob_options) {
var condition = ob_options[st_name];
if (condition) {
element.trigger(st_name);
}
}
})
})
}
}
}])
Puis dans votre balisage:
<span tooltip-trigger="show" tooltip="Login or register here" nt-trigger-if="{'show':{{ (errorConidtion) }}, 'hide':{{ !(errorConidtion) }} }"></span>