Post data of form created by ng-repeat - angularjs

I have one input field =, one checkbox and one file upload option per row of table and the rows are created by ng-repeat .
<tr data-ng-repeat="choice in choices track by $index">
<td><input type="textbox" size="50" class="des-textinput" required></td>
<td><input type="checkbox" required></td>
<td><input type="file" class="photo-upload" ></td>
</tr>
My question is how to post the datas to backend via one submit button as it is created by ng-repeat and it will be multiple.

For starters bind your inputs to the model using ng-model. Then create a directive that will bind the file input to the model. Lastly, call a function from your submit button that will iterate through the model and call an upload service for each file.
var app = angular.module('uploadApp', []);
app.controller('MainCtrl', function($scope) {
$scope.choices = [{
desc: 'file 1',
include: false,
file: null
}, {
desc: 'file 2',
include: false,
file: null
}, {
desc: 'file 3',
include: false,
file: null
}];
$scope.uploadFiles = function() {
$scope.choices.forEach(f => {
const file = f.file;
if (file) {
// call upload function from here
console.log('Upload: ', file);
}
});
};
});
app.directive("fileInput", function() {
return {
require: "ngModel",
restrict: 'A',
link: function postLink(scope, element, attrs, ngModel) {
element.on("change", function(e) {
var file = element[0].files[0];
ngModel.$setViewValue(file);
});
}
};
});
<!DOCTYPE html>
<html ng-app="uploadApp">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<script data-require="angular.js#1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
</head>
<body ng-controller="MainCtrl">
<table>
<tr data-ng-repeat="choice in choices track by $index">
<td>
<input type="textbox" size="50" class="des-textinput" ng-model="choice.desc" required />
</td>
<td>
<input type="checkbox" required ng-model="choice.include" />
</td>
<td>
<input type="file" class="photo-upload" ng-model="choice.file" file-input/>
</td>
</tr>
</table>
<button ng-click="uploadFiles()">Submit</button>
</body>
</html>

Related

Angular JS Controller not rendering table

I am stuck on a problem.
I want to take first and last names as Input show them as full names and add them separately on a table by push method. Full name function is working properly but another controller is either not working or showing the results.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.8.3/angular.min.js"
integrity="sha512-KZmyTq3PLx9EZl0RHShHQuXtrvdJ+m35tuOiwlcZfs/rE7NZv29ygNA8SFCkMXTnYZQK2OX0Gm2qKGfvWEtRXA=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<form name="myForm" ng-submit="addRow()">
First Name: <input type="text" name="fname" ng-model="firstName"><br>
Last Name: <input type="text" name="lname" ng-model="lastName"><br>
<input type="submit" value="Submit"><br>
</form>
<p> Full Name: {{fullName()}}</p>
<div ng-controller="tableCtrl">
<table>
<tr>
<th>First Name</th>
<th>Last Name</th>
</tr>
<tr ng-repeat="x in records">
<td>{{x.firstName}}</td>
<td>{{x.lastName}}</td>
</tr>
</table>
</div>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function ($scope) {
$scope.firstName = myForm.fname.value;
$scope.lastName = myForm.lname.value;
$scope.fullName = function () {
return $scope.firstName + " " + $scope.lastName;
};
});
app.controller('tableCtrl', ['$scope', function ($scope) {
$scope.records = [];
$scope.addRow = function () {
$scope.records.push({
'firstName': $scope.firstName,
'lastName': $scope.lastName
});
};
}]);
</script>
</body>
</html>
This is the code of the index.html file I am using Angular js with a CDN link.

AngularJS Multi-level forms

I am kind of new to AngularJS and is now facing with an issue. When I browse the solution and select an item from any category it updates the all the sections textboxes with the result instead of the on intended section.
If I have only one section then everything is perfectly fine but the moment I have more than one section, then everything goes for a toss. I know this is because of the $scope variable currentItem. I am not sure how I can solve this issue.
Any light thrown to solve the issue is highly appreciated. Thank you in advance.
HTML Page [default.htm]
<html ng-app="myapp" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Untitled Page</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular-route.min.js"></script>
</head>
<body>
<div ng-view>
</div>
<script src="myapp.js" type="text/javascript"></script>
</body>
</html>
JavaScript [myapp.js]
var app = angular.module('myapp', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/home', {
templateUrl : 'partials/Home.htm',
controller : 'HomeController'
})
.otherwise({redirectTo: '/home'});
});
app.controller('HomeController', function($scope,$sce, $http, $location, $rootScope) {
$scope.datas = [
{
"category":"First Category",
"items":[
{
"itemCode":"001",
"itemDescription":"Item 01"
},
{
"itemCode":"002",
"itemDescription":"Item 02"
}
]
},
{
"category":"Second Category",
"items":[
{
"itemCode":"004",
"itemDescription":"Item 04"
},
{
"itemCode":"005",
"itemDescription":"Item 05"
}
]
}
];
$scope.selectItem = function(parentindex, index){
$scope.currentItem = $scope.datas[parentindex].items[index];
}
});
Partial Page [partials/Home.htm]
<div ng-repeat='data in datas'>
<table>
<tr>
<td>
{{data.category}} Items
</td>
</tr>
<tr ng-repeat='item in data.items' ng-click='selectItem($parent.$index, $index)'>
<td>
{{item.itemDescription}}
</td>
</tr>
</table>
<table>
<tr>
<td>
Code:
</td>
<td>
<input ng-model='currentItem.itemCode' type="text" />
</td>
</tr>
<tr>
<td>
Description:
</td>
<td>
<input ng-model='currentItem.itemDescription' type="text" />
</td>
</tr>
</table>
</div>

Directive not rendering inside ng-repeat

The directive test-dir fails to render
<ul>
<li ng-repeat="person in data">
<table>
<thead>{{person.name}}</thead>
<tbody>
<tr ng-repeat="row in person.entries">
<test-dir data="row"></test-dir>
</tr>
</tbody>
</table>
</li>
</ul>
app.directive("testDir", function(){
return {
restrict: 'EA',
scope: {
data: '='
},
template: "<td>{{data}}</td>"
};
});
It does render when used as an attribute. Not sure why it wouldn't work as an element.
PLNKR: http://plnkr.co/edit/fraBDzt9kjZlUIuV1fDf?p=preview
First, you need to add replace: true to testDir directive.
Otherwise you'll have a <div> inside a <tr> which is why the directive is not rendered when used as element.
However, even with replace: true you will encounter a known bug:
Error: Template must have exactly one root element. was: <td>{{data}}</td>
Better use the directive as attribute.
Just use ng-repeat with directive like <test-dir ng-repeat="row in person.entries" data="row"></test-dir>
So your code will be
<!doctype html>
<html ng-app="plunker" >
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<script>document.write("<base href=\"" + document.location + "\" />");</script>
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.js"></script>
<script>
var app = angular.module('plunker', []);
app.directive("testDir", function(){
return {
restrict: 'EA',
scope: {
data: '='
},
template: "<td>{{data}}</td>"
};
});
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.data = [
{
name: 'cars',
entries: [
{model: 'fiat', speed: 100 },
{model: 'tesla', speed: 200 },
]
},
{
name: 'trucks',
entries: [
{model: 'volvo', speed: 50 },
{model: 'merc', speed: 75 },
]
}
];
});
</script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<ul>
<li ng-repeat="person in data">
<table>
<thead>{{person.name}}</thead>
<tbody>
<tr >
<test-dir ng-repeat="row in person.entries" data="row"></test-dir>
</tr>
</tbody>
</table>
</li>
</ul>
</body>
</html>

How to change template URL at runtime in AngularJS?

I have in app.js
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
// Fetch the data from the API calls
var empDept = GetEmployeeData();
var marFin = GetFinanceData();
var x = 1;
$scope.list = {};
switch(x)
{
case 1: $scope.list = {
EmployeeDepartment: empDept
}; break;
case 2:
$scope.list = {
MarketingFinance: marFin
};break;
}
});
app.directive('myCustomer', function() {
return {
restrict: 'AE',
scope: {
customer: '=myCustomer'
},
replace: true,
templateUrl: 'EmpDept.html'
}
};
});
And my index.html is as under
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<script data-semver="1.3.15" src="https://code.angularjs.org/1.3.15/angular.js" data-require="angular.js#1.3.x"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<label ng-repeat="(key,val) in list">
<div ng-if="key === 'EmployeeDepartment'">
<table border="1">
<tr>
<td><b>EmployeeNames</b></td>
</tr>
<tbody>
<tr ng-repeat="customer in val" my-customer="customer"></tr>
</tbody>
</table>
<script type="text/ng-template" id="EmpDept.html">
<tr>
<td>{{customer.EmpName}}</td>
</tr>
</script>
</div>
<div ng-if="key === 'MarketingFinance'">
<table border="1">
<tr>
<td><b>Product Name</b></td>
<td><b>Price</b></td>
</tr>
<tbody>
<tr ng-repeat="customer in val" my-customer="customer"></tr>
</tbody>
</table>
<script type="text/ng-template" id="MarkFin.html">
<tr>
<td>{{customer.ProductName}}</td>
<td>{{customer.Price}}</td>
</tr>
</script>
</div>
</label>
</html>
Now the problem is that
Depending on the value of the switch case, the templateURL has to be changed.
e.g
if x=1, templateURL = EmpDept.html
if x=2, templateURL = MarkFin.html
Can you please tell how to do it?
N.B.~ I have seen this but could not plug into the application. Any other easy way?
I have added a plunker that allows you to dynamically change the template URL
http://plnkr.co/edit/yG5qEbFORyyNnCdVDOOY?p=preview
You must add the variable that stores the html link to the directive scope as you can see below:
app.directive('myCustomer', function() {
return {
restrict: 'AE',
scope: {
customer: '=myCustomer',
templateHtml: "="
},
replace: true,
template: '<div ng-include="templateHtml"></div>',
link: function(scope, element, attrs) {
}
};
});

How to filter array if filter is in angular directive?

I try to create general directive for filtering array in angular.
<body ng-controller="MainCtrl">
controller: <input type="text" ng-model="query.name" /> - work<br>
directive: <span filter by="name"></span> - not work
<ul>
<li ng-repeat="item in list | filter:query">{{item.name}}</li>
</ul>
</body>
controller and directive are:
app.controller('MainCtrl', function($scope) {
$scope.list = [
{id: 1, name:'aaa'},
{id: 2, name:'bbb'},
{id: 3, name:'ccc'}
];
});
app.directive('filter', function () {
return {
scope: {
by: '#'
},
link: function postLink(scope, element, attrs) {
element.append(
'<input type="text" ng-model="query.' + attrs.by + '">');
}
}
});
Filter in controller works but filter in directive doesn't. I don't know how to fix it.
Solution is fixed in plunker: http://plnkr.co/edit/WLGd6RPQEwMFRBvWslpt?p=preview
Since you have isolated the scopes you have to use eiter $parent or you have to set up two way binding using '=' i have update your example with two way binding
<!doctype html>
<html ng-app="plunker" >
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
controller: <input type="text" ng-model="query.name" /> - work<br>
directive: <span filter by="query"></span> - not work
<ul>
<li ng-repeat="item in list | filter:query">{{item.name}}</li>
</ul>
<script>
var app = angular.module('plunker', []);
app.controller('MainCtrl', function ($scope) {
$scope.list = [
{ id: 1, name: 'aaa' },
{ id: 2, name: 'bbb' },
{ id: 3, name: 'ccc' }
];
alert("123");
$scope.query = { name: "" }
});
app.directive('filter', function () {
return {
scope: {
by: '='
},
replace: true,
template:'<input ng-model="by.name"></input>'
}
});
</script>
</body>
</html>

Resources