Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Commit

Permalink
fix(input): ngMessages jump with ngShow, ngIf, etc
Browse files Browse the repository at this point in the history
When the ngMessages directive was used with the ngShow,
ngIf and other directives inside of an md-input-container,
the messages would flicker and jump rather than properly
animating.

Additionally, if the messages spanned multiple lines,
the animations were incorrect due to hard-coded values.

Fix many styles and move animations into JS so we can
properly calculate message heights.

Also, add more flexibility with the `md-auto-hide` CSS
class and associated attribute and update docs/demo
accordingly.

BREAKING CHANGE

By default, the `<md-input-container>` now automatically
hides any error messages until the component is in an
error state (determined by `md-is-error`). If you wish
to achieve the original behavior where messages are
always visible, add the `md-auto-hide="false"` attribute
to your `ng-messages` or use one of the following
visibility directives:

 - `ng-if`
 - `ng-show`/`ng-hide`
 - `ng-switch-when`/`ng-switch-default`

Fixes #5298.

Closes #6164
  • Loading branch information
topherfangio authored and jelbourn committed Dec 9, 2015
1 parent 6acd1c3 commit cf7f21a
Show file tree
Hide file tree
Showing 10 changed files with 575 additions and 136 deletions.
3 changes: 2 additions & 1 deletion src/components/input/demoErrors/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<md-content layout-padding>
<form name="projectForm">

<md-input-container class="md-block">
<label>Description</label>
<input md-maxlength="30" required name="description" ng-model="project.description">
Expand Down Expand Up @@ -36,7 +37,7 @@
<input required type="number" step="any" name="rate" ng-model="project.rate" min="800"
max="4999" ng-pattern="/^1234$/" md-maxlength="20" />

<div ng-messages="projectForm.rate.$error" multiple>
<div ng-messages="projectForm.rate.$error" multiple md-auto-hide="false">
<div ng-message="required">
You've got to charge something! You can't just <b>give away</b> a Missile Defense
System.
Expand Down
106 changes: 106 additions & 0 deletions src/components/input/demoErrorsAdvanced/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<div ng-controller="AppCtrl" layout="column" ng-cloak>

<md-content layout-padding>
<form name="userForm">
<div layout="row" layout-xs="column" layout-sm="column" layout-align="space-between center">
<div flex-gt-sm="80">
<p>
The <code>md-input-container</code> gives you the flexibility to display your messages
using many standard angular directives.
</p>

<p>
For instance, toggle the switch

<span hide-xs hide-sm>to the right</span>
<span hide-gt-sm>below</span>

to see the messages switch between some custom hints, and the actual error messages.
Note that some of the <code>ng-messages</code> containers use <code>ngIf</code> while
others use <code>ng-show</code> or <code>ng-hide</code>.
</p>
</div>

<md-input-container>
<md-switch ng-model="showHints">Showing {{showHints ? "Hints" : "Errors"}}</md-switch>
</md-input-container>
</div>

<div layout-gt-sm="row">

<md-input-container class="md-block" flex-gt-sm>
<label>Name</label>
<input md-maxlength="30" required name="name" ng-model="user.name" />

<div class="hint" ng-if="showHints">Tell us what we should call you!</div>

<div ng-messages="userForm.name.$error" ng-if="!showHints">
<div ng-message="required">Name is required.</div>
<div ng-message="md-maxlength">The name has to be less than 30 characters long.</div>
</div>
</md-input-container>

<div flex="5" hide-xs hide-sm>
<!-- Spacer //-->
</div>

<md-input-container class="md-block" flex-gt-sm>
<label>Social Security Number</label>
<input name="social" ng-model="user.social" ng-pattern="/^[0-9]{3}-[0-9]{2}-[0-9]{4}$/" />

<div class="hint" ng-if="showHints">###-##-####</div>

<div ng-messages="userForm.social.$error" ng-if="!showHints">
<div ng-message="pattern">###-##-#### - Please enter a valid SSN.</div>
</div>
</md-input-container>

</div>

<div layout-gt-sm="row">

<md-input-container class="md-block" flex-gt-sm>
<label>Email</label>
<input name="email" ng-model="user.email"
required minlength="10" maxlength="100" ng-pattern="/^.+@.+\..+$/" />

<div class="hint" ng-show="showHints">How can we reach you?</div>

<div ng-messages="userForm.email.$error" ng-hide="showHints">
<div ng-message-exp="['required', 'minlength', 'maxlength', 'pattern']">
Your email must be between 10 and 100 characters long and look like an e-mail address.
</div>
</div>
</md-input-container>

<div flex="5" hide-xs hide-sm>
<!-- Spacer //-->
</div>

<md-input-container class="md-block" flex-gt-sm>
<label>Phone Number</label>
<input name="phone" ng-model="user.phone" ng-pattern="/^([0-9]{3}) [0-9]{3}-[0-9]{4}$/" />

<div class="hint" ng-show="showHints">(###) ###-####</div>

<div ng-messages="userForm.phone.$error" ng-hide="showHints">
<div ng-message="pattern">(###) ###-#### - Please enter a valid phone number.</div>
</div>
</md-input-container>

<style>
/*
* The Material demos system does not currently allow targeting the body element, so this
* must go here in the HTML.
*/
body[dir=rtl] .hint {
right: 2px;
left: auto;
}
</style>
</div>

</form>
</md-content>

</div>
12 changes: 12 additions & 0 deletions src/components/input/demoErrorsAdvanced/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
angular.module('inputErrorsAdvancedApp', ['ngMaterial', 'ngMessages'])

.controller('AppCtrl', function($scope) {
$scope.showHints = true;

$scope.user = {
name: "",
email: "",
social: "123456789",
phone: "N/A"
};
});
31 changes: 31 additions & 0 deletions src/components/input/demoErrorsAdvanced/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.hint {
/* Position the hint */
position: absolute;
left: 2px;
right: auto;
bottom: 7px;

/* Copy styles from ng-messages */
font-size: 12px;
line-height: 14px;
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2);

/* Set our own color */
color: grey;
}

/* NOTE: Check the demo's HTML to see some additional RTL support CSS */

/* Setup animations similar to the ng-messages */
.hint.ng-hide,
.hint.ng-enter,
.hint.ng-leave.ng-leave-active {
bottom: 26px;
opacity: 0;
}

.hint.ng-leave,
.hint.ng-enter.ng-enter-active {
bottom: 7px;
opacity: 1;
}
6 changes: 2 additions & 4 deletions src/components/input/demoIcons/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,8 @@
<md-input-container class="md-icon-float md-icon-right md-block">
<label>Donation Amount</label>
<md-icon md-svg-src="img/icons/ic_card_giftcard_24px.svg"></md-icon>
<div layout="row">
<input ng-model="user.donation" type="number" step="0.01" flex>
<md-icon md-svg-src="img/icons/ic_euro_24px.svg" style="position: absolute; top: 4px;"></md-icon>
</div>
<input ng-model="user.donation" type="number" step="0.01">
<md-icon md-svg-src="img/icons/ic_euro_24px.svg"></md-icon>
</md-input-container>

</md-content>
Expand Down
9 changes: 9 additions & 0 deletions src/components/input/demoIcons/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,12 @@ md-input-container:not(.md-input-invalid) > md-icon.email { color: green; }
md-input-container:not(.md-input-invalid) > md-icon.name { color: dodgerblue; }
md-input-container.md-input-invalid > md-icon.email,
md-input-container.md-input-invalid > md-icon.name { color: red; }
/*
.right-icon {
position: absolute;
top: 4px;
right: 2px;
left: auto;
margin-top: 0;
}
*/
Loading

3 comments on commit cf7f21a

@kuhnroyal
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@topherfangio If there is an input-container with an active ngMessage and it is hidden and shown again with ng-if, the ngMessage is not visible but the ngModel is still invalid. It should show the ngMessage as it was before being hidden.

http://codepen.io/anon/pen/XXbXPV
Toggle show errors and then toggle the hidden switch.

@topherfangio
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kuhnroyal Am I correct in seeing that it works for the Name/SSN fields because they are using ng-if, but it fails for the Email/Phone fields because they are using ng-hide? Are you able to use ng-if in your code to work around it?

@kuhnroyal
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@topherfangio It seems that way. Hiding the name/email fileds with ng-show works:
http://codepen.io/anon/pen/PZqEaM

However that is not a solution for me, I am trying to dynamically hide parts of a form. If i just hide them with ng-show/hide they still get validated and submission fails.

Please sign in to comment.