Get all dirty form fields by table row in AngularJS - angularjs

I have a form that is rendered inside of an HTML table using AngularJS, similar to:
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<form name="inputData" id="inputData" ng-submit="submit()">
<table class="table">
<tr>
<th>Name</th>
<th>Employees</th>
<th>Head Office</th>
</tr>
<tr ng-repeat="company in companies">
<td>
<input type="text" ng-model="company.name" />
</td>
<td>
<input type="text" ng-model="company.employees" />
</td>
<td>
<input type="text" ng-model="company.headoffice" />
</td>
</tr>
</table>
<input type="submit"/>
</form>
</div>
</div>
Users can edit the values in the form. When the form is submitted, I'd like to get the $index of the row(s) that were edited. That way I can access the full row from the model via $scope.companies[$index] (which is going to get POSTed to a server).
I know I can check individual fields for the $dirty property. But is there a way I can retrieve the row number? Or better yet, a way I can retrieve all fields in the edited rows?
Here's a fiddle where, right now, I'm just highlighting the dirty fields using CSS: https://jsfiddle.net/jmg157/kzxeL0yw/2/
Thanks for any and all help!

You can try something like this ( using angular.equals) :
var app = angular.module("myApp", []);
app.controller("MyCtrl", ["$scope", function($scope) {
$scope.companies = [{
name: "Infosys Technologies",
employees: 125000,
headoffice: "Bangalore"
}, {
name: "Cognizant Technologies",
employees: 100000,
headoffice: "Bangalore"
}, {
name: "Wipro",
employees: 115000,
headoffice: "Bangalore"
}];
$scope.orginalCompanies = angular.copy($scope.companies);
$scope.submit = function() {
$scope.changedIndex = [];
if(angular.equals($scope.orginalCompanies, $scope.companies)){
console.log('NOthing is changed');
}else{
angular.forEach($scope.companies, function(value, key) {
if(!angular.equals(value, $scope.orginalCompanies[key])){
$scope.changedIndex.push(key);
}
});
console.log("changed Index:=>");
console.log($scope.changedIndex);
}
}
}]);
input.ng-dirty {
background-color: #ff0000;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<form name="inputData" id="inputData" ng-submit="submit()">
<table class="table">
<tr>
<th>Name
</th>
<th>Employees
</th>
<th>Head Office
</th>
</tr>
<tr ng-repeat="company in companies">
<td>
<input type="text" ng-model="company.name" />
</td>
<td>
<input type="text" ng-model="company.employees" />
</td>
<td>
<input type="text" ng-model="company.headoffice" />
</td>
</tr>
</table>
<input type="submit"/>
</form>
</div>
</div>

You can simply use ng-change directive:
angular.module("myApp", []).controller("MyCtrl", ["$scope", function($scope) {
$scope.companies = [{
name: "Infosys Technologies",
employees: 125000,
headoffice: "Bangalore"
}, {
name: "Cognizant Technologies",
employees: 100000,
headoffice: "Bangalore"
}, {
name: "Wipro",
employees: 115000,
headoffice: "Bangalore"
}];
$scope.submit = function() {
console.log($scope.inputData);
}
$scope.logs = [];
$scope.logDirty = function(key, $index) {
var message = 'company[' + $index + '].' + key + 'is dirty';
if ($scope.logs.indexOf(message) == -1)
$scope.logs.push(message);
}
}]);
input.ng-dirty {
background-color: #ff0000;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<form name="inputData" id="inputData" ng-submit="submit()">
<table class="table">
<tr>
<th>Name
</th>
<th>Employees
</th>
<th>Head Office
</th>
</tr>
<tr ng-repeat="company in companies" ng-init='parentIndex=$index'>
<td ng-repeat='(key, val) in company'>
<input ng-change='logDirty(key, parentIndex)' type="text" ng-model="company[key]" />
</td>
</tr>
</table>
<input type="submit" />
<ul ng-if='logs.length > 0'>
<li ng-repeat='log in logs'>{{log}}</li>
</ul>
</form>
</div>
</div>

Related

How to Add and Edit and Delete table data using Angular Js?

I would like to Add and Edit and Delete table list data.
With my knowledge I was able to write the below code for adding a new user and I don't know how to perform the edit and delete operation.
I searched lot in google but did not get proper solution.
Can some one help me please?
index.html:-
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body ng-app="myApp" ng-controller="userCtrl">
<div class="w3-container">
<h3>Users</h3>
<table class="w3-table w3-bordered w3-striped">
<tr>
<th>Edit</th>
<th>First Name</th>
<th>Last Name</th>
</tr>
<tr ng-repeat="user in users">
<td>{{ user.fName }}</td>
<td>{{ user.lName }}</td>
<td>
<button class="w3-btn w3-ripple" ng-click="editUser()">Edit</button>
</td>
<td>
<button class="w3-btn w3-ripple" ng-click="deleteUser()">Delete</button>
</td>
</tr>
</table>
<br></br>
<h3>Create New User</h3>
<form>
<label>First Name:</label>
<input class="w3-input w3-border" type="text" ng-model="fName" placeholder="First Name">
<br>
<label>Last Name:</label>
<input class="w3-input w3-border" type="text" ng-model="lName" placeholder="Last Name">
<br></br>
<button class="w3-btn w3-green w3-ripple" ng-click="addUser()">Save Changes</button>
</form>
</div>
<script src= "myUsers.js"></script>
</body>
</html>
myUsers:-
angular.module('myApp', []).controller('userCtrl', function($scope) {
$scope.users = [
{id:1, fName:'Hege', lName:"Pege" },
{id:2, fName:'Kim', lName:"Pim" },
{id:3, fName:'Sal', lName:"Smith" },
{id:4, fName:'Jack', lName:"Jones" },
{id:5, fName:'John', lName:"Doe" },
{id:6, fName:'Peter',lName:"Pan" }
];
$scope.addUser=function(){
$scope.users.push({
'fName':users.fName,
'lName':users.lName,
});
}
$scope.editUser=function(){
}
$scope.deleteUser=function(){
}
});
Please check the tutorial from here.
For your reference use following code and check the codepen to here.
In template
<tr ng-repeat="user in users">
<td>
<span ng-if="!user.editFlag">{{ user.fName }}</span>
<input ng-if="user.editFlag" ng-model="user.fName"/>
</td>
<td>
<span ng-if="!user.editFlag">{{ user.fName }}</span>
<input ng-if="user.editFlag" ng-model="user.lName"/>
</td>
<td>
<button class="w3-btn w3-ripple" ng-click="editUser($index)"><span ng-if="!user.editFlag">Edit<span><span ng-if="!user.editFlag">Save</span></button>
</td>
<td>
<button class="w3-btn w3-ripple" ng-click="deleteUser($index)">Delete</button>
</td>
</tr>
In your controller
// edit data
$scope.editUser = function (index) {
if($scope.users.length){
// its checking with your edit flag to save or edit
$scope.users[index].editFlag = !$scope.users[index].editFlag;
}
};
// Delete data
$scope.deleteUser = function (index) {
// Remove from main records (using index)
if($scope.users.length){
$scope.users.splice(index, 1);
}
};
Please check this sample to here.
Hopes this will help you !!
These changes will make addUser functionality work
$scope.addUser=function(index){
if(index){
$scope.users[index].fName=$scope.fName;
$scope.users[index].lName=$scope.lName;
}
else{
$scope.users.push({
'fName':$scope.fName,
'lName':$scope.lName,
});
}
$scope.editMode=false;
$scope.fName='';
$scope.lName='';
}
$scope.editUser=function(index){
$scope.editMode=true;
$scope.editIndex=index;
$scope.fName=$scope.users[index].fName;
$scope.lName=$scope.users[index].lName;
}
$scope.deleteUser=function(index){
$scope.users.splice(index,1)
}
Here is working version of above problem
with changes in html and js code
https://embed.plnkr.co/ecKSDwW2hfU9t7cj4rZP/

angularjs checkbox with ng-repeat

i want to make something like this
angularjs-checkbox
this is my code
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head></head>
<script>
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.records = [
"ALL",
"KOREAN",
"ENGLISH",
"CHINESE",
"JAPANESE",
"GERMAN",
"FRENCH",
"ITALIAN",
"SPANISH",
"OTHERS",
]
});
</script>
<body class="other_page" ng-app="myApp">
<table class="checkbox_table" ng-controller="myCtrl">
<tr>
<td colspan="3" class="filter_subtitle_td">
<div class="filter_subtitle">
<span>
CATEGORY
</span>
</div>
</td>
</tr>
<tr ng-repeat="x in records" ng-if="$index % 3 == 0">
<td class="checkbox_td">
<input type="checkbox" id="{{records[$index]}}" class="category_filter_checkbox" ng-model="all" />
<label for="{{records[$index]}}" class="checkbox_label">
{{records[$index]}}
</label>
</td>
<td class="checkbox_td" ng-if="x != ''">
<input type="checkbox" id="{{records[$index + 1]}}" class="category_filter_checkbox" ng-checked="all" />
<label for="{{records[$index + 1]}}" class="checkbox_label">
{{records[$index + 1]}}
</label>
</td>
<td class="checkbox_td" ng-if="x != ''">
<input type="checkbox" id="{{records[$index + 2]}}" class="category_filter_checkbox" ng-checked="all" />
<label for="{{records[$index + 2]}}" class="checkbox_label">
{{records[$index + 2]}}
</label>
</td>
</tr>
</table>
</body>
</html>
my questions is:
how to make ng-repeat stop when no data left?
how to give only 'ALL' data ng-model so the other checkbox can be selected by click this 'ALL' checkbox?
Thank you for your help
I think you chose too complicated way.
To simplify you can use lodash.com or underscorejs and split array to chunks as: $scope.records = _.chunk(data, 3);
So output will be:
[[{"type":"ALL","value":false},{"type":"KOREAN","value":false},{"type":"ENGLISH","value":false}],[{"type":"CHINESE","value":false},{"type":"JAPANESE","value":false},{"type":"GERMAN","value":false}],[{"type":"FRENCH","value":false},{"type":"ITALIAN","value":false},{"type":"SPANISH","value":false}],[{"type":"OTHERS","value":false}]]
Further, to make checkboses to work properly with ng-model we need pass not primitive but objects as {type:<NAME>, value:true/false}:
var data = [
{type:"ALL",value:false},
{type:"KOREAN",value:false},
{type: "ENGLISH",value:false},
{type: "CHINESE",value:false},
{type:"JAPANESE",value:false},
{type: "GERMAN",value:false},
{type:"FRENCH",value:false},
{type:"ITALIAN",value:false},
{type:"SPANISH",value:false},
{type:"OTHERS",value:false}
];
$scope.all = angular.copy(data[0]);
$scope.records = _.chunk(data, 3);
So your HTML will look like:
<table class="checkbox_table" ng-controller="myCtrl">
<tr>
<td colspan="3" class="filter_subtitle_td">
<div class="filter_subtitle">
<span>
CATEGORY
</span>
</div>
</td>
</tr>
<tr ng-repeat="record in records" >
<td ng-repeat="x in record" >
<input type="checkbox" ng-model="all.value" ng-if="x.type === 'ALL'" />
<input type="checkbox" ng-model="x.value" ng-checked="all.value" ng-if="x.type !== 'ALL'" />
<label for="{{x.type}}" ng-if="x.type !== 'ALL'" >{{x.type}}</label>
<label for="{{all.type}}" ng-if="x.type === 'ALL'" >{{x.type}}</label>
</td>
</tr>
</table>
Demo Fiddle

How to clear the value of a particular text box under ng- repeat in angularjs

This is my code structure.Here I have multiple roles and region text boxes accordingly.Now if I entered wrong value then how can I clear that particular text box?
<tbody>
<tr ng-repeat="od in default_role">
<td>{{od.role}}</td>
<td>
<datalist id="all_region_list"> <option data-ng-repeat="or in list_region" value="{{or}}"> </datalist>
<input class="form-control" type="text" data-ng-model="region" list="all_region_list" placeholder="Region" title="Region" ng-keyup='get_region_values("Region");' ng-blur='location_value_check("Region",region,$index)'>
</td>
</tr>
</tbody>
You need to set the model's property (which is connected to the particular textbox) value to ''. So it will clear the textbox.
Demo:
angular.module('myApp', []).controller('ctrl', function($scope) {
$scope.list = [
{
name: 'name1'
},
{
name: 'name2'
},
{
name: 'name3'
},
{
name: 'name4'
}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<div ng-app="myApp" ng-controller="ctrl">
<table>
<tr ng-repeat="item in list">
<td><input type="text" ng-model="item.name" placeholder="name" /></td>
<td><button ng-click="item.name = ''">Clear textbox</button></td>
<td>Model: {{item | json }}</td>
</tr>
</table>
</div>
If you want to just clear the textbox without changing the model:
angular.module('myApp', []).controller('ctrl', function($scope) {
$scope.list = [
{
name: 'name1'
},
{
name: 'name2'
},
{
name: 'name3'
},
{
name: 'name4'
}
];
angular.element(document).ready(function() {
$('button').click(function() {
$(this).parents('tr').first().find('input').val('');
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<div ng-app="myApp" ng-controller="ctrl">
<table>
<tr ng-repeat="item in list">
<td><input type="text" ng-model="item.name" placeholder="name" /></td>
<td><button>Clear textbox</button></td>
<td>Model: {{item | json }}</td>
</tr>
</table>
</div>

dropdown selected value use only once on add button in angular js

Selected value from the drop down should be added when I click on add button, only once the value should be added to the result field. Some once can help me on this. below is code which i tried.
function ContactController($scope) {
$scope.contacts = ["Apple"];
$scope.curItem = [{
id: "1",
items: "Apple"
}, {
id: "2",
items: "Orange"
}, {
id: "3",
items: "Banana"
}, {
id: "4",
items: "Apricot"
}, {
id: "5",
items: "Asparagus"
}, ];
$scope.selectedItem = $scope.curItem[0];
}
View :
<table class="range-table" width="100%">
<tr>
<td>
<input type="hidden">
<button class="btn btn-link" value= "Save">
<span class="glyphicon glyphicon-plus"></span>
</button>
</td>
<td>
<select required="" style="min-width:180px;"> </select>
</td>
</tr>
</table>
<table class="range-table" width="100%">
<tr>
<td ng-repeat="contact in contacts"> <td>{{ contact }}</td>
</tr>
</table>
HTML:
<body ng-controller="MainCtrl">
<table class="range-table" width="100%">
<tr>
<td><input type="hidden"> <button class="btn btn-link" ng-click="save(selectedItem)">Save</button> </td>
<td><select ng-model="selectedItem" ng-options="i.items as i.items for i in curItem" ng-init="selectedItem=curItem[0].id"></select></td> </tr>
</table>
<table class="range-table" width="100%">
<tr>
<tr ng-repeat="contact in contacts track by $index">
<td>{{ contact }}</td>
</tr>
</table>
</body>
Javascript (your controller code):
app.controller('MainCtrl', function($scope) {
$scope.contacts = ["Apple"];
$scope.curItem=[{id:"1",items:"Apple"}, {id:"2",items:"Orange"}, {id:"3",items:"Banana"}, {id:"4",items:"Apricot"}, {id:"5",items:"Asparagus"}];
$scope.save=function(i){
if ($scope.contacts.indexOf(i) <= -1){
$scope.contacts.push(i);
}
};
});
Here is the working Plunker
Edit: It seems that you want to add value only once. I've edited my answer and plunker.
I have created a plunker
Textbox should be enabled on click of other option radio button is checked
JS:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.$watch('form.Program', function(mVal){
if (angular.isUndefined($scope.form)) return;
if(mVal === 'other'){
$scope.form.OtherProgram = $scope.tmVar;
} else {
if($scope.form.OtherProgram !== null){
$scope.tmVar = $scope.form.OtherProgram;
$scope.form.OtherProgram = null;
}
}
});
});
HTML:
<body ng-controller="MainCtrl">
<p>
Program:
<label><input type="radio" ng-model="form.Program" name="Program" value="option 1" required /> option 1</label>
<label><input type="radio" ng-model="form.Program" name="Program" value="option 2" required /> option 2</label>
<label><input type="radio" ng-model="form.Program" name="Program" value="other" required /> other</label>
<input type="text" ng-model="form.OtherProgram" ng-disabled="form.Program != 'other'" name="Program_Other" ng-required ="form.Program != 'other'"/>
</p>
</body>

How to add the object values into table using angularjs

var app = angular.module("myapp", ["ngSanitize"]);
app.controller("controller", ['$scope', function($scope) {
$scope.tasks = [{
item: "Shopping",
status: true
}, {
item: "Cleaning",
status: false
}];
}]);
and html
<div ng-app="myapp">
<div ng-controller='controller'>
<table border=1 ng-repeat='task in tasks'>
<tr>
<td>{{task.item}}</td>
<td>{{task.status}}</td>
</tr>
</table>
</div>
</div>
I tried as above but i could not able to attach header to the table.And at the place of Done I am tring to attach a checkbox...I mean if status is true the chexk box must be checked or else unchecked.
Output:
Item Done
Shopping checkbox with ticked
Cleaning checkbox without ticked
See documentation for checkbox input
Not exactly the answer, but why do you repeat table instead of rows?
<div ng-app="myapp">
<div ng-controller='controller'>
<table border=1 >
<tr>
<th>Name</th>
<th>Status</th>
</tr>
<tr ng-repeat='task in tasks'>
<td>{{task.item}}</td>
<td><input type="checkbox" ng-model="task.status"></td>
</tr>
</table>
</div>
</div>
But I don't see any sense in table in your case.
<span ng-repeat="task in tasks">
<input type="checkbox" ng-model="task.status"> {{task.item}}
</span>
That would be much cleaner.
Do changes as follows in the HTML.
<body ng-app="myapp" ng-controller="ListController">
<table border="1" ng-repeat='task in tasks'>
<tr>
<td>
{{task.item}}
</td>
<td>
<input type="checkbox" ng-model="task.status">
</td>
</tr>
</table>
</body>
Do changes in the Angular js as follows.
var app = angular.module("myapp", []);
app.controller("ListController", ['$scope', function($scope) {
$scope.tasks = [{
item: "Shopping",
status: true
}, {
item: "Cleaning",
status: false
}];
}]);

Resources