Validate inputs in table row with angular - javascript

I use this lib to create table on page.
Every row in this table can be edited. So if editMode is on, I show inputs at each column of row. Some of this inputs is required. I want to show red text "Required" or just red border if required field is empty.
But problem - it's simple when I use form. But in my case I can't use forms.
This answer isn't good for me, cause every row must have unique form-name for correct validation.
Example : https://jsfiddle.net/r8d1uq0L/147/
<div ng-repeat="user in users">
<div name="myform-{{user.name}}" ng-form>
<input type="text" ng-model='user.name' required name="field"/>
<span class="error" ng-show="myform.field.$error.required">Too long!</span>
</div>
</div>
<div>
<button ng-click="add()">
Add
</button>
</div>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.users = [{name:"1"}, {name:"2"}];
$scope.add = function(){
$scope.users.push({});
}
});

No need to create a dynamic form name, as ng-repeat does create new child scope on each iteration while drawing template on browser. So just keep name as name="innerForm" and use innerForm.field.$error.required to have validation over it.
<div ng-repeat="user in users">
<div name="innerForm" ng-form>
<input type="text" ng-model='user.name' required name="field"/>
{{myform[$index]}}
<span class="error" ng-show="innerForm.field.$error.required">Too long!</span>
</div>
</div>
Forked Fiddle

Related

is there any way to bind ng-model to multiple input fields uniquely inside a directive?

In my Project i Got a Issue like.I need to bind the user hobbies in the text field.if the user comes with a single hobby he can directly enter the hobby that he has. but when he had multiple then he had to click add multiple hobbies button.that working fine when i am displaying input fields dynamically using directives.but the issue is the value that coming from ng-model for that input field is binding to all input fields.
Here is my code.
Thanks in advance!
these are the images
this is how i am getting
this is what i need
In HTML
<div>
<div id="showHobbyfield"></div>
<input type="number" class="form-control" placeholder="ADD HOBBIES"
ng-click="addHoby()">
</div>
In controller
$scope.addHoby= function(){
var compiledeHTML = $compile("<div my-hobby></div>")($scope);
$("#showHobbyfield").append(compiledeHTML);
};
$scope.addUser = function(){
$scope.Users= [];
var obj = {
userhobby : $scope.user.morehobies
};
$scope.Users.push(obj);
menuStorage.put($scope.Users);
//menustorage is service to store user in localStorage.
In directive
'use strict';
angular.module('myApp')
.directive('myHobby', function() {
return {
scope : false,
templateUrl: 'views/my-hobby.html'
};
});
this is template: my-hobby.html
<div class="input-group">
<input type="text" ng-model="user.morehobies" class="form-control" placeceholder="type your hobbies here">
<div class="close-icon">
<span class="glyphicon glyphicon-remove" style="padding-left: 6px;"> </span>
</div>
</div>
For this i would suggest some other way if its ok with you.
If your hobbies is coming in array, like
user.morehobies = ['Reading', 'Writing']
or create array for storing hobbies.
then inside directive you can pass that object in directive.
I will use ng-repeat inside directive.
<div class="input-group" ng-repeat="h in hobies">
<input type="text" ng-model="h" class="form-control" placeceholder="type your hobbies here">
<div class="close-icon">
<span class="glyphicon glyphicon-remove" style="padding-left: 6px;"> </span>
</div>
</div>
so whenever user clicks on "Add hobbies" then we can add empty string in hobbies object in directive.
and whenever user clicks on remove you can remove that item from array.

textbox validation for number and required in repeating mode angular js

Please refer below link
https://plnkr.co/edit/9HbLMBUw0Q6mj7oyCahP?p=preview
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.NDCarray = [{val: ''}];
$scope.NDCadd = function() {
$scope.NDCarray.unshift(
{val: ''}
);
};
$scope.data = angular.copy($scope.NDCarray);
$scope.NDCcancel=function(){debugger
$scope.NDCarray=$scope.data;
}
$scope.NDCdelete = function(index) {
if(index != $scope.NDCarray.length -1){
$scope.NDCarray.splice(index, 1);
}
};
});
It contains the textbox with add button. I have added validation for number and required field, it is working fine. but when i click add button it will create another textbox with entered value that time it showing the validation message for all the textboxes , i don't want to show validation message for all the textboxes. need to show validation for corresponding textbox only. that means when i enter something wrong in second textbox it is showing message to that textbox only.refer below screenshot.
validation message displaying for all textboxes.that should display for only one textbox.
Working plnkr : https://plnkr.co/edit/f4kAdZSIsxWECd0i8LDT?p=preview
Your problem is in your HTML, to get independant fields you must :
Move outside the form of the ng-repeat
Provide a dynamic name using $index on your fields, because name is what make each fields independant on the validation.
Here is the final HTML from the plnkr i didn't touch at all the javascript :
<body ng-controller="MainCtrl">
<form name="myForm">
<div ng-repeat ="ndc in NDCarray">
<div class="col-sm-4 type7" style="font-size:14px;">
<div style="margin-bottom:5px;">NDC9</div>
<label>Number:
<input type="number" ng-model="ndc.value"
min="0" max="99" name="{{'input_'+$index}}" required>
</label>
<div role="alert">
<span class="error" ng-show="myForm.input.$dirty && myForm.input.$error.required">
Required!</span>
<span class="error" ng-show="myForm.input.$error.number">
Not valid number!</span>
</div>
<tt>value = {{example.value}}</tt><br/>
<tt>myForm['input_{{$index}}'].$valid = {{myForm['input_'+$index].$valid}}</tt><br/>
<tt>myForm['input_{{$index}}'].$error = {{myForm['input_'+$index].$error}}</tt><br/>
</div>
<div class="col-sm-4 type7 " style="font-size:14px;">
<div style="padding-top:20px; display:block">
<span class="red" id="delete" ng-class="{'disabled' : 'true'}" ng-click="NDCdelete($index)">Delete</span>
<span>Cancel </span>
<span id="addRow" style="cursor:pointer" ng-click="NDCadd()">Add </span>
</div>
</div>
</div>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
<tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
</form>
</body>
Couple of changes:
If you add "track by $index" to your ng-repeat it will make each group of elements unique so that you don't have to worry about deriving unique names for elements.
Your validation on the number (myForm.ndcValue.$error.number) didn't work so I changed it to myForm.ndcValue.$error.max || myForm.ndcValue.$error.min
Also, you can throw an ng-form attribute directly on the div with your ng-repeat.
Like this:
<div ng-repeat="ndc in NDCarray track by $index" ng-form="myForm">
<div class="col-sm-4 type7" style="font-size:14px;">
<div style="margin-bottom:5px;">NDC9</div>
<label>Number:
<input type="number" ng-model="ndc.value" min="0" max="99" name="ndcValue" required>
</label>
<div role="alert">
<span class="error" ng-show="myForm.ndcValue.$dirty && myForm.ndcValue.$error.required">
Required!</span>
<span class="error" ng-show="myForm.ndcValue.$error.max || myForm.ndcValue.$error.min">
Not valid number!</span>
</div>
<tt>value = {{example.value}}</tt>
<br/>
<tt>myForm.ndcValue.$valid = {{myForm.ndcValue.$valid}}</tt>
<br/>
<tt>myForm.ndcValue.$error = {{myForm.ndcValue.$error}}</tt>
<br/>
</div>
Here's the working plunker.
I changed the input element name from "input" to "ndcValue" to be less confusing.

Incorporate directive's functionality into Angular form validation

I have two questions that are related:
First: I have the following directive, who's purpose is to validate whether an input[type=file] is valid or not, however I have no idea how it does it least of all, what the actual code means, here it is:
angular.module('sccateringApp')
.directive('fileModel', ['$parse', function($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
Like I said, I have no idea what the above code actually does, the explanation I got from the forum where I copied that was that it validated an input type file. Is this correct? (So far I haven't been able to verify if it works or not since it doesn't work with the code I'm using at the moment to validate my forms).
Second: Having the form below, using angular form validation it doesn't allow the submit button to be clicked until the actual inputs inside the form match the validation rules (enter a name for the category, and the description should have a max length of 144 characters). I included the directive into the file input, however the actual ng-model for the form ignores the required in the input type file and just verifies the rules are met for the first two inputs.
Here is my form:
<form method="post" role="form" name="newCategoryForm" ng-submit="submitForm()" enctype="multipart/form-data" novalidate>
<div class="row">
<div class="row">
<div class="col s12">
<div input-field>
<input type="text" name="cat-name" id="cat-name" ng-class="{ 'ng-invalid' : newCategoryForm.catname.$invalid && !newCategoryForm.catname.$pristine }"
ng-model="catname" required>
<label>Nombre</label>
</div>
</div>
</div>
<div class="row">
<div class="col s12">
<div input-field>
<textarea class="materialize-textarea" name="cat-description" id="cat-description" length="144"
ng-model="catdescription" ng-maxlength="144" required></textarea>
<label>Descripción</label>
</div>
</div>
</div>
<div class="row">
<div class="col s12">
<h6>Imagen de Fondo</h6>
<div class="file-field input-field">
<div class="btn pink darken-2 waves-effect waves-light">
<span>Archivo</span>
<input type="file" name="cat-bgimg" id="cat-bgimg"
file-model="variable" required>
</div>
<div class="file-path-wrapper">
<input class="file-path" type="text">
</div>
</div>
</div>
</div>
</div>
<button type="submit" class="btn btn-large pink darken-2 waves-effect waves-light center-button" ng-disabled="newCategoryForm.$invalid">Crear Categoría</button>
</form>
The first two inputs get validated correctly, the third one (file input) doesn't and I don't really know why since the directive got included on the input (I know natively, ngModel doesn't validate file inputs).
Any ideas or suggestions of how can I fix this? I'm really new to Angular, and all the tutorials are pretty much useless. I come from 5 years of experience working on jQuery, and the transition to Angular hasn't been easy at all.
The directive posted above is used to make the submit get the data found in the <input type="file"></input>.
Also, a variable should be initialized in the controller so that the values found inside the form are copied to said variable, then this variable needs to be sent as a parameter inside the ng-submit="submitForm().
Example:
angular.module('sccateringApp')
.controller('newSubcategoryController', function (httpcalls, $scope) {
...
$scope.subcategory = [];
...
$scope.submitForm = function(subcategory){
...
$scope.request.insertSubcategory(subcategory);
}
});
Each ng-model inside the form would be:
<input type="text" ng-model="category.name">
So that the category variable found in the controller acquires that value.

AngularJS: ng-model not clearing input

I have a dynamic input for CPFs (Brazilian 'social security' number).
Every time I enter one CPF, another input should be displayed, and so on..
But for some reason, the ng-model is not being cleared after the CPF is added.
Here's my HTML (inside a directive with isolate scope):
<div ng-repeat="cpf in cpfs" class="field-input">
<input type="text" class="field" ng-model="cpf.number" required>
<label>added CPF</label>
</div>
<div class="field-input">
<input type="text" class="field" ng-model="cpf.number" required>
<label>add new CPF</label>
<button ng-click="addCpf(cpf)" class="btn btn-primary">add</button>
</div>
Here's my controller (inside a directive with isolate scope):
$scope.cpfs = [];
$scope.addCpf = function(cpf) {
$scope.cpfs.push(angular.copy(cpf));
delete $scope.cpf;
};
instead of delete $scope.cpf; use $scope.cpf.number = "";
we can't delete an model, we have to set it to blank, because its linked with our View part

Input field blurs when inline editing in ng-repeat

I am trying to do inline editing on a table of data (See the plunkr)
<table class="table table-bordered">
<tr ng-repeat="data in dataset" >
<td ng-repeat="(key, value) in data" >
<div class="key-block">
<strong >{{key}}</strong>
</div>
<div class="val-block" inline-edit="data[key]" on-save="updateTodo(value)" on-cancel="cancelEdit(value)">
<input type="text" on-enter="save()" on-esc="cancel()" ng-model="model" ng-show="editMode">
<button ng-click="cancel()" ng-show="editMode">cancel</button>
<button ng-click="save()" ng-show="editMode">save</button>
<span ng-mouseenter="showEdit = true" ng-mouseleave="showEdit = false">
<span ng-hide="editMode" ng-click="edit()">{{model}}</span>
<a ng-show="showEdit" ng-click="edit()">edit</a>
</span>
</div>
</td>
</tr>
I can see in many places that we have to use a . in ng-model inside ng-repeat to avoid the scope issue. As I dont know the key already I am doing like data[key] for the model.
The input field blurs after I enter a single character.
The behavior you described is normal. If you look closely you will see that both the input value and the directive are bound to the same object i.e data[key]. When you change the value of the text input the model get updated ultimately triggering a refresh of the directive and you are back to the "list" view.
One easy solution to fix this is to use an intermediate variable between the directive and the input value and update the model only when the save button is clicked. Something like that :
//Directive
scope.newValue = null;
scope.edit = function() {
scope.editMode = true;
scope.newValue = scope.model;
$timeout(function() {
elm.find('input')[0].focus();
}, 0, false);
};
//Template
<input type="text" on-enter="save()" on-esc="cancel()" ng-model="newValue" ng-show="editMode">
You can see a modified plunker here.

Categories