@@ -18,7 +18,7 @@ var jqLite;
18
18
* sequencing based on the order of how the messages are defined in the template.
19
19
*
20
20
* Currently, the ngMessages module only contains the code for the `ngMessages`, `ngMessagesInclude`
21
- * `ngMessage` and `ngMessageExp ` directives.
21
+ * `ngMessage`, `ngMessageExp` and `ngMessageDefault ` directives.
22
22
*
23
23
* ## Usage
24
24
* The `ngMessages` directive allows keys in a key/value collection to be associated with a child element
@@ -257,7 +257,21 @@ var jqLite;
257
257
* .some-message.ng-leave.ng-leave-active {}
258
258
* ```
259
259
*
260
- * {@link ngAnimate Click here} to learn how to use JavaScript animations or to learn more about ngAnimate.
260
+ * {@link ngAnimate See the ngAnimate docs} to learn how to use JavaScript animations or to learn
261
+ * more about ngAnimate.
262
+ *
263
+ * ## Displaying a default message
264
+ * If the ngMessages renders no inner ngMessage directive (that is to say when the key values does not
265
+ * match the attribute value present on each ngMessage directive), then it will render a default message
266
+ * using the {@link ngMessageDefault} directive.
267
+ *
268
+ * ```html
269
+ * <div ng-messages="myForm.myField.$error" role="alert">
270
+ * <div ng-message="required">This field is required</div>
271
+ * <div ng-message="minlength">This field is too short</div>
272
+ * <div ng-message-default>This field has an input error</div>
273
+ * </div>
274
+ * ```
261
275
*/
262
276
angular . module ( 'ngMessages' , [ ] , function initAngularHelpers ( ) {
263
277
// Access helpers from AngularJS core.
@@ -286,8 +300,11 @@ angular.module('ngMessages', [], function initAngularHelpers() {
286
300
* at a time and this depends on the prioritization of the messages within the template. (This can
287
301
* be changed by using the `ng-messages-multiple` or `multiple` attribute on the directive container.)
288
302
*
289
- * A remote template can also be used to promote message reusability and messages can also be
290
- * overridden.
303
+ * A remote template can also be used (With {@link ngMessagesInclude}) to promote message
304
+ * reusability and messages can also be overridden.
305
+ *
306
+ * A default message can also be displayed when no `ngMessage` directive is inserted, using the
307
+ * {@link ngMessageDefault} directive.
291
308
*
292
309
* {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
293
310
*
@@ -298,13 +315,15 @@ angular.module('ngMessages', [], function initAngularHelpers() {
298
315
* <ANY ng-message="stringValue">...</ANY>
299
316
* <ANY ng-message="stringValue1, stringValue2, ...">...</ANY>
300
317
* <ANY ng-message-exp="expressionValue">...</ANY>
318
+ * <ANY ng-message-default>...</ANY>
301
319
* </ANY>
302
320
*
303
321
* <!-- or by using element directives -->
304
322
* <ng-messages for="expression" role="alert">
305
323
* <ng-message when="stringValue">...</ng-message>
306
324
* <ng-message when="stringValue1, stringValue2, ...">...</ng-message>
307
325
* <ng-message when-exp="expressionValue">...</ng-message>
326
+ * <ng-message-default>...</ng-message-default>
308
327
* </ng-messages>
309
328
* ```
310
329
*
@@ -333,6 +352,7 @@ angular.module('ngMessages', [], function initAngularHelpers() {
333
352
* <div ng-message="required">You did not enter a field</div>
334
353
* <div ng-message="minlength">Your field is too short</div>
335
354
* <div ng-message="maxlength">Your field is too long</div>
355
+ * <div ng-message-default>This field has an input error</div>
336
356
* </div>
337
357
* </form>
338
358
* </file>
@@ -409,8 +429,15 @@ angular.module('ngMessages', [], function initAngularHelpers() {
409
429
} ) ;
410
430
411
431
if ( unmatchedMessages . length !== totalMessages ) {
432
+ // Unset default message if set
433
+ if ( ctrl . default ) ctrl . default . detach ( ) ;
434
+
412
435
$animate . setClass ( $element , ACTIVE_CLASS , INACTIVE_CLASS ) ;
413
436
} else {
437
+
438
+ // Set default message if no other matched
439
+ if ( ctrl . default ) ctrl . default . attach ( ) ;
440
+
414
441
$animate . setClass ( $element , INACTIVE_CLASS , ACTIVE_CLASS ) ;
415
442
}
416
443
} ;
@@ -428,23 +455,31 @@ angular.module('ngMessages', [], function initAngularHelpers() {
428
455
}
429
456
} ;
430
457
431
- this . register = function ( comment , messageCtrl ) {
432
- var nextKey = latestKey . toString ( ) ;
433
- messages [ nextKey ] = {
434
- message : messageCtrl
435
- } ;
436
- insertMessageNode ( $element [ 0 ] , comment , nextKey ) ;
437
- comment . $$ngMessageNode = nextKey ;
438
- latestKey ++ ;
458
+ this . register = function ( comment , messageCtrl , isDefault ) {
459
+ if ( isDefault ) {
460
+ ctrl . default = messageCtrl ;
461
+ } else {
462
+ var nextKey = latestKey . toString ( ) ;
463
+ messages [ nextKey ] = {
464
+ message : messageCtrl
465
+ } ;
466
+ insertMessageNode ( $element [ 0 ] , comment , nextKey ) ;
467
+ comment . $$ngMessageNode = nextKey ;
468
+ latestKey ++ ;
469
+ }
439
470
440
471
ctrl . reRender ( ) ;
441
472
} ;
442
473
443
- this . deregister = function ( comment ) {
444
- var key = comment . $$ngMessageNode ;
445
- delete comment . $$ngMessageNode ;
446
- removeMessageNode ( $element [ 0 ] , comment , key ) ;
447
- delete messages [ key ] ;
474
+ this . deregister = function ( comment , isDefault ) {
475
+ if ( isDefault ) {
476
+ delete ctrl . default ;
477
+ } else {
478
+ var key = comment . $$ngMessageNode ;
479
+ delete comment . $$ngMessageNode ;
480
+ removeMessageNode ( $element [ 0 ] , comment , key ) ;
481
+ delete messages [ key ] ;
482
+ }
448
483
ctrl . reRender ( ) ;
449
484
} ;
450
485
@@ -647,9 +682,41 @@ angular.module('ngMessages', [], function initAngularHelpers() {
647
682
*
648
683
* @param {expression } ngMessageExp|whenExp an expression value corresponding to the message key.
649
684
*/
650
- . directive ( 'ngMessageExp' , ngMessageDirectiveFactory ( ) ) ;
685
+ . directive ( 'ngMessageExp' , ngMessageDirectiveFactory ( ) )
686
+
687
+ /**
688
+ * @ngdoc directive
689
+ * @name ngMessageDefault
690
+ * @restrict AE
691
+ * @scope
692
+ *
693
+ * @description
694
+ * `ngMessageDefault` is a directive with the purpose to show and hide a default message for
695
+ * {@link ngMessages}, when none of provided messages matches.
696
+ *
697
+ * More information about using `ngMessageDefault` can be found in the
698
+ * {@link module:ngMessages `ngMessages` module documentation}.
699
+ *
700
+ * @usage
701
+ * ```html
702
+ * <!-- using attribute directives -->
703
+ * <ANY ng-messages="expression" role="alert">
704
+ * <ANY ng-message="stringValue">...</ANY>
705
+ * <ANY ng-message="stringValue1, stringValue2, ...">...</ANY>
706
+ * <ANY ng-message-default>...</ANY>
707
+ * </ANY>
708
+ *
709
+ * <!-- or by using element directives -->
710
+ * <ng-messages for="expression" role="alert">
711
+ * <ng-message when="stringValue">...</ng-message>
712
+ * <ng-message when="stringValue1, stringValue2, ...">...</ng-message>
713
+ * <ng-message-default>...</ng-message-default>
714
+ * </ng-messages>
715
+ *
716
+ */
717
+ . directive ( 'ngMessageDefault' , ngMessageDirectiveFactory ( true ) ) ;
651
718
652
- function ngMessageDirectiveFactory ( ) {
719
+ function ngMessageDirectiveFactory ( isDefault ) {
653
720
return [ '$animate' , function ( $animate ) {
654
721
return {
655
722
restrict : 'AE' ,
@@ -658,25 +725,28 @@ function ngMessageDirectiveFactory() {
658
725
terminal : true ,
659
726
require : '^^ngMessages' ,
660
727
link : function ( scope , element , attrs , ngMessagesCtrl , $transclude ) {
661
- var commentNode = element [ 0 ] ;
662
-
663
- var records ;
664
- var staticExp = attrs . ngMessage || attrs . when ;
665
- var dynamicExp = attrs . ngMessageExp || attrs . whenExp ;
666
- var assignRecords = function ( items ) {
667
- records = items
668
- ? ( isArray ( items )
669
- ? items
670
- : items . split ( / [ \s , ] + / ) )
671
- : null ;
672
- ngMessagesCtrl . reRender ( ) ;
673
- } ;
728
+ var commentNode , records , staticExp , dynamicExp ;
729
+
730
+ if ( ! isDefault ) {
731
+ commentNode = element [ 0 ] ;
732
+ staticExp = attrs . ngMessage || attrs . when ;
733
+ dynamicExp = attrs . ngMessageExp || attrs . whenExp ;
734
+
735
+ var assignRecords = function ( items ) {
736
+ records = items
737
+ ? ( isArray ( items )
738
+ ? items
739
+ : items . split ( / [ \s , ] + / ) )
740
+ : null ;
741
+ ngMessagesCtrl . reRender ( ) ;
742
+ } ;
674
743
675
- if ( dynamicExp ) {
676
- assignRecords ( scope . $eval ( dynamicExp ) ) ;
677
- scope . $watchCollection ( dynamicExp , assignRecords ) ;
678
- } else {
679
- assignRecords ( staticExp ) ;
744
+ if ( dynamicExp ) {
745
+ assignRecords ( scope . $eval ( dynamicExp ) ) ;
746
+ scope . $watchCollection ( dynamicExp , assignRecords ) ;
747
+ } else {
748
+ assignRecords ( staticExp ) ;
749
+ }
680
750
}
681
751
682
752
var currentElement , messageCtrl ;
@@ -701,7 +771,7 @@ function ngMessageDirectiveFactory() {
701
771
// If the message element was removed via a call to `detach` then `currentElement` will be null
702
772
// So this handler only handles cases where something else removed the message element.
703
773
if ( currentElement && currentElement . $$attachId === $$attachId ) {
704
- ngMessagesCtrl . deregister ( commentNode ) ;
774
+ ngMessagesCtrl . deregister ( commentNode , isDefault ) ;
705
775
messageCtrl . detach ( ) ;
706
776
}
707
777
newScope . $destroy ( ) ;
@@ -716,14 +786,14 @@ function ngMessageDirectiveFactory() {
716
786
$animate . leave ( elm ) ;
717
787
}
718
788
}
719
- } ) ;
789
+ } , isDefault ) ;
720
790
721
791
// We need to ensure that this directive deregisters itself when it no longer exists
722
792
// Normally this is done when the attached element is destroyed; but if this directive
723
793
// gets removed before we attach the message to the DOM there is nothing to watch
724
794
// in which case we must deregister when the containing scope is destroyed.
725
795
scope . $on ( '$destroy' , function ( ) {
726
- ngMessagesCtrl . deregister ( commentNode ) ;
796
+ ngMessagesCtrl . deregister ( commentNode , isDefault ) ;
727
797
} ) ;
728
798
}
729
799
} ;
0 commit comments