Angular-Formly : Adding Form fields dynamically on user click - angularjs

How would I go about adding the capability in the form so that the user can add more input fields by clicking the "Add". This using the angular formly library.
Here is an example of the exact feature but done using only angularjs.
Adding form fields dynamically

See this Plunker
Here is an example of what you need. As you can see in the plunker, there is a TextArea which can be created dynamically on button click. The created TextAreas can also be removed with the remove button click.
See the HTML below
<div class="col-sm-10">
<input type="button" class="btn btn-info" ng-click="addNewChoice()" value="ADD QUESTION">
<div class="col-sm-4">
<fieldset data-ng-repeat="field in choiceSet.choices track by $index">
<textarea rows="4" cols="50" ng-model=" choiceSet.choices[$index]"></textarea>
<button type="button" class="btn btn-default btn-sm" ng-click="removeChoice($index)">
<span class="glyphicon glyphicon-minus"></span> REMOVE
</button>
</fieldset>
</div>
</div>
and the JS will be as below
var app = angular.module('myApp', []);
app.controller('inspectionController', function($scope, $http) {
$scope.choiceSet = {
choices: []
};
$scope.quest = {};
$scope.choiceSet.choices = [];
$scope.addNewChoice = function() {
$scope.choiceSet.choices.push('');
};
$scope.removeChoice = function(z) {
$scope.choiceSet.choices.splice(z, 1);
};
});

I put simple example.
var app = angular.module("app",[]);
app.controller("MyCtrl" , function($scope){
$scope.data ={
names:[{ name:""}]
};
$scope.addRow = function(index){
var name = {name:""};
if($scope.data.names.length <= index+1){
$scope.data.names.splice(index+1,0,name);
}
};
$scope.deleteRow = function($event,name){
var index = $scope.data.names.indexOf(name);
if($event.which == 1)
$scope.data.names.splice(index,1);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="MyCtrl">
<table>
<tr ng-repeat="name in data.names track by $index">
<td> <input type="text" ng-model="data.names[$index].name"></td>
<td> <input type="button" ng-click="addRow($index)" value="Add" ng-show="$last"></td>
<td> <input type="button" ng-click="deleteRow($event,name)" value="Delete" ng-show="$index != 0"></td>
</tr>
</table>
<span>{{data|json}}</span>
</div>

Simple example works also deleting in any order:
http://plnkr.co/edit/c0FbjBJkHtDYRKslz0iq?p=preview
or:
some html:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="oneApp" ng-controller="ctrl">
<button ng-click="addNewRow()">Add row</button>
<table>
<tr ng-repeat="row in tablerows track by $id(row)">
<td ng-model="tablerows[$index]">
<input>
</td>
<td>
<button ng-click="removeRow($index)" type="button">
Delete
</button>
<td>
</tr>
</table>
</body>
</html>
script.js:
var app = angular.module('oneApp', []);
app.controller('ctrl', function($scope){
$scope.tablerows = [];
$scope.addNewRow = function () {
var row_id;
var tablerows = $scope.tablerows;
if(tablerows.length > 0){
row_id = tablerows[tablerows.length-1];
row_id = row_id +1;
}else{
row_id = 0;
}
$scope.tablerows.push(row_id);
};
$scope.removeRow = function (index) {
$scope.tablerows.splice(index,1);
};
}
);

Related

angularjs form validation. TypeError: Cannot read property '$valid' of undefined

I need to save data(Save button) in local storage but before I must validate form. after invoking SavelocalStorage function have a mistake TypeError: Cannot read property '$valid' of undefined. what's wrong? any help appreciated
ps if $scope.myForm.$valid replace for myForm.$valid validation works but inappropriate way. even after fill in all the gaps still popup alert warning.
in case of removing data validation it is all right with LS data saving
var app = angular.module("myApp",['listOfBooks']);
app.controller("myCtrl", function($scope){
$scope.authors = [];
$scope.addAuthor = function(){
var author = {};
author.surname = "";
author.name = "";
$scope.authors.push(author);
};
$scope.SavelocalStorage = function(){
if($scope.myForm.$valid){
localStorage.setItem('Authors', JSON.stringify($scope.authors));
}
else{
alert("fill in all the gaps pls!");
}
};
});
var app = angular.module("listOfBooks", []);
app.controller("booksCtrl", function($scope) {
$scope.showBooks = false;
$scope.currentAuthor = {};
$scope.showBookList = function(author) {
$scope.showBooks = !$scope.showBooks;
$scope.currentAuthor = author;
}
$scope.addBook = function() {
$scope.currentAuthor.books = $scope.currentAuthor.books || [];
var book = {};
book.title = "";
$scope.currentAuthor.books.push(book);
};
});
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body ng-app="myApp" ng-controller="myCtrl">
<div class="container">
<h3>AUTHORS' LIST</h3>
<div class="btn-group">
<button ng-click="addAuthor()" type="button" class="btn btn-default">Add</button>
<button ng-click="SavelocalStorage()" type="button" class="btn btn-default">Save</button>
</div>
<form ng-controller="booksCtrl" name="myForm">
<table class="table table-bordered">
<tr>
<th>Surname</th>
<th>Name</th>
<th>Books</th>
</tr>
<tr ng-repeat="author in authors">
<td><input ng-model="author.surname" required type="text" class="form-control"></td>
<td><input ng-model="author.name" required type="text" class="form-control"></td>
<td>
<button ng-click="showBookList(author)" type="button" class="btn btn-default">List</button>
</td>
</tr>
</table>
<div ng-show="showBooks" class="col-sm-8" style="background-color:lightblue; position: absolute; left:5px; top:5px;z-index:2;">
<div class="btn-group">
<button ng-click="addBook()" type="button" class="btn btn-default">Add</button>
</div>
<table class="table table-bordered">
<tr>
<th>Title</th>
</tr>
<tr ng-repeat="book in currentAuthor.books">
<td><input ng-model="book.title" type="text" class="form-control"></td>
</tr>
</table>
<button class="btn btn-sm btn-warning" ng-click="showBooks = false">Close</button>
</div>
</form>
</div>
</body>
</html>
You need to play with $scope inheritance a little bit, When you use controllerAs syntax with the parent controller, If you set the name of form inside booksCtrl to vm.myForm, the form get registered to parent $scope because of prototypical inheritance of JavaScript, and you can call validation on the form in parent $scope.
var app = angular.module("myApp",['listOfBooks']);
app.controller("myCtrl", function($scope){
$scope.authors = [];
var vm = this;
$scope.addAuthor = function(){
var author = {};
author.surname = "";
author.name = "";
$scope.authors.push(author);
};
$scope.SavelocalStorage = function(){
if(vm.myForm.$valid){
localStorage.setItem('Authors', JSON.stringify($scope.authors));
}
else{
alert("fill in all the gaps pls!");
}
};
});
var app = angular.module("listOfBooks", []);
app.controller("booksCtrl", function($scope) {
$scope.showBooks = false;
$scope.currentAuthor = {};
$scope.showBookList = function(author) {
$scope.showBooks = !$scope.showBooks;
$scope.currentAuthor = author;
}
$scope.addBook = function() {
$scope.currentAuthor.books = $scope.currentAuthor.books || [];
var book = {};
book.title = "";
$scope.currentAuthor.books.push(book);
};
});
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body ng-app="myApp" ng-controller="myCtrl as vm">
<div class="container">
<h3>AUTHORS' LIST</h3>
<div class="btn-group">
<button ng-click="addAuthor()" type="button" class="btn btn-default">Add</button>
<button ng-click="SavelocalStorage()" type="button" class="btn btn-default">Save</button>
</div>
<form ng-controller="booksCtrl" name="vm.myForm">
<table class="table table-bordered">
<tr>
<th>Surname</th>
<th>Name</th>
<th>Books</th>
</tr>
<tr ng-repeat="author in authors">
<td><input ng-model="author.surname" required type="text" class="form-control"></td>
<td><input ng-model="author.name" required type="text" class="form-control"></td>
<td>
<button ng-click="showBookList(author)" type="button" class="btn btn-default">List</button>
</td>
</tr>
</table>
<div ng-show="showBooks" class="col-sm-8" style="background-color:lightblue; position: absolute; left:5px; top:5px;z-index:2;">
<div class="btn-group">
<button ng-click="addBook()" type="button" class="btn btn-default">Add</button>
</div>
<table class="table table-bordered">
<tr>
<th>Title</th>
</tr>
<tr ng-repeat="book in currentAuthor.books">
<td><input ng-model="book.title" type="text" class="form-control"></td>
</tr>
</table>
<button class="btn btn-sm btn-warning" ng-click="showBooks = false">Close</button>
</div>
</form>
</div>
</body>
</html>

After injecting $http, code is not displaying the table in angular.js

I am a beginner in anular.js. I'm trying to write a code which add and removes rows in a table on button click and once done ad user clicks on createdelivery button I want to send the data as a JSON object to server.
But when am injecting $http as follows,
var app = angular.module("createDelivery", []);
app.controller("MyController", ['$scope', 'http', function($scope, $http)
it doesn't create the table also.
Please help me to solve the issue.
<html>
<head>
<title>Add Rows</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script>
var app = angular.module("createDelivery", []);
app.controller("MyController", ['$scope', 'http', function($scope, $http) {
$scope.deliveryDetails = [
{
'fname':'Muhammed',
'lname':'Shanid',
'email':'shanid#shanid.com'
},
{
'fname':'Roy',
'lname':'Mathew',
'email':'roy#roy.com'
}];
$scope.addNew = function(cdDetails){
$scope.deliveryDetails.push({
'fname': "",
'lname': "",
'email': "",
});
};
$scope.remove = function(){
var newDataList=[];
$scope.selectedAll = false;
angular.forEach($scope.deliveryDetails, function(selected){
if(!selected.selected){
newDataList.push(selected);
}
});
$scope.deliveryDetails = newDataList;
};
$scope.checkAll = function () {
if (!$scope.selectedAll) {
$scope.selectedAll = true;
} else {
$scope.selectedAll = false;
}
angular.forEach($scope.deliveryDetails, function(cdDetails) {
cdDetails.selected = $scope.selectedAll;
});
};
$scope.getData = function(cdDetails)
{
alert("Check");
var jsonString;
jsonString = angular.toJson(cdDetails);
//JSON.stringify(jsonString);
$http
({
url: "/scheduler/createDelivery",
dataType: 'json',
method: 'POST',
data: jsonString
}).success(function(response) {
alert("success : : "+jsonString);
$scope.value = response;
}).error(function(error) {
alert("error::"+error);
});
//window.location.reload();
//document.write("\nString value "+jsonString);
};
}]);
</script>
</head>
<body ng-app="createDelivery" ng-controller="MyController">
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-body">
<form ng-submit="addNew()">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th><input type="checkbox" ng-model="selectedAll" ng-click="checkAll()" /></th>
<th>Firstname</th>
<th>Lastname</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="cdDetails in deliveryDetails">
<td>
<input type="checkbox" ng-model="cdDetails.selected"/></td>
<td>
<input type="text" class="form-control" ng-model="cdDetails.fname" required/></td>
<td>
<input type="text" class="form-control" ng-model="cdDetails.lname" required/></td>
<td>
<input type="email" class="form-control" ng-model="cdDetails.email" required/></td>
</tr>
</tbody>
</table>
<div class="form-group">
<input ng-hide="!deliveryDetails.length" type="button" class="btn btn-danger pull-right" ng-click="remove()" value="Remove">
<input type="submit" class="btn btn-primary addnew pull-right" value="Add New">
<button type="button" name = "createDelivery"class="col-sm-2 btn btn-primary" style="width:25%" ng-click="getData(cdDetails);">Create Delivery</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
app.controller("MyController", ['$scope', 'http'
One mistake in code is above. Change it and try. you must inject $http

Is this possible to assign ng-model value from anchor rag(<a ../>)

My question is
when I click the edit link in the table model-dialog want to open and its
value should be assigned in there field. Here dialog will opening but the
value will not getting initialized.
<div ng-app="myapp" ng-controller="myctrl">
<form method="POST" action="Projects" >
<div class="modal fade" id="update" role="dialog" >
<div class="modal-dialog">
<label for="Project_Id"> Project Id</label>
<input readonly="readonly" ng-model=project_id class="form-control"
id="project_id" value="" />
</div>
</div>
</form>
MY question is
when I click the edit link in the table model-dialog want to open and its
value should be assigned in there field. Here dialog will opening but the
value will not getting initialized.
<table>
<thead><tr><td> Edit </td></tr></thead>
<tbody>
<tr ng-repeat="values in records ">
<td>
<a data-toggle="modal" ng-model=values.projectId
ng-href="#update"</td>
</tr>
</tbody>
</table>
</div>
<script type="text/javascript">
var app = angular.module('myapp', []);
app.controller('myctrl', function($scope, $http) {
$http.get('Projects').success(function (data) {
$scope.records = data;
$scope.project_id=$scope.data.projectId;
// $scope.project_id="some value" ...if i remove this comment it is working properly some value will be shown, but I need particular record data.projectId should be displayed
});
</script>
Try the following:
Put an ng-click on your tag like so:
<a data-toggle="modal" ng-model= values.projectId ng-click="viewRecord(values.projectid)"></a>
In your Angular Controller:
$scope.selected = {
records:[]
};
$scope.viewRecord = function(recordId){
$scope.selected.records.push(record)
}
Then on your modal:
<div ng-repeat="r in selected.records">
<div><input type="text" value="r.projectId"></div>
</div>
<table>
<thead><tr><td> Edit </td></tr></thead>
<tbody>
<tr ng-repeat="record_values in records ">
<td>
<a data-toggle="modal" ng-click='disp(record_values)'
ng-href="#update"</td>
</tr>
</tbody>
</table>
</div>
<script type="text/javascript">
var app = angular.module('myapp', []);
app.controller('myctrl', function($scope, $http) {
$http.get('Projects').success(function (data) {
$scope.records = data;
$scope.disp=function( record)
{
$scope.project_description=record.projectId;
};
});
</script>

How to bind the data using ng-model in table row (inline editing)

I have 3 values in an object empID,empName,empEmail like this
my problem is in the function gettemplete function(),
var app = angular.module('myApp' , []);
app.controller('myCtrl' , function($scope){
$scope.count=0;
$scope.employees = [{empID:$scope.count+1,empName:'lin',empEmail:'b#1.in'},{empID:$scope.count+1,empName:'test',empEmail:'aaa#3.com'}];
$scope.employeeData = {};
$scope.selected = {};
$scope.addEmployee = function(){
$scope.employees.push({
empName : $scope.empName,
empEmail : $scope.empEmail
});
console.log($scope.employees);
};
$scope.deleteEmployee = function(employee){
var index = $scope.employees.indexOf(employee);
$scope.employees.splice(index,1);
console.log($scope.employees);
};
$scope.getTemplate = function (employee) {
if (employee.empID === $scope.selected.empID){
console.log(employee.empID);
console.log($scope.selected.empID);
console.log("edit");
return 'edit';
}
else {
console.log("display");
console.log(employee.empID);
console.log($scope.selected.empID);
return 'display';
}
};
$scope.reset = function () {
$scope.selected = {};
console.log($scope.selected);
};
$scope.add = function(){
$scope.addEmployee();
};
$scope.editEmployee = function (employee) {
$scope.selected = angular.copy(employee);
console.log($scope.selected);
console.log(employee);
console.log($scope.selected);
};
$scope.updateEmployee = function(employee) {
$scope.employees.push({
empName : $scope.empName,
empEmail : $scope.empEmail
});
console.log($scope.employees);
$scope.getTemplate();
$scope.reset();
};
});
Here goes my html code
<body ng-controller="myCtrl">
<div>
<h3>List Employees</h3>
<table class="table table-striped table-bordered">
<thead>
<th>empID</th>
<th>Employee Name</th>
<th>Employee Email</th>
<th>Action</th>
</thead>
<tbody>
<tr ng-repeat="employee in employees" ng-include="getTemplate(employee)">
<script type="text/ng-template" id="display">
<td>{{employee.empID}}</td>
<td>{{employee.empName}}</td>
<td>{{employee.empEmail}}</td>
<td>
<button type="button" class="btn btn-primary" ng-click="editEmployee(employee)">Edit</button>
<button type="button" class="btn btn-danger" ng-click="deleteEmployee(employee)">Delete</button>
</td>
</script>
<script type="text/ng-template" id="edit">
<td>{{employee.empID+ 1}}</td>
<td><input type="text" ng-model=employee.empName class="form-control input-sm"/></td>
<td><input type="text" ng-model=employee.empEmail class="form-control input-sm"/></td>
<td>
<button type="button" class="btn btn-primary" ng-click="updateEmployee(employee)">Save</button>
<button type="button" class="btn btn-danger" ng-click="reset()">Cancel</button>
</td>
</script>
</tr>
</tbody>
<table>
<button ng-click="add()"> Add row </button>
</div>
</body>
I am able to display my empName and empEmail but I dont know how to display empID. I have a button called addrow to create a row in the table, so when I click that button I need the empID as counted a 3,4,5,...etc like that.
Try changing your addEmployee function as below.
$scope.addEmployee = function(){
$scope.employees.push({
empId : $scope.count++,
empName : $scope.empName,
empEmail : $scope.empEmail
});
console.log($scope.employees);
};
If you are creating few sample employees, make sure you add them via addEmployee function. That way count increases automatically. However, if you want to statically create some employees, assign count correctly. cheers.
your empId is not a number, its a string
change this
empID:'1'
To this
empID:1
So your array
$scope.employees = [{empID:1,empName:'lin',empEmail:'b#1.in'},{empID:2,empName:'test',empEmail:'aaa#3.com'}];
<input type="number" ng-model="employee.empID" class="form-control input-sm"/>
to increment employeeId you can do like
<button type="button" class="btn btn-primary" ng-click="saveEmployee(employee); empId = empId+1" ng-init="empId=1">Save</button>
Current count = {{empId}}

AngularJS Hide / Show Row with toggle-Button not work

I try to use a toggle-button to show and hide a row of my table. Unfortunately, it does not work and I get no error in the console. Debugging AngularJS is quite hard for a beginner. If I put links between it works. But I need the toggle-Button outside of my table.
Here is the fiddle, which do not work.
fiddle
Thank you!
HTML
<body ng-app="lexoffice" ng:controller="CtrlInvoice">
<table ng-repeat="field in data.fields">
<tbody>
<tr class="trShipping" ng-hide="field.isRowHidden">
<td><input>{{field.shippingcosts}}</input></td>
<td><textarea type="text" ng:model="selectionCurrency"></textarea></td></tr>
</tbody>
</table>
<div class="btn-group btn-group-shipping" data-toggle="buttons">
<label class="btn btn-default shipping-radio">
<input type="radio" class="btn" ng-click="hideShippingCosts(field)">
Hide Row</label>
<label class="btn btn-default shipping-radio">
<input type="radio" class="btn" ng-click="showShippingCosts(field)">
Show Row</label>
</div>
SCRIPT
var myApp = angular.module('lexoffice', []);
function CtrlInvoice($scope) {
$scope.data = {
fields: [{
shippingcosts: 0.00,
isRowHidden: false
}]
};
$scope.hideShippingCosts = function (field) {
field.shippingcosts = 0.00;
field.isRowHidden = true;
}
$scope.showShippingCosts = function (field) {
field.shippingcosts = 0.00;
field.isRowHidden = false;
}
}
So to hide the shipping cost row, you'll want to put the ng-hide on the <tr> with the shipping cost. You also need to repeat the toggle buttons since it seems its per row. Here is the fiddle: http://jsfiddle.net/BAEh2/
updated HTML
<div ng-controller="CtrlInvoice">
<table ng-repeat="field in data.fields">
<tbody>
<tr class="trShipping">
<td ng-hide="field.isRowHidden"><input ng-model="field.shippingcosts"/></td>
<td><textarea type="text" ng-model="selectionCurrency"></textarea></td>
<td>
<div class="btn-group btn-group-shipping" data-toggle="buttons">
<label class="btn btn-default shipping-radio"ng-click="hideShippingCosts(field)" ng-class="{'active': field.isRowHidden}">
<input type="radio" class="btn" />
Hide Row</label>
<label class="btn btn-default shipping-radio" ng-click="showShippingCosts(field)" ng-class="{'!active': field.isRowHidden}">
<input type="radio" class="btn" />
Show Row</label>
</div>
</td>
</tr>
</tbody>
</table>
</div>
update JS (just added more rows to show repeat)
var myApp = angular.module('lexoffice', []);
function CtrlInvoice($scope) {
$scope.data = {
fields: [{
shippingcosts: 1.00,
isRowHidden: false
},
{
shippingcosts: 2.00,
isRowHidden: false
},
{
shippingcosts: 3.00,
isRowHidden: true
}]
};
$scope.hideShippingCosts = function (field) {
field.shippingcosts = 0.00;
field.isRowHidden = true;
};
$scope.showShippingCosts = function (field) {
field.shippingcosts = 0.00;
field.isRowHidden = false;
};
}

Resources