how to use angularJS with appended elements - javascript

Basically, i have a structure like this example
Every cell of last column needs to have this formula:
value[i][2] = value[i-1][2] + value[i][0] - value[i][1]
I'm actually having 2 problems. The first one comes when i just try to program the first row of the table. What's wrong with this extremely simple thing?
angular.module('calc', [])
.controller('cont', function($scope) {
$scope.addNumbers = function() {
var c = aCom[30][5];
var a = parseFloat($scope.entrata1);
var b = parseFloat($scope.uscita1);
return c+a-b;
}
});
considering entrata1 and uscita1 as they are value[0][0] and value[0][1].
But most important, how can I extend the formula to all other rows? Consider that every row except the first one is created dinamically with an appendChild()function to the body, do i have to use at every appended item the function setAttribute("ng-model","entrata")?
Thanks

I would suggest forget appendchild. Use ng-repeat and add rows adding to the scope
like this
angular.module('plunker', []).controller('tableCtrl', function($scope,$filter) {
$scope.rows = [{'a': 0,'u': 300},{'a': 0,'u': 150},{'a': 200,'u': 0},{'a': 0,'u': 300}];
$scope.rowscalc = function(val){
var total=0;
angular.forEach($scope.rows, function(values, key){
if(key<=val) total += values.u-values.a;});
return total;
};
$scope.addRowM = function(){
$scope.rows.push({'a': 0, 'u': 0});
};
});
<script src="//unpkg.com/angular/angular.js"></script>
<div ng-app="plunker" ng-controller="tableCtrl">
<table class="table">
<thead>
<tr>
<td class="dthead">A</td>
<td class="dthead">U</td>
<td class="dthead">Total</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in rows">
<td><input type="number" ng-model="row.a"/></td>
<td><input type="number" ng-model="row.u"/></td>
<td>{{rowscalc($index)}}</td>
</tr>
<tr>
<td colspan="3">
<button ng-click="addRowM()">Add Row</button>
</td>
</tr>
</tbody>
</table>
</div>
you can check in plunker

Related

Create Javascript object from HMTL table

I have a table like
<table id="misc_inputs">
<thead>
<tr><th>Property</th><th>Input</th></tr>
</thead>
<tbody>
<tr>
<td>a</td>
<td><input type="number" value="1"></td>
</tr>
<tr>
<td>b</td>
<td><input type="number" value="2"></td>
</tr>
...
I would like to convert that table to a Javascript object like
misc_inputs = {"a": 1, "b": 2, ...
How can the result be generated?
You can use below re-usable javascript method to convert any HTML table into Javascript object.
<table id="MyTable">
<thead>
<tr><th>Property</th><th>Input</th></tr>
</thead>
<tbody>
<tr>
<td>a</td>
<td><input type="number" value="1"></td>
</tr>
<tr>
<td>b</td>
<td><input type="number" value="2"></td>
</tr>
</tbody>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
function ConvertHTMLToJSObject(htmlTableId)
{
var objArr = {};
var trList = $('#' + htmlTableId).find('tr');
$('#' + htmlTableId).find('tbody tr').each(function ()
{
var row = $(this);
var key = $(row).first().text().trim();
var value = $(row).find('input').attr("value");
objArr[key] = value;
});
return objArr;
}
var obj = ConvertHTMLToJSObject("MyTable");
console.log(obj);
});
You can loop through each inputs and create the object:
var misc_inputs = {};
$("#misc_inputs input[type=number]").each(function(i, el){
var k = $(this).closest('td').prev().text();
return misc_inputs[k] = +el.value;
});
console.log(misc_inputs);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="misc_inputs">
<thead>
<tr><th>Property</th><th>Input</th></tr>
</thead>
<tbody>
<tr>
<td>a</td>
<td><input type="number" value="1"></td>
</tr>
<tr>
<td>b</td>
<td><input type="number" value="2"></td>
</tr>
</tbody>
</table>
Probably you can do it without any library but with jQuery it's easier. Something like that should work (not tested):
// Here we will store the results
var result = {};
// Ask jQuery to find each row (TR tag) and call a function for each
$('tr').each(function(){
// Inside a jQuery each() "this" is the current element, the TR tag in this example
var row = $(this);
// We ask jQuery to find every TD inside the current row (the second parameter of a jQuery selector is the parent node for your search). We take the first one and then we take the content of the tag
var label = $("td", row).first().text();
// We ask for an "input" tag inside the current row and we read its "value" attribute
var value = $("input", row).attr("value");
// Store everything in result
result[label] = value;
});

How can i make some of the table rows not selectable in SmartTable angularjs

I am using angularJS and smart table framework to manage my table in html:
The table rows are selectable using SmartTable attribute : st-select-row="row".
after user selects rows and click "add" button the selected data registered to some other list.
I don't want to remove added rows from table but I do want them to be not selectable.
This is code example:
HTML:
<body ng-app="FarmManagment" ng-controller="mainCtrl">
<table id="Table" class="table table-hover" st-table="displayedCollection" st-safe-src="rowCollection">
<thead>
<tr>
<th st-sort="farmName">Farm Name</th>
<th st-sort="FarmDescription">Description</th>
<th st-sort="DataCenter">DC</th>
</tr>
</thead>
<tbody>
<tr st-select-row="row" st-select-mode="multiple" ng-repeat="row in displayedCollection">
<td ng-bind="row.farmName">{{row.farmName}}</td>
<td ng-bind="row.FarmDescription"></td>
<td ng-bind="row.DataCenter"></td>
</tr>
</tbody>
</table>
<button id="add" ng-click="add(displayedCollection)"> add </button>
<li>
<ul ng-bind="row.farmName" ng-repeat="row in added"></ul>
</li>
</body>
JavaScript:
var app = angular.module('FarmManagment', ['smart-table']);
app.controller('mainCtrl', function ($scope) {
$scope.rowCollection = [
{farmName: 'farm1', FarmDescription: 'some farm1', DataCenter: 'London'},
{farmName: 'farm2', FarmDescription: 'some farm2', DataCenter: 'Paris'},
{farmName: 'farm3', FarmDescription: 'some farm3', DataCenter: 'Berlin'}
];
$scope.added = [];
$scope.add = function(rows){
angular.forEach(rows,function(row){
if (row.isSelected === true){
row.isSelected = false;
var index = $scope.added.indexOf(row);
if(index === -1){
$scope.added.push(row);
// row.disableSelection this is what i want to do
}
}
});
};
});
How can I implement such behavior?
plunker code:plunker
Thanks
Dima
You can add condition like
<tr st-select-row="isSelectableRow(row)" st-select-mode="multiple" ng-repeat="row in displayedCollection">
and in the controller
$scope.isSelectableRow = function (row) {
if (~$scope.added.indexOf(row))
return false;
return row;
}
And also, you have incorrect html
<li><ul>..</ul></li>
change it to
<ul><li>..</li></ul>
Working example here
can be done using the attribute st-select-row:
for example prevent the second row to be selectable
<tr st-select-row="$index != 1 ? row : null" st-select-mode="multiple" ng-repeat="row in displayedCollection">
plunker

How do I get the total sum in ng-init and ng-repeat - angularjs

Having a problem with in ng-init and ng-repeat angularjs
i'm trying to loop the fields rates to get the total
for example this is my table
nane +++++++id+++++++rate
joe +++++++++1+++++++3
joe +++++++++2+++++++3
joe +++++++++3+++++++3
joe +++++++++4+++++++3
this my code.
<table>
<tr>
<td>name</td>
<td>rate</td>
</tr>
<tr ng-repeat="item in videos">
<td>{{item.name}}</td>
<td ng-init="videos.total.rate = videos.total.rate + item.rate">{{item.rate}}</td>
</tr>
<tr>
<td>Total</td>
<td>{{videos.total.rate}}</td>
</tr>
The Result that I get is 3333 instead of 12 when added all together
this is the line with problem
<td ng-init="videos.total.rate = videos.total.rate + item.rate">{{item.rate}}</td>
if i change it to a number it works fine.
<td ng-init="videos.total.rate = videos.total.rate + 3">{{item.rate}}</td>
your help would be great.thanks
Try something like this in controller.
JS
$scope.RateTotal= 0;
for (var i = 0; i < data.length; i++) {
$scope.RateTotal= $scope.RateTotal + data[i].rate;
}
HTML
<p>{{RateTotal}}</p>
Option above is better, but if you want use ng-init use something like this.
<table ng-init="RateTotal = 0">
<thead>
<th>Rate</th>
</thead>
<tbody>
<tr ng-repeat="item in videos">
<td ng-init="$parent.RateTotal= $parent.RateTotal + item.rate">{{item.rate}}</td>
</tr>
<tr>
<thead>
<tr>
<th>Total</th>
<th>{{RateTotal}}</th>
</tr>
</thead>
</tr>
</tbody>
</table>
P.S.
This directive can be abused to add unnecessary amounts of logic into
your templates. There are only a few appropriate uses of ngInit, such
as for aliasing special properties of ngRepeat, as seen in the demo
below; and for injecting data via server side scripting. Besides these
few cases, you should use controllers rather than ngInit to initialize
values on a scope. - ngInit
move this logic into the controller. That is what it is for. The view should be displaying data.
Now you have to worry about how to cast strings to an integer and writing 4x more code in a language that angular must interpret into javascript.
The complexity you are adding here is going to be fun to maintain.
but you probably want to continue doing it wrong, in which case this should work: <table ng-init='videos.total = {"rate": 0}'>
Define a filter to calculate the total:
app.filter('calculateRateTotal',function(){
return function(input){
var total = 0;
angular.forEach(input,function(value,key){
total = total+value.rate;
});
return total;
};
});
HTML:
<td ng-bind="videos | calculateRateTotal"></td>
After 10hrs of no luck just my managed to get it right. turned to be very simple.
This is the code.
In the Controller added
$scope.getTotal = function(){
var total = 0;
for(var i = 0; i < $scope.videos.length; i++){
var item = $scope.videos[i];
total += (item.rate*1);
}
return total; }
And HTML
<table>
<tr>
<th>Rate</th>
</tr>
<tr ng-repeat="item in videos">
<td>{{item.rate}}</td>
</tr>
<tr>
<td>Total: {{ getTotal() }}</td>
</tr>
</table>
Thanks everyone for helping

Sum of Inputs in ng-repeat

I'm trying to create a prototype that populates a list of unpaid invoices using ng-repeat. Within this, I am creating an input for each invoice. I want to be able to have a user input $ amounts into these inputs and then display a total of all inputs. Going off of this example: http://jsfiddle.net/d5ug98ke/9/ I cannot get it to work as it does in the fiddle. Here is my code:
<table class="table table-striped header-fixed" id="invoiceTable">
<thead>
<tr>
<th class="first-cell">Select</th>
<th class="inv-res2">Invoice #</th>
<th class="inv-res3">Bill Date</th>
<th class="inv-res4">Amount</th>
<th class="inv-res5">Amount to Pay</th>
<th class="inv-res6"></th>
</tr>
</thead>
<tbody>
<tr ng-if="invoices.length" ng-repeat="item in invoices | filter: {status:'Unpaid'}">
<td class="first-cell"><input type="checkbox" /></td>
<td class="inv-res2">{{item.invoiceNum}}</td>
<td class="inv-res3">{{item.creationDate}}</td>
<td class="inv-res4" ng-init="invoices.total.amount = invoices.total.amount + item.amount">{{item.amount | currency}}</td>
<td class="inv-res5">$
<input ng-validate="number" type="number" class="input-mini" ng-model="item.payment" ng-change="getTotal()" min="0" step="0.01" /></td>
</tr>
</tbody>
</table>
<table class="table">
<tbody>
<tr class="totals-row" >
<td colspan="3" class="totals-cell"><h4>Account Balance: <span class="status-error">{{invoices.total.amount | currency }}</span></h4></td>
<td class="inv-res4"><h5>Total to pay:</h5></td>
<td class="inv-res5">${{total}}</td>
<td class="inv-res6"></td>
</tr>
</tbody>
</table>
And the Angular:
myBirkman.controller('invoiceList', ['$scope', '$http', function($scope, $http) {
$http.get('assets/js/lib/angular/invoices.json').success(function(data) {
$scope.invoices = data;
});
$scope.sum = function(list) {
var total=0;
angular.forEach(list , function(item){
total+= parseInt(item.amount);
});
return total;
};
$scope.total = 0;
$scope.getTotal = function() {
$scope.invoices.forEach(function(item){
$scope.tot += parseInt(item.payment);
});
};
}]);
Any help would be appreciated. I dont necessarily need to use the method in the fiddle if someone has a better idea.
It seems there are two issues. First a simple typo:
$scope.tot += parseInt(item.payment, 10);
should be
$scope.total += parseInt(item.payment, 10);
And you should also reset $scope.total to 0 at the beginning of getTotal().
Edit: The way you did it, you always have to remember to update the total when something changes. Instead, you could let getTotal just return the total and write {{ getTotal() }} in the template. You don't have to trigger getTotal() in via ng-change then. If you don't have a lot of inputs you shouldn't worry about performance here.

Angularjs add element to DOM when clicking

I want to create a table which contains dynamic Content. When clicking on an element, the Details should Show up in the next line. So i creatied the following:
<table ng-controller="TestCtrl">
<tr ng-repeat-start="word in ['A', 'B', 'C']">
<td><!-- Some Information, Image etc --></td>
<td ng-click="showDetails(word)">{{word}}</td>
</tr>
<!-- This is only visible if necessary -->
<tr ng-repeat-end ng-show="currentDetail == word">
<td colspan="2" ng-attr-id="{{'Details' + word}}"></td>
</tr>
</table>
And I have the following js code:
angular.module('maApp', []).controller("TestCtrl", function($scope, $document, $compile){
$scope.showDetails = function(word){
var target = $document.find("Details" + word);
//I checked it - target is NOT null here
//target.html("<div>Test</div>");
//target.append("<div>Test</div>");
var el = $compile("<div>Test</div>")($scope);
target.append(el);
//Show tr
$scope.currentDetail = word;
};
});
I also tried the commented Solutions above but nothing of it works (The tr is showing up however). I guess there is something wrong with $document.find("Details" + word) but I don't know what.
Ultimately I want to add an <iframe> and the source would contain the word.
Does anybody see what I'm doing wrong here?
No need for weird non-angulary DOM manipulation: All you need is this.
HTML:
<table ng-controller="TestCtrl">
<tr ng-repeat-start="word in ['A', 'B', 'C']">
<td><!-- Some Information, Image etc --></td>
<td ng-click="showDetails(word)">{{word}}</td>
</tr>
<tr ng-show="currentDetail==word" ng-repeat-end>
<td colspan="2">Details {{word}}</td>
</tr>
</table>
JS:
angular.module('myApp', []).controller("TestCtrl", function($scope, $document, $compile){
$scope.showDetails = function(word) {
$scope.currentDetail = word;
};
});
http://jsfiddle.net/HB7LU/20074/
$document.find in jqlite is limited to tag name only. You have to add jquery for anything more.
See what is suported in the docs.
you have all you need built into angular already, you don't need the Javascript at all.
see this plunker example
<table style="width:100%;">
<thead style="background-color: lightgray;">
<tr>
<td style="width: 30px;"></td>
<td>
Name
</td>
<td>Gender</td>
</tr>
</thead>
<tbody>
<tr ng-repeat-start="person in people">
<td>
<button ng-if="person.expanded" ng-click="person.expanded = false">-</button>
<button ng-if="!person.expanded" ng-click="person.expanded = true">+</button>
</td>
<td>{{person.name}}</td>
<td>{{person.gender}}</td>
</tr>
<tr ng-if="person.expanded" ng-repeat-end="">
<td colspan="3">{{person.details}}</td>
</tr>
</tbody>
</table>

Categories

Resources