AngularJS text input validation with counter - angularjs

I'm developing an app containing a form which has a text input with ng-model="description".
Now I want to validate this text input using ng-maxlength="50" and required. This works fine, but I also want to add a character counter (like 67/50) shown at all times. I'm using the following code to display the counter: {{description.length || 0}}/50
The issue with this, however, is that description.length doesn't return a value when it's greater than 50, because description input is invalid. In my scenario the counter would default to 0/50 when there's no input (and that's fine) but also when input exceeds max length.
I would also like to display my counter in red when the input length's invalid, but that shouldn't be too hard using angular validation css classes.
Of course I could provide custom validation, but I'm positive there's an easier solution.

Use the form element $viewValue instead like this:
<form name='form'>
<input type="text" name='description' ng-model='description' ng-maxlength="50">
{{form.description.$viewValue.length || 0}}/50
</form>
See this plunker

Related

restrict uibDatepicker pop up to accept only digits and '-'

I have a requirement that I need to let user only enter digits and - into date picker and prevent user from entering other characters, how can I achieve this?
for example I want prevent user from entering text like asasdfas in input field for datepicker.
I used this code in parseDate function inside uibDatepicker code but view doesn't get updated.
var regex = /[^0-9\-]/g;
viewValue = viewValue.replace(regex, '');
here is a plunk to play around: http://plnkr.co/edit/AKFhTG162Ck5Blt0ZBH7?p=preview
Changing the input type to date restricts the user from inputting any extra text.
<input type="date" />
The problem is that enables the HTML5 default date picker. I have added a little css to hide that part but you would need to check it other browsers. I was unable to remove the arrows and again I will leave you to do it.
Hope it helps. I forked your PLUNK HERE

Submittable HTML5 Web Component

How do I create a form-submittable web component?
Background:
I have a customer-picker component that is basically a text input plus a tiny button to the right of the text box plus a dialog that pops up when the button is clicked. It is used in the same way as one might use an html select.
This component is used as part of an html form that is submitted in the old fashioned (non-ajax) kind of way. The actual html input is encapsulated privately inside of the customer-picker component.
Problem:
The text input's value is not submitted
I guess I can understand why this is. I suppose this is the desired behavior (otherwise we are breaking encapsulation).
So with all that said, how do I create a submittable web component?
For example, suppose I have a form like this:
<form action="action.jsp">
<input name="date-start"/>
<input name="date-end"/>
<input name="name-first"/>
<input name="name-last"/>
</form>
that gets submitted like this:
action.jsp?date-start=2016-06-01&date-end=2016-06-30&name-first=Joe&name-last=Smith
I would like to create the same form using components like this:
<form action="action.jsp">
<date-range name="date">
<full-name name="name">
</form>
that gets submitted exactly the same way as the example above:
action.jsp?date-start=2016-06-01&date-end=2016-06-30&name-first=Joe&name-last=Smith
I am aware of iron-form. But this solution has some problems.
For one, it does not emulate native form submission very well. In a normal html form, when you submit, the current page is automatically replaced by whatever is returned by the action URL. This doesn't seem to happen with iron-form.
Second. It only allows your component to contribute a single value to the submitted data. In the above mentioned date-range example, I would like two values to be submitted for one component.

AngularJS + TinyMCE: ng-maxlength is not working on <textarea>

I want to limit max text length so it doesn't exceed a column length in a DB. I've put this limitation on backend, and now I want to enforce it on frontend.
I use TinyMCE v4.3.3 with angular-ui-tinymce v0.0.12 plugin and AngularJS v1.4.6.
JS:
var tinymceOpts = {
toolbar: false,
menubar: false,
// do not add <p></p> from the start:
forced_root_block: ''
}
HTML:
<textarea ui-tinymce="tinymceOpts"
ng-model="body"
name="body"
ng-maxlength="100"
required>
{{ body }}
</textarea>
<span ng-show="form.body.$error.maxlength" class="error">
Reached limit!
</span>
As you can see, I use ng-maxlength attribute here to limit a length of <textarea>.
Expected result: input is validated and error message is displayed only if content length (with tags included) has exceeded a limit (100 characters in this case).
Actual result:
Form input state is set to invalid when the input contains some text (no matter what length).
Number of characters (in the right bottom corner) is calculated for testing:
this.getCharCount = function() {
var tx = editor.getContent({format: 'raw'});
return tx.length;
};
The problem here is that TinyMCE uses an own <iframe> to edit text contents and writes them back to your <textarea> on special events.
No wonder ng-maxlength does not work here.
In order to achieve what you want you will need to check for the editor content itself and disallow entering more characters in case the maxlength is reached.
I managed to get it working! It was necessary to disable SCE mode in AngularJS:
angular.module('myApp', ['ui.tinymce'])
.config(['$sceProvider', function($sceProvider) {
$sceProvider.enabled(false);
}])
.controller('myCtrl', ['$scope', function($scope) {
// ...
}]);
jsFiddle
! Beware of security vulnerabilities !
Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain contexts to result in a value that is marked as safe to use for that context. With SCE disabled, an AngularJS application allows to render arbitrary HTML into the <div>, and rendering user controlled input creates security vulnerabilities.
I believe what you really want is to have the TinyMCE directive calculate the "length" of the visible characters as opposed to counting the characters in the <textarea>. TinyMCE is going to inject its own iFrame into the page and the editor is part of that iFrame - its not the <textarea>.
When you put validation on the <textarea> you are asking Angular to count the characters in the <textarea>...this is going to be an issue for you. The issue is that the standard directives just count characters so a simple (empty) HTML sample:
<p></p>
Would indeed be counted as 7 characters when in reality there is no "visible" content. I built a custom directive for another editor and what I ended up doing is using jQuery's .text() function against the HTML. This removes all of the HTML tags and provides an approximation for the number of actual text characters in the editor. This is a portion of the code in the directive:
var jStrippedString = jQuery(modelValue).text().trim();
return (maxlength < 0) || ngModelCtrl.$isEmpty(jStrippedString) || (jStrippedString.length <= maxlength);
I believe that you would want to create a custom Attribute directive that allows you to grab the model data for the editor and perform this validation yourself as opposed to simply counting the characters in the <textarea>.

AngularJS - Form validation triggered on load

I added field validation attributes like "required" and "pattern" in my form, and the form is inside a ng-controller. The validation works. But it seems the validations are triggered on page load, and I see all the fields are marked as invalid with error message when the page load.
I tried to add "novalidation" attribute to the form as indicated in the examples on AngularJS website, but no luck.
I would like to have the validation triggered the first time the user tries to interact with it. How can I do that?
Update
Here's an example https://jsfiddle.net/davidshen84/00t197gx/
<div class="mdl-cell mdl-cell-6-col mdl-textfield mdl-js-textfield">
<input class="mdl-textfield__input" type="text" id="screenname" pattern="[a-zA-Z0-9]{3,}" ng-model="comment.screenname" required/>
<label class="mdl-textfield__label" for="screenname">Screen Name</label>
</div>
On load, you should see all the input fields had a red line under them which indicate they are in the invalid state. And the line turns to blue once validated.
Note: The style on the check button does not work...should not be a concern in the problem.
Angular is going to check the form the same way at any point (load or later) and render the result. If you don't want to display the results on load, add logic to check whether the form has been interacted with. You can hide your error messages using ng-if="yourFormName.$dirty", or display according to the status of an individual field with yourFormName.yourFieldName.$dirty.
Click here for live demo.
What is currently implemented (wrong IMHO) is that MDL automatically validates input and doesn't mind "novalidate" form attribute. I had to implement check for empty input value (skip validation and remove is-invalid class) and, since angular form validation requires "novalidate" attribute, check:
if (input.form.novalidate = true) // skip validation
that way you can actually turn off mdl validation and leave everything to angular.
One more thing is actually required. You can create angular directive which validates expression and add is-invalid class if necessary:
div class="mdl-textfield" mdl-validator="form.email.$error"

ng-maxlength preventing a valid value from being databound to input field

I have the following field in a form:
<input type="text" name="dedicatedstaff" ng-model="staffingRecord.dedicatedStaff"
tabindex="9" ng-pattern="/^[0-9]{0,4}(\.[0-9]{1,2})?$/" ng-maxlength="7" />
The form is to edit an existing record. No matter what value is in the existing record, the field fails validation and the databind becomes undefined. Some example values that exist on the records are 1, 2.5, 12.5, 99.25, 4.0. I believe every one of these should pass both the pattern and maxlength validations, but it isn't working. I've checked the model and the values are present when loading the form.
When I remove the ng-maxlength directive and just have the ng-pattern, it works fine and those values pass validation. If I remove ng-pattern and just have max-length, it fails. It also doesn't matter if the INPUT is of type text or number. If ng-maxlength is present, it fails. Browser also does not make a difference (tested Chrome, IE & Firefox). I have also verified that it is the maxlength error in the error list.
I am also using ng-maxlength with almost every other field on this particular form, and they also work just fine. And if I type the exact values listed above after form load when ng-maxlength is present validates fine at that point. But that's not a reasonable workflow to make the client type the values over again every time they load the form.
I don't understand it as I use this same pattern in other forms within the app and they work fine. I can get by with just ng-pattern on this particular field, but I would much rather figure out why, in this one case, it won't validate properly on load.
I'm using AngularJS 1.2.14, with JQuery 1.9.1.
I figured it out. It was actually the INPUT type after all. After further testing, I realized my initial test of that variation was incorrect. Changing the INPUT type to NUMBER fixed the validation issues.
<input type="number" name="dedicatedstaff" ng-model="staffingRecord.dedicatedStaff"
tabindex="9" ng-pattern="/^[0-9]{0,4}(\.[0-9]{1,2})?$/" ng-maxlength="7" />

Resources