Dynamically add input fields with Angular and perform validation on blur - angularjs

Form at start has 1 input field for address. Bellow there is a link that when clicked adds another input and so on. There is no limitation in number of fields.
Is there more elegant way of adding new elements in model collection in Angular? I'm currently using an array of null elements, and on the link click I just push another null in that array so ng-repeat picks it up. And when I want to submit form I go through that array and filter out elements that are not null.
When input field is focused out/blurred there should be validation performed. I'm currently calling a function from controller on ng-blur event but I'm having trouble passing it current input text value.
Fiddle
HTML:
<div ng-app="TestApp">
<div ng-controller="MainCtrl">
<div ng-repeat="field in fields track by $index">
<input type="text" placeholder="enter the address" ng-model="fields[$index]" ng-blur="validate()" />
</div>
+ Add another input
<br/>
<br/>
List addresses
</div>
</div>
JS:
var app = angular.module("TestApp", []);
app.controller("MainCtrl", function($scope){
$scope.fields = [null];
$scope.addresses = [];
$scope.addField = function(){
$scope.fields.push(null);
};
$scope.listAddresses = function(){
for(var i in $scope.fields){
if($scope.fields[i] !== null){
$scope.addresses[i] = $scope.fields[i];
}
}
alert("Addresses: " + $scope.addresses);
};
$scope.validate = function(){
console.log("Should validate current input");
};
});

Instead of using two arrays, use one and store objects:
$scope.items =
[
{ address: '' }
];
It will now be clearer what the model of the input is, as you don't have to use $index. You can also pass the item to the validate function:
<div ng-repeat="item in items">
<input type="text" ng-model="item.address" ng-blur="validate(item)" placeholder="enter the address" />
</div>
Adding item:
$scope.addItem = function() {
$scope.items.push({ address: '' });
};
Demo: http://plnkr.co/edit/sPlPO2DfrgNHf5AasYlH?p=preview

Related

Push values to array in controller

I have input fields on the DOM that I'm capturing using ng-model.
In my controller, I have an array:
app.controller('mainCtrl', function() {
// set an empty array
self.manualEntry = [];
/**
* ensure form validation
* #returns boolean - ng-disabled value
*/
self.disableForm = function() {
if (self.manualEntry.length <= 0) {
return true;
}
else {
return false;
}
};
});
In my view, I have input fields:
<form>
<input placeholder="John" ng-model="mainCtrl.manualEntry.firstName"/>
<input placeholder="Smith" ng-model="mainCtrl.manualEntry.lastName"/>
</form>
<button type="submit"
ng-disabled="mainCtrl.disableForm()"
title="Submit">Submit
</button>
I thought that $scope automatically updated the model for use in the controller. I thought using dot notation in the DOM would push these values to the array.
When I update these values, the submit button on the form remains disabled (i.e. disableForm() returns true).
How can I push these values to self.manualEntry when they change or are updated on the DOM?
I am making a large assumption on what you want but it seems regular form validation is the way to go for this. Demo at http://plnkr.co/edit/Nzmk3R8eU0fmbBZRrTBa?p=info.
Controller Code
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
// set an empty array
var self = this;
self.manualEntry = {};
//Let HTML5 handle the form validation itself
self.printInfo = function() {
console.log(self.manualEntry);
};
});
HTML Code:
<body ng-controller="MainCtrl as mainCtrl">
<form ng-submit="mainCtrl.printInfo()">
<input placeholder="John" ng-model="mainCtrl.manualEntry.firstName" ng-required="true" />
<input placeholder="Smith" ng-model="mainCtrl.manualEntry.lastName" ng-required="true" />
<button type="submit" title="Submit">Submit
</button>
</form>
</body>

Resetting form controls after action in Angular

Need a bit of help with this. I am trying to get Angular to reset value of my input box after add control is invoked. This is kind of important when it comes to drop down select boxes. I want to be able to clear what user has selected after the option is pushed to a collection.
I also seems to have an issue with user.fName updating whatever I previously added to the users array but it's probably related to the above.
Also can you see what I am doing wrong with ng-show?
html
<div ng-controller="UserController" name="form">
<div ng-show="form.fName.$touched">Hello {{ user.fName }}</div>
<input type="text" name="fName" ng-model="user.fName">
<a ng-click="addUser(user)">Add</a>
<br>
<div ng-repeat="user in users">{{ user }}</div>
</div>
javascript
function UserController($scope) {
//$scope.user = {
// fName: "Joe",
// lName: "Doe"
//};
$scope.users = [];
$scope.addUser = function (user) {
if($scope.users.indexOf(user) === -1){
$scope.users.push(user);
} else {
// trigger error/notification message
console.log(user, ' already added');
}
user = {}; //clear user
};
}
ngModel will try to bind to the property given by evaluating the expression on the current scope. If the property doesn't already exist on this scope, it will be created implicitly and added to the scope.
You are currently not using the scoped property in your click action but a copy that is passed as a parameter. Change user to $scope.user in your addUser method
Note: your object comparison to identify already added users won't work as you always create new objects that will never match. Change it to some different comparison method like comparing the fName properties.
html
<div ng-controller="UserController" name="form">
<div ng-show="form.fName.$touched">Hello {{ user.fName }}</div>
<input type="text" name="fName" ng-model="user.fName">
<a ng-click="addUser()">Add</a>
<br>
<div ng-repeat="user in users">{{ user }}</div>
</div>
javascript
function UserController($scope) {
$scope.users = [];
$scope.addUser = function () {
if($scope.users.indexOf($scope.user) === -1){
$scope.users.push($scope.user);
} else {
// will never match as indexOf() will always return -1
console.log($scope.user, ' already added');
}
$scope.user = {}; //clear user
};
}
http://plnkr.co/edit/N5FXJdWRl42YrVwJsUuR?p=preview
As for your ng-show question: $touched was introduced in AngularJS 1.3 and you're referencing AngularJS 1.2.x in your Plunker code.

Angular js Dynamic Input and show value

I want dynamic input in my form so that user can add many input as much he wants
Same time I want to display the value of it..
Example:
Suppose i have one input
Customer: <input type="text" ng-model="name"/> <!--first input>
<a>Add more</a>
I can easily get value for it
All customers <p ng-bind="name"></p>
BUT if users add one more customer name input, Then how can i show that value
Under "All customers tag"
All customers <p ng-bind="name"></p> // Customer1,Customer1 name here
Use an array of objects on scope in conjunction with a ng-repeat. The button will then add to the array.
View:
<p ng-repeat="item in array">Name: <input type="text" ng-model="item.name" ></p>
<button ng-click="add()">Add</button>
<p>All customers</p>
<p ng-repeat="item in array">{{item.name}}</p>
Js:
app.controller('MainCtrl', function($scope) {
$scope.array = [];
$scope.add = function () {
$scope.array.push({ name: ''});
}
$scope.add();
});
Plunkr
You have to create array.
In your controller
$scope.inputs = [];
$scope.add = function() {
$scope.inputs.push({value: ''});
}
$scope.add();
now in HTML
<div ng-repeat="input in inputs">
<input type="text" ng-model="input.value" />
</div>
<button ng-click="add()">Add</button>
This is raw concept of how that might be done.
Update
Added plunker example
http://plnkr.co/edit/bHLXCjsP46GiixysZZ83?p=preview

Callback on 2 Inputs

I have a 2 form input (firstName, lastName) and I want to check if they are unique (form validation) by querying my database. So I basically want to have a callback when two of my input elements is inputted.
What is the angular way of doing this?
I'm thinking of getting the element and using .on('blur') while checking if the other input is valid but this feels very jQuery like.
use ng-blur on the inputs.
Here's an example:
HTML:
<div ng-app='myApp' ng-controller='myCtrl'>
Username : <input type='text' ng-model='model.username' ng-blur='checkInputs()' /><br/>
Password: <input type='text' ng-model='model.password' ng-blur='checkInputs()' /> <br/>
</div>
JS:
var app = angular.module('myApp',[]);
app.controller('myCtrl', function($scope){
$scope.model = {username:'', password:''};
$scope.checkInputs = function(){
if($scope.model.username != '' && $scope.model.password != ''){
if($scope.model.username == 'testuser' || $scope.model.password == 'testpass')
{
alert('insert unique fields!!!!')
}
}
}
});
func will sit in your controller in this case and will have access to the username\password. You need to perform an ajax to check this, but I assume you got the point..
Here's a Fiddle.

Bind dynamic element creation to keypress with AngularJS

I am trying to append an element to the DOM from user text input using AngularJS.
The desired behaviour is:
User types string into input ng-model "newTask"
Presses enter key
Dynamic element is then appended to the DOM
The relevant section of HTML is as follows:
<div class="add-task">
<input type="text" placeholder="Type then press enter to create task" ng-model="newTask" />
</div>
<div class="task-list">
<a class="task"><span class="text">{{ newTask }}</span></a>
</div>
Currently the HTML is instantly updated. How can I bind this event to only happen after enter keypress? The AngularJS UI is also loaded.
Many appreciations,
an AngularJS newbie
Try creating a temp value
Html:
<input type="text" placeholder="Type then press enter to create task" ng-model="tmpTask" ng-keypress="saveTask($event)" />
Your ng-model binds to a tmpTask property. Only when enter is pressed, save it back to newTask
JS:
app.controller('MainCtrl', function($scope) {
$scope.saveTask = function (event){
if (event.keyCode == 13){
$scope.newTask = $scope.tmpTask;
}
}
});
DEMO
html
<form ng-submit="createTask()">
<input type="text" ng-model="newTaskText" />
</form>
<div ng-repeat="task in tasks">{{ task.text }}</div>
controller
$scope.tasks = [];
$scope.createTask = function() {
$scope.tasks.push({
text: $scope.newTaskText
});
};
Since one of the other answers addresses the ng-keypress, I'll offer up the fact you don't need to use the ng-keypress event but can just watch the variable instead which negates the need for enter:
http://plnkr.co/edit/osFGRtpHG46bMyp15mc8?p=preview
app.controller('MainCtrl', function($scope) {
$scope.taskList = [];
$scope.$watch('newTask', function(newVal){
if (newVal=="newTask") {
$scope.taskList.push("Task " + $scope.taskList.length);
$scope.newTask = null;
}
});
});
<body ng-controller="MainCtrl">
<div class="add-task">
<input type="text" placeholder="Type then press enter to create task" ng-model="newTask" />
</div>
{{taskList.length}}
<div class="task-list" >
<a class="task" ng-repeat="task in taskList" ><span class="text">{{ task }} </span></a>
</div>
</body>

Resources