Set validation for dynamic field - angularjs

I have a form where the user can add fields dynamically. It is my html:
<body ng-controller="FruitController">
<button type="button" ng-click="addFruit()">Add fruit</button>
<form name="list">
<div id="dynamicList" ng-repeat="fruit in fruits">
<input type="text" name="fruitName" ng-model="fruit.name" ng-minlength="3"/>
</div>
</form>
</body>
And it is my controller:
app.controller('FruitController', [function(){
$scope.fruits = [
{name: 'Apple', color: 'red'}
];
$scope.addFruit = function()
{
$scope.fruits.push({name: '', color: ''});
};
}]);
So, when a field is invalid i add a css class with the next directive:
ng-class="{'uk-form-danger': (list.fruitName.$invalid && !list.fruitName.$pristine)}"
The problem is that, when 1 field fails, another fields too.
Any ideas ?

Form inside ng-repeat won't work directly. You need to create a a separate form for inner elements that form will be child of outer form list
<form name="list">
<div id="dynamicList" ng-repeat="fruit in fruits">
<form name="innerForm">
<input type="text" name="fruitName" ng-model="fruit.name" ng-minlength="3"
ng-class="{'uk-form-danger': (innerForm.fruitName.$invalid && !fruit.name.$pristine)}"/>
</form>
</div>
</form>

Related

input ng-model within ng-repeat

I am repeating a list of tasks that I would like other users to be able to comment on using an input field. I repeat the list with ng-repeat and am trying to send the value of the comment input to the server with ng-model and scope. I am testing by console logging but it shows as undefined. Please help!
Html:
<div class="taskContainer">
<div ng-repeat='task in taskList' class="task">
<div class="postedBy">
<h6>{{task.user.userName}}</h6>
</div>
<h4>{{task.taskText}}</h4>
<div class="comments">
<input ng-model="newComment" type="text" placeholder="comments">
<button ng-click='comment(task.taskId)' type="button" name="button">Add</button>
<h6>{{task.commentText}}</h6>
</div>
</div>
</div>
JS controller:
$scope.comment = function(id,text){
console.log(`send comment text ${$scope.newComment}`);
console.log(`task Id: ${id}`);
};
This is the first time I've tried to do more than display itmes with ng-repeat
You're getting undefined because ngRepeat creates its own $scope.
Always assign ngModel using Dot Rule or controller-as-syntax.
Put it in your controller:
$scope.model = {};
Then use the ngModel as this:
<input ng-model="model.newComment[$index]" type="text" placeholder="comments">
Then you can have something like this:
<div class="taskContainer">
<div ng-repeat="task in taskList track by $index" class="task">
<div class="postedBy">
<h6>{{task.user.userName}}</h6>
</div>
<h4>{{task.taskText}}</h4>
<div class="comments">
<input ng-model="model.newComment[$index]" type="text" placeholder="comments">
<button ng-click='comment($index)' type="button" name="button">Add</button>
<h6>{{task.commentText}}</h6>
</div>
</div>
</div>
$scope.comment = function(index) {
console.log(`send comment text ${$scope.model.newComment[index]}`);
console.log(`task Id: ${taskList[index].id}`);
};
Note: Your function is expecting 2 parameters, you should change it to:
$scope.comment = function(id) {
Thanks for the help from #developer033.
Here is what solved my problem:
HTML:
<div class="taskContainer">
<div ng-repeat="task in taskList track by $index" class="task">
<div class="postedBy">
<h6>{{task.user.userName}}</h6>
</div>
<h4>{{task.taskText}}</h4>
<div class="comments">
<input ng-model="model.newComment[$index]" type="text" placeholder="comments">
<button ng-click='comment(task.taskId,$index)' type="button" name="button">Add</button>
<h6>{{task.commentText}}</h6>
</div>
</div>
</div>
and the JS:
$scope.model = {};
$scope.comment = function(id, index) {
console.log(`send comment text ${$scope.model.newComment[index]}`);
console.log(`task Id: ${id}`);
};
HTML,
<input ng-model="newComment" type="text" placeholder="comments">
<button ng-click='comment(task.taskId, newComment)' type="button" name="button">Add</button>
JavaScript,
$scope.comment = function(id, text) {
console.log(`task Id: ${id}`);
console.log(`send comment text ${text}`);
};

How to submit current form in ng-repeat angularjs

I need am not able to access the $scope.mainform.subform.submitted property in my script. My html goes as below.
<div ng-form="mainform">
<div ng-repeat="dependent in DependentDetails">
<ng-form name="subform">
<input type="text" class="textbox" ng-model="dependent.FirstName"/>
#*Same goes for other personal details*#
<input type="button" id="submitbutton" value="Save" ng-model="Submit" ng-click="saveDependentDetailsClick($event, $index, dependent)" />
</ng-form>
</div>
</div>
Can anyone help?
First of all, I think that it's not correct to use <ng-form name="subform">...</div> in ng-repeat in a way you have used it because you will end up with multiple forms having same name(subform) within the same scope therefore you can't refer to each of these forms as they have not unique name providing you with reference to them.
You will also end up with multiple submit buttons with the same id="submitbutton" in same html document which is an invalid html.
try this.
var app = angular
.module('MyApp', [
])
.controller('Main', ['$scope', function ($scope) {
$scope.DependentDetails = [{"FirstName":""},{"FirstName":""}];
$scope.saveDependentDetailsClick = function(DependentDetails){
console.log(DependentDetails);
}
}])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="main-content" ng-app="MyApp" ng-controller="Main as myCtrl">
<div ng-form="mainform">
<div ng-repeat="dependent in DependentDetails">
<ng-form name="subform">
<input type="text" class="textbox" ng-model="dependent.FirstName"/>
<input type="button" value="Save" ng-click="saveDependentDetailsClick(dependent)" />
</ng-form>
</div>
</div>
</div>

How to validate if form has at least one not empty input?

Just like in the title: I am wondering how I can validate, if my form has at least one input which is not empty - and then change the submit button to enabled?
Thanks!
<div ng-app="myApp" ng-controller="MyCtrl">
<div class="col-xs-12">
<form name="myForm">
<input type="text" ng-model="user.firstname">
<input type="text" ng-model="user.secondname">
<button type="button" ng-click="checkIsEmpty()" ng-disabled="!user">SUBMIT
</button>
</form>
</div>
</div>
EDIT:
JS:
function MyCtrl($scope) {
$scope.user = {};
$scope.checkIsEmpty = function(){
return angular.equals({}, $scope.user);
}
}
Fiddle:http://jsfiddle.net/nq1eyj1v/128/

How do I build a directive in angular that adds a wrapper around an input and shows message if input is invalid?

I'm a total beginner in Angular, so maybe I am thinking about it totally wrong.
What I'm trying to do is create a directive that wraps an input in some boilerplate html. It should bind the input's ng-model to the parent scope (the myForm controller's scope) but should have access to the validation state of the input.
Here's my setup:
parent_form.html
<form name="myForm">
<div fieldContainer label="'Field 1'" model="'field1'">
<input type="text" ng-model="field1" required/>
</div>
<div fieldContainer label="'Field 2'" model="'field2'">
<input type="text" ng-model="field2" required/>
</div>
</form>
field_container.html
<div class="row">
<div class="col-md-5">{{label}}</div>
<div class="col-md-5" ng-transclude></div>
<div class="col-md-2" ng-show="valid">REQUIRED!</div>
</div>
parent_form.js
angular.module('myApp')
.controller('myForm', function ($scope) {
$scope.field1 = '';
$scope.field2 = '';
})
.directive('fieldContainer', function () {
return {
restrict: 'A',
templateUrl: 'field_container.html',
transclude: true,
scope: {
label: '=label',
model : '=model'
}
}
});
I got it working by:
Adding a name to the field (so that Angular's Form validation takes over)
Setting ng-show on the validation message to be: $parent.myForm[model].$valid
So apparently the transcluded input still uses the parent (myForm) scope and the directive has access to the parent's scope via scope.$parent.
Not sure if this is the cleanest way to do it...
Final code looks like:
parent_form.html
<form name="myForm">
<div fieldContainer label="'Field 1'" model="'field1'">
<input type="text" name="field1" ng-model="field1" required/>
</div>
<div fieldContainer label="'Field 2'" model="'field2'">
<input type="text" name="field2" ng-model="field2" required/>
</div>
</form>
field_container.html
<div class="row">
<div class="col-md-5">{{label}}</div>
<div class="col-md-5" ng-transclude></div>
<div class="col-md-2" ng-show="$parent.myForm[model].$valid">REQUIRED!</div>
</div>

Button inside ng-repeat to update input in form

What I am trying to do is update an input field from within an ng-repeat. I have an ng-click on the button inside the ng-repeat for each user. When clicking on the button it should update the value of the input field which is outside the ng-repeat but in the same controller. I have just started using Angularjs and I seem to be missing something simple here, but just can't figure it out. Any help is greatly appreciated!
<div ng-app="MyApp">
<div ng-controller="Main">
<form name="myForm">
<input type="email" ng-model="rootFolders">
<button type="submit">Submit</button>
</form>
<span ng-repeat="user in users" style="float:left">
{{user.name}}<br>
<button ng-click="rootFolders='{{user.login}}'">Load Email</button>
</span>
</div>
</div>
Controller
angular.module('MyApp', []);
function Main($scope) {
$scope.rootFolders = 'bob#go.com';
$scope.users = [
{id:0,name:'user1',login:'user1#go.com',password:'123456'},
{id:1,name:'user2',login:'user2#go.com',password:'123456'},
]
}
Here is the fiddle: http://jsfiddle.net/DahDC/
You need to create a ng-click action in scope and pass in the user for current row.
<div ng-app="MyApp">
<div ng-controller="Main">
<form name="myForm">
<input type="email" ng-model="rootFolders">
<button type="submit">Submit</button>
</form> <span ng-repeat="user in users" style="float:left">
{{user.name}}<br>
<button ng-click="loadEmail(user);">Load Email</button>
</span>
</div>
</div>
angular.module('MyApp', []);
function Main($scope) {
$scope.rootFolders = 'bob#go.com';
$scope.users = [{
id: 0,
name: 'user1',
login: 'user1#go.com',
password: '123456'
}, {
id: 1,
name: 'user2',
login: 'user2#go.com',
password: '123456'
}, ]
$scope.loadEmail = function (user) {
$scope.rootFolders = user.login;
}
}
Try it. FIDDLE
I believe that because you are making the assignment inside ng-click inside ng-repeat, it is assigning the rootFolders property on the local scope there (the one instantiated by ng-repeat for each element). So your actually assigning a new property on all the local scopes of ng-repeat.
I've edited your fiddle to explicitly show this. A good learning point!
<div ng-app="MyApp">
<div ng-controller="Main">
<form name="myForm">
<input type="email" ng-model="rootFolders"> {{ rootFolders }}
<button type="submit">Submit</button>
</form>
<span ng-repeat="user in users" style="float:left">
{{user.name}}<br>
<button ng-click="rootFolders = user.login">Load Email {{ user.login }}</button><br/>
{{ rootFolders }}
</span>
</div>

Resources