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

custom directive and ng-pattern interfere in rc.2 #9156

Closed
mblase75 opened this issue Sep 18, 2014 · 8 comments
Closed

custom directive and ng-pattern interfere in rc.2 #9156

mblase75 opened this issue Sep 18, 2014 · 8 comments

Comments

@mblase75
Copy link

http://plnkr.co/edit/dbvC9NWcZTpWRRiUTkJU?p=preview

A custom directive (to convert a text input to all-caps as the user types), combined with a ng-pattern for validation, prevents any text from being entered into the text input.

Key HTML:

<input type="text" ng-pattern="/^[a-zA-Z]{2}$/" name="CustomerState" ng-model="customer.CustomerState" required allcaps>

JS:

'use strict';
var app = angular.module('app', ['ngRoute']);

app.directive('allcaps', function() {
// use in input fields as an HTML attribute to capitalize ALL input before sending to the model:
// <input type="text" name="JobCodeCode" ng-model="quote.JobCodeCode" capitalize>
// copied from: http://stackoverflow.com/a/16388643/901048
return {
    require: 'ngModel',
    link: function(scope, element, attrs, modelCtrl) {
        var allcaps = function(oldstr) {
            if (oldstr == undefined) { oldstr = ''; }
            var newstr = oldstr.toUpperCase();
            if (newstr!==oldstr) {
                modelCtrl.$setViewValue(newstr);
                modelCtrl.$render();
            }
            console.log(oldstr+","+newstr); // outputs capitalized characters as I type
            return newstr;
        }
        modelCtrl.$parsers.push(allcaps);
        allcaps(scope[attrs.ngModel]);  // capitalize initial value
    }
};
});

In rc.2, I type in the text field and nothing appears. This code works fine in rc.1 and previous versions.

If I remove either the custom directive JS or the ng-pattern attribute, the text field displays text again in rc.2

@mblase75 mblase75 changed the title directive won't update model in a routed view in rc.2 custom directive and ng-pattern interfere in rc.2 Sep 18, 2014
@shahata
Copy link
Contributor

shahata commented Sep 18, 2014

This is because the value passed to your parser is undefined because it is invalid (pattern requires two chars, so the first char is always invalid)
You can fix that by using ng-model-options="{allowInvalid: true}". Fixed plunkr: http://plnkr.co/edit/l8CjOdmRVVU52lklntkd?p=preview

@caitp
Copy link
Contributor

caitp commented Sep 18, 2014

did we ever mark that as a breaking change? I know someone asked for it to be documented in the changelog

@mblase75
Copy link
Author

Is this an identical issue to #8290 then? I would have liked to see it in the changelog as well.

@btford
Copy link
Contributor

btford commented Sep 19, 2014

@caitp sadly, no.

@mblase75, @shahata – would either of you like to submit a PR to add this to the changelog? :D

@mblase75
Copy link
Author

I'm still too new to do it correctly. :-/

@caitp
Copy link
Contributor

caitp commented Sep 19, 2014

I'm not sure when we changed this --- it might have been db044c4 but I'm not positive. If I can sort out when this broke I'll make sure it's documented

@Narretz
Copy link
Contributor

Narretz commented Oct 19, 2014

Throwing another hat into the ring: the actual cause is 3e51b84

$render now checks if the $modelValue is empty before calling val() with the $viewValue. This doesn't really make sense, or rather it locks $render into a single use case, model -> view updates. If we want to check for empty values before rendering, we need a different way.

What happens in the issue here is that $render sets the input to empty string, but the $viewValue stays correct. This confuses the whole processing.

Imo $render should be dumb and only set the .val()

@Narretz Narretz modified the milestones: 1.3.x, Backlog Oct 19, 2014
@Narretz Narretz self-assigned this Oct 19, 2014
Narretz added a commit to Narretz/angular.js that referenced this issue Oct 19, 2014
$render should only be concerned if there is a $viewValue present.
When we check $isEmpty($modelValue), we assume $render is used in
context of a model -> view update. But since it is part of the public
API, it needs to work independent of internal usage.

Fixes angular#9156
Narretz added a commit to Narretz/angular.js that referenced this issue Oct 19, 2014
$render should only be concerned if there is a $viewValue present.
When we check $isEmpty($modelValue), we assume $render is used in
context of a model -> view update. But since it is part of the public
API, it needs to work independent of internal usage.

Fixes angular#9156
@Narretz
Copy link
Contributor

Narretz commented Nov 25, 2014

This is fixed in 1.3.4 :)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.