angular / angular.js

AngularJS - HTML enhanced for web apps!
https://angularjs.org
MIT License
58.81k stars 27.49k forks source link

Way to retrieve ng-minlength/maxlength value in form object #11671

Open jonricaurte opened 9 years ago

jonricaurte commented 9 years ago

I was looking through the form object and it doesn't seem I can see the actual value that is being set for ng-minlength="6". Is it possible to get the 6 from the form object?

Thanks.

wonderfan commented 9 years ago

Yes. You can get it via its attributes

bruunofco commented 9 years ago

@jonricaurte Send an example of what you really want to do

kentcdodds commented 9 years ago

Here's a solution I think you'll be happy with... Here's a working jsbin

HTML:

<!DOCTYPE html>
<html>
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
    <meta charset="utf-8">
    <title>JS Bin</title>
  </head>
  <body ng-app="app" ng-controller="MainCtrl as vm">
    <div>
      <form name="vm.myForm">
        <input name="myInput" id="theInput" ng-model="foo" ng-minlength="2" ng-maxlength="{{vm.max}}" />
      </form>
    </div>
    <hr />
    <div>
      Can't get it from the NgModelController normally:
      <pre>{{vm.normalNgModelCtrl | json}}</pre>
    </div>
    <hr />
    <div>
      But you could write your own <code>ng-model</code> directive which will be used in addition to
      the normal directive and publish those values to the controller
      <pre>{{vm.myForm.myInput | json}}</pre>
    </div>
    <hr />
    <div>
      It can even be dynamic :-)
      <input type="number" ng-model="vm.max" />
    </div>
    <hr />
    <div>
      Or you could always hack it with some regular JavaScript... &lt;shudders-in-fear&gt;
      <div>
        Minlength: <span id="minlength"></span>
      </div>
      <div>
        Maxlength: <span id="maxlength"></span>
      </div>
    </div>
  </body>
</html>

JavaScript

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

app.controller('MainCtrl', function() {
  var vm = this;

  vm.max = 6;

  vm.normalNgModelCtrl = {
    "$validators": {},
    "$asyncValidators": {},
    "$parsers": [],
    "$formatters": [
      null
    ],
    "$viewChangeListeners": [],
    "$untouched": true,
    "$touched": false,
    "$pristine": true,
    "$dirty": false,
    "$valid": true,
    "$invalid": false,
    "$error": {},
    "$name": "myInput",
    "$options": null
  };
});

app.directive('ngModel', function attributeNgModelDirective() {
  return {
    require: 'ngModel',
    link: function(scope, el, attrs, ctrl) {
      ctrl.attributes = attrs;
    }
  };
});

// regular JavaScript... probably don't need to do it this way...
(function() {
  var inputEl = document.getElementById('theInput');
  var minlengthEl = document.getElementById('minlength');
  var maxlengthEl = document.getElementById('maxlength');
  minlengthEl.innerText = inputEl.getAttribute('ng-minlength');
  maxlengthEl.innerText = inputEl.getAttribute('ng-maxlength');
})();
wonderfan commented 9 years ago

@kentcdodds: Your sample codes make sense.

jonricaurte commented 9 years ago

I was thinking more of something like this:

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

kentcdodds commented 9 years ago

You could use the directive I showed you above to accomplish this.

As a side note, if you're looking for advanced forms using angular... Look no further than angular-formly. Here's an example that does something similar to what I think what you're trying to accomplish... http://angular-formly.com/#/example/other/error-summary

jonricaurte commented 9 years ago

I feel like this is a valid feature request. The error object should include something that specifies the value of ng-minlength/maxlength and the others.

kentcdodds commented 9 years ago

I see now what you are asking. You want the $error object to have meta-data about the validator used to cause an error. If that's correct, then that's a different conversation than I thought we were having :-) Until something like that gets enough interest, I don't see the angular team adding this feature to angular core. However, with the workaround I suggested, I think it'll work just fine for what you're looking for. Also, if you're doing a lot of forms in your app, I highly recommend using angular-formly which simplifies the forms API considerably.

jonricaurte commented 9 years ago

It's all good :) I feel like this is a common use case especially seeing something like angular valdr and angular-formly and how they have to have text for every kind of error instead of reusing the same template for everything. Here is another example use case for more than one on same element:

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

Also if you wanted to do something with translations you could add a filter (very basic example):

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

kentcdodds commented 9 years ago

they have to have text for every kind of error instead of reusing the same template for everything

Not sure what you mean by this. You can pretty easily make a template with angular-formly to show a dynamic the error message based on the error. Would appreciate an issue on angular-formly if you think the API could be improved :-)

jonricaurte commented 9 years ago

I should have clarified. Will leave a comment in the issues if I am misunderstanding something and will leave this ticket open as a feature request to hopefully be able to use forms like this later.

DigitalSmile commented 9 years ago

Very useful feature to have. Meta data is sometimes needed through custom validation process.

ryanelian commented 8 years ago

I need this metadata for simplifying an all-in validator component.

Something like:

<label for="Password">Password</label>
<input class="form-control" type="password" ng-model="me.Password" id="Password" name="Password" minlength="8" maxlength="72" required="required" />
<validation-message input="UserCreateForm.Password" param-maxlength="72" param-minlength="8"></validation-message>

I wish can simplify the component and do this instead:

<label for="Password">Password</label>
<input class="form-control" type="password" ng-model="me.Password" id="Password" name="Password" minlength="8" maxlength="72" required="required" />
<validation-message input="UserCreateForm.Password"></validation-message>