Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

fix(form input): input["email"] and ngRequired not working together #7868

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/content/tutorial/step_04.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ __`test/e2e/scenarios.js`:__
"MOTOROLA XOOM\u2122"
]);

element(by.model('orderProp')).findElement(by.css('option[value="name"]')).click();
element(by.model('orderProp')).element(by.css('option[value="name"]')).click();

expect(getNames()).toEqual([
"MOTOROLA XOOM\u2122",
Expand Down
16 changes: 9 additions & 7 deletions src/Angular.js
Original file line number Diff line number Diff line change
Expand Up @@ -615,12 +615,14 @@ function makeMap(str) {
if (msie < 9) {
nodeName_ = function(element) {
element = element.nodeName ? element : element[0];
return (element.scopeName && element.scopeName != 'HTML')
? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
return lowercase(
(element.scopeName && element.scopeName != 'HTML')
? element.scopeName + ':' + element.nodeName : element.nodeName
);
};
} else {
nodeName_ = function(element) {
return element.nodeName ? element.nodeName : element[0].nodeName;
return lowercase(element.nodeName ? element.nodeName : element[0].nodeName);
};
}

Expand Down Expand Up @@ -683,10 +685,10 @@ function arrayRemove(array, value) {

function isLeafNode (node) {
if (node) {
switch (node.nodeName) {
case "OPTION":
case "PRE":
case "TITLE":
switch (nodeName_(node)) {
case "option":
case "pre":
case "title":
return true;
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/jqLite.js
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','),
});
var BOOLEAN_ELEMENTS = {};
forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
BOOLEAN_ELEMENTS[uppercase(value)] = true;
BOOLEAN_ELEMENTS[value] = true;
});
var ALIASED_ATTR = {
'ngMinlength' : 'minlength',
Expand All @@ -495,7 +495,7 @@ function getBooleanAttrName(element, name) {
var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];

// booleanAttr is here twice to minimize DOM access
return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
}

function getAliasedAttrName(element, name) {
Expand Down Expand Up @@ -605,7 +605,7 @@ forEach({

val: function(element, value) {
if (isUndefined(value)) {
if (nodeName_(element) === 'SELECT' && element.multiple) {
if (element.multiple && nodeName_(element) === 'select') {
var result = [];
forEach(element.options, function (option) {
if (option.selected) {
Expand Down
2 changes: 1 addition & 1 deletion src/ng/anchorScroll.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function $AnchorScrollProvider() {
function getFirstAnchor(list) {
var result = null;
forEach(list, function(element) {
if (!result && lowercase(element.nodeName) === 'a') result = element;
if (!result && nodeName_(element) === 'a') result = element;
});
return result;
}
Expand Down
12 changes: 6 additions & 6 deletions src/ng/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -759,8 +759,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
nodeName = nodeName_(this.$$element);

// sanitize a[href] and img[src] values
if ((nodeName === 'A' && key === 'href') ||
(nodeName === 'IMG' && key === 'src')) {
if ((nodeName === 'a' && key === 'href') ||
(nodeName === 'img' && key === 'src')) {
this[key] = value = $$sanitizeUri(value, key === 'src');
}

Expand Down Expand Up @@ -1030,7 +1030,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
case 1: /* Element */
// use the node name: <directive>
addDirective(directives,
directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);

// iterate over the attributes
for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
Expand Down Expand Up @@ -1897,8 +1897,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
var tag = nodeName_(node);
// maction[xlink:href] can source SVG. It's not limited to <maction>.
if (attrNormalizedName == "xlinkHref" ||
(tag == "FORM" && attrNormalizedName == "action") ||
(tag != "IMG" && (attrNormalizedName == "src" ||
(tag == "form" && attrNormalizedName == "action") ||
(tag != "img" && (attrNormalizedName == "src" ||
attrNormalizedName == "ngSrc"))) {
return $sce.RESOURCE_URL;
}
Expand All @@ -1912,7 +1912,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (!interpolateFn) return;


if (name === "multiple" && nodeName_(node) === "SELECT") {
if (name === "multiple" && nodeName_(node) === "select") {
throw $compileMinErr("selmulti",
"Binding to the 'multiple' attribute is not supported. Element: {0}",
startingTag(node));
Expand Down
10 changes: 4 additions & 6 deletions src/ng/directive/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -1128,22 +1128,20 @@ function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
textInputType(scope, element, attr, ctrl, $sniffer, $browser);

var urlValidator = function(value) {
return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
};

ctrl.$formatters.push(urlValidator);
ctrl.$parsers.push(urlValidator);
ctrl.$validators.url = urlValidator;
}

function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
textInputType(scope, element, attr, ctrl, $sniffer, $browser);

var emailValidator = function(value) {
return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
};

ctrl.$formatters.push(emailValidator);
ctrl.$parsers.push(emailValidator);
ctrl.$validators.email = emailValidator;
}

function radioInputType(scope, element, attr, ctrl) {
Expand Down
2 changes: 1 addition & 1 deletion src/ng/directive/ngPluralize.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
* When one person, perhaps John, views the document, "John is viewing" will be shown.
* When three people view the document, no explicit number rule is found, so
* an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
* In this case, plural category 'one' is matched and "John, Marry and one other person are viewing"
* In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
* is shown.
*
* Note that when you specify offsets, you must provide explicit number rules for
Expand Down
2 changes: 1 addition & 1 deletion src/ng/location.js
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ function $LocationProvider(){
var elm = jqLite(event.target);

// traverse the DOM up to find first A tag
while (lowercase(elm[0].nodeName) !== 'a') {
while (nodeName_(elm[0]) !== 'a') {
// ignore rewriting if no A tag (reached root element, or no parent - removed from document)
if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
}
Expand Down
2 changes: 1 addition & 1 deletion src/ngMessages/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ angular.module('ngMessages', [])
*
* @description
* `ngMessages` is a directive that is designed to show and hide messages based on the state
* of a key/value object that is listens on. The directive itself compliments error message
* of a key/value object that it listens on. The directive itself compliments error message
* reporting with the `ngModel` $error object (which stores a key/value state of validation errors).
*
* `ngMessages` manages the state of internal messages within its container element. The internal
Expand Down
1 change: 0 additions & 1 deletion src/ngScenario/browserTrigger.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@

var inputType = (element.type) ? element.type.toLowerCase() : null,
nodeName = element.nodeName.toLowerCase();

if (!eventType) {
eventType = {
'text': 'change',
Expand Down
4 changes: 2 additions & 2 deletions src/ngScenario/dsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ angular.scenario.dsl('element', function() {
var href = elements.attr('href');
var eventProcessDefault = elements.trigger('click')[0];

if (href && elements[0].nodeName.toUpperCase() === 'A' && eventProcessDefault) {
if (href && elements[0].nodeName.toLowerCase() === 'a' && eventProcessDefault) {
this.application.navigateTo(href, function() {
done();
}, done);
Expand All @@ -394,7 +394,7 @@ angular.scenario.dsl('element', function() {
var href = elements.attr('href');
var eventProcessDefault = elements.trigger('dblclick')[0];

if (href && elements[0].nodeName.toUpperCase() === 'A' && eventProcessDefault) {
if (href && elements[0].nodeName.toLowerCase() === 'a' && eventProcessDefault) {
this.application.navigateTo(href, function() {
done();
}, done);
Expand Down
4 changes: 2 additions & 2 deletions test/AngularSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,7 @@ describe('angular', function() {
var div = jqLite('<div xmlns:ngtest="http://angularjs.org/">' +
'<ngtest:foo ngtest:attr="bar"></ngtest:foo>' +
'</div>')[0];
expect(nodeName_(div.childNodes[0])).toBe('NGTEST:FOO');
expect(nodeName_(div.childNodes[0])).toBe('ngtest:foo');
expect(div.childNodes[0].getAttribute('ngtest:attr')).toBe('bar');
});

Expand All @@ -960,7 +960,7 @@ describe('angular', function() {
var div = jqLite('<div xmlns:ngtest="http://angularjs.org/">' +
'<ngtest:foo ngtest:attr="bar"></ng-test>' +
'</div>')[0];
expect(nodeName_(div.childNodes[0])).toBe('NGTEST:FOO');
expect(nodeName_(div.childNodes[0])).toBe('ngtest:foo');
expect(div.childNodes[0].getAttribute('ngtest:attr')).toBe('bar');
});
}
Expand Down
2 changes: 1 addition & 1 deletion test/ng/compileSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4625,7 +4625,7 @@ describe('$compile', function() {
inject(function($compile, $rootScope) {
var element = jqLite('<div>before<div transclude></div>after</div>').contents();
expect(element.length).toEqual(3);
expect(nodeName_(element[1])).toBe('DIV');
expect(nodeName_(element[1])).toBe('div');
$compile(element)($rootScope);
expect(nodeName_(element[1])).toBe('#comment');
expect(nodeName_(comment)).toBe('#comment');
Expand Down
10 changes: 10 additions & 0 deletions test/ng/directive/inputSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,16 @@ describe('ngModel', function() {
expect(element).toHaveClass('ng-invalid-required');
}));

it('should remove required on bad input', inject(function($compile, $rootScope, $sniffer) {
var element = $compile('<input type="email" ng-model="value" required />')($rootScope);
$rootScope.$digest();

element.val('bademail');
browserTrigger(element, $sniffer.hasEvent('input') ? 'input' : 'change');
expect(element).toBeInvalid();
expect(element).toHaveClass('ng-valid-required');
}));

it('should set the control touched state on "blur" event', inject(function($compile, $rootScope) {
var element = $compile('<form name="myForm">' +
'<input name="myControl" ng-model="value" >' +
Expand Down