How to apply Multiple ng-pattern with one input control

后端 未结 5 558
甜味超标
甜味超标 2021-01-01 05:30

I am trying to Validate Postal code and Phone Number in Text box using Angularjs. But it\'s not working

 

        
相关标签:
5条回答
  • 2021-01-01 05:33

    See this answer: Angularjs dynamic ng-pattern validation

    You can add a function from scope that returns a true or false based on the validation test. Here is some code below to check out. See the answer for additional information:

    Controller:

    $scope.postalCodeValidation = (function() {
        var regexp = /^\(?(\d{3})\)?[ .-]?(\d{3})[ .-]?(\d{4})$/;
        return {
            test: function(value) {
                return regexp.test(value);
            }
        };
    })();
    

    HTML:

    <input type="text" class="form-control errorfields" id="postalCode"
     name="postalCode" ng-model="postalCode" 
     ng-pattern="postalCodeValidation "  required>
    
    0 讨论(0)
  • 2021-01-01 05:39

    Your regex has two || instead of single, which breaks the regex validation clause.

    I pasted it to (https://regex101.com) and it says that char breaks it.

    0 讨论(0)
  • 2021-01-01 05:42

    First, having double pipes in your regex syntax as mico pointed out, is invalid and will break your expression.

    Second, ng-pattern can only validate one pattern per input. If you need it to validate either or, you will need to go one of two routes, create a custom directive, or add some logic to the controller to determine which expression we should check against and pass it into ng-pattern using data binding. This is bad practice in the angular world, so your best bet is to make a directive.

    0 讨论(0)
  • 2021-01-01 05:44

    Edit: This will only work for regular expressions with starting ^ and ending $ metacharacters.

    Like many of my StackOverflow answers, I'm super late to this party. This question got me on the right track, but none of the answers given were good enough to make a final solution.

    Here's something I wrote recently after reading this thread which didn't fully answer my question, which made my code reviewer exclaim, "WTF IS THIS?!" Followed by him hitting the MERGE button.

    My problem was I had a form input which I wanted to accept and validate against latitude or longitude regular expressions. I wanted to match against DMS, DDM, and DD style inputs. I could have written one giant expression, but I also needed to test the input at the component level to determine which type the user input and convert it to DD. The expressions for lat/long would make this answer even more complicated, so I am using what I think the original author intended.

    If you're interested in lat/long expressions, here's a gist: https://gist.github.com/pjobson/8f44ea79d1852900457bc257a4c9fcd5

    Here's kind of a rewrite of my code for this exercise, I abstracted it from angular to make it more accessible as it could be used for other purposes.

    It looks like you're accepting: North America Zip Code OR UK Zip Code OR something which starts with 0-9.

    Fleshing out the regex a bit, I haven't tested these myself very well, so your mileage may vary. This is what the need seemed to look like to me, it is just sample code, so it doesn't really matter that much 3+ years later.

     N.America Zip or Zip+4 (from sample above)
         ^(\d{5}(-\d{4})?$
     UK Zip Code (from wikipedia)
         ^([A-Za-z][A-Ha-hJ-Yj-y]?[0-9][A-Za-z0-9]? ?[0-9][A-Za-z]{2}|[Gg][Ii][Rr] ?0[Aa]{2})$
     N.America Phone Number (from RegExLib.com)
        ^[2-9]\d{2}-\d{3}-\d{4}$
     UK Phone Number (from RegExLib.com)
        ^(\s*\(?0\d{4}\)?\s*\d{6}\s*)|(\s*\(?0\d{3}\)?\s*\d{3}\s*\d{4}\s*)$
    

    In an object...

    const expressions = {
        naZip: /^\d{5}(-\d{4})?$/,
        ukZip: /^([A-Za-z][A-Ha-hJ-Yj-y]?[0-9][A-Za-z0-9]? ?[0-9][A-Za-z]{2}|[Gg][Ii][Rr] ?0[Aa]{2})$/,
        naPhone: /^[2-9]\d{2}-\d{3}-\d{4}$/,
        ukPhone: /^(\s*\(?0\d{4}\)?\s*\d{6}\s*)|(\s*\(?0\d{3}\)?\s*\d{3}\s*\d{4}\s*)$/
     };
    

    Now the problem is ng-pattern ONLY accepts one regex, but I have four. I want to keep those as four different things so in my component I can test to figure out which one the user input and do different actions based on whatever it is.

    This looks like garbage, but it works really well.

     const combinedExpression = new RegExp(`^(${_.map(expressions, exp => `(${exp.toString().replace(/^\/\^(.+?)\$\/$/,'$1')})`).join('|')})$`);
    

    From here of course you can add this to your model and set your ng-pattern to it.

    I'll try to explain this in several different ways here...

    Here is a break down of what it is doing.

     new RegExp(`^(${_.map(expressions, exp => `(${exp.toString().replace(/^\/\^(.+?)\$\//g,'$1')})`).join('|')})$`);
     ^          ^^^^ ^                  ^      ^ ^ ^              ^                                ^  ^          ^^
     |          |||| |                  |      | | |              |                                |  |          ||
     |          |||| |                  |      | | |              |                                |  |          |+- end of the 1st template literal
     |          |||| |                  |      | | |              |                                |  |          +- end the expression with $
     |          |||| |                  |      | | |              |                                |  +- join all stringified expressions with a pipe so (a|b|c|d)
     |          |||| |                  |      | | |              |                                +- end of 2nd template literal
     |          |||| |                  |      | | |              +- replace the like /^(\d{5}(-\d{4})?$/ to (\d{5}(-\d{4})?
     |          |||| |                  |      | | +- convert the expression to a string
     |          |||| |                  |      | +- new Expression interpolation
     |          |||| |                  |      +- 2nd templte literal
     |          |||| |                  +- each expression is represented by exp
     |          |||| +- Using lodash map the expressions
     |          |||+- Expression interpolation
     |          ||+- Regex group match, we will be grouping each of the expressions
     |          |+- Regex starts with ^
     |          +- Starting a new template literal
     +- Establish a new combined expression.
    

    Further clarification...

    What I'm doing is taking each of the expressions, converting them to strings, removing the starting end ending characters, joining them back together as an OR Group and then converting the whole thing to one huge combined regular expression.

    Further clarification...

    If that was too confusing, which I can see how it may be...

    1. Loop through each of the expressions.
    2. Convert each of those values to a string removing the starting and ending components so /^(\d{5}(-\d{4})?$/ converts to (\d{5}(-\d{4})?.
    3. Join all of those together into one big OR Group so you'd get something like (a|b|c|d) where a, b, c, d are each of your stringified expressions.
    4. Wrap the OR Group with starts with ^ and ends with $.
    5. Wrap the entire thing with in a new RegExp.

    Further clarification, in long hand JS.

    // Instantiate a new empty array
    const strings = [];
    // Loop the expressions
    for (let key in expressions) {
      // Console log to see what we're getting
      console.log('original expression', expressions[key]);
      // assign the current expression
      let stringifiedExp = expressions[key];
      // convert the current expression to a string
          stringifiedExp = stringifiedExp.toString();
      // replace the starting /^ and ending $/ with the contents
          stringifiedExp = stringifiedExp.replace(/^\/\^(.+?)\$\/$/,'$1');
      // Console log to see what we got.
      console.log('stringified expression', stringifiedExp);
      // Push the stringified expression to strings.
      strings.push(stringifiedExp);
    }
    
    // Instantiate a new string which we'll build the regex with
    let expString  = '^(';
        expString += strings.join('|');
        expString += ')$';
    
    // Console log to see what we've got.
    console.log(expString);
    
    // Make a new Regular Expression out of the string
    const combinedExpression = new RegExp(expString);
    
    // Console log what we've got
    console.log(combinedExpression);
    
    0 讨论(0)
  • 2021-01-01 05:51

    I think you need to wrap a ng-form around your input. And then you can use [formName].postalCode.$error

    0 讨论(0)
提交回复
热议问题