Output the difference of totals on columns 3 and 5 in Angular - javascript

Is there any way I can get the difference of the totals on column 3 and the last column?
<body ng-app="Test">
<section style="margin-top:80px">
<h3>Plastic Calculator Form Version 2.0</h3>
<div ng-controller="TestController as test" >
<p>To date,
<strong><u># of people who pledged</u></strong>
Earthlings have pledged to reduce
their single-use plastic waste from
<strong><u>{{ test.approve | sumByColumn: 'amount' }}</u>
</strong> Items per year to <strong>
<u>{{ test.approve | sumByColumn5: 'amount' }}</u>
</strong>.
That's a reduction of
<strong><u>{{ test.approve | sumByColumn4: 'reducedTotal' }}</u>
</strong> per year! Do your part. Make a pledge!
</p>
<table class="table">
<tr>
<th>Single-Use Plastic Items</th>
<th>Enter the Number You Use Per Week</th>
<th>The Number You Use Per Year is:</th>
<th>How Many Less Can You Use Per Week?</th>
<th>Your Reduced Usage Per Year Would Be:</th>
</tr>
<tr ng-repeat="x in test.approve">
<td> {{ x.name }} </td>
<td> <input class="qty form-control" type="number"
ng-model="x.number" ng-change="sumByColumn3()" min="0"
restrict-to="[0-9]"/>
</td>
<td ng-model="x.amount"> {{ x.number*x.amount }} </td>
<td> <input class="qty form-control" type="number"
ng-model="x.reducedAmount" ng-change="sumByColumn2()"
min="0" restrict-to="[0-9]"/>
</td>
<td ng-model="x.reducedTotal"> {{ x.reducedAmount*x.reducedTotal }}
</td>
</tr>
<tr>
<td>TOTALS</td>
<td>{{ test.approve | sumByColumn3: 'number' }}</td>
<td>{{ test.approve | sumByColumn: 'amount' }}</td>
<td>{{ test.approve | sumByColumn2: 'reducedAmount' }}</td>
<td>{{ test.approve | sumByColumn4: 'reducedTotal' }}</td>
</tr>
</table>
<form>
<div class="col-sm-4">
<div class="form-group">
<label for="full-name">Name</label>
<input type="text" class="form-control" id="full-name"
placeholder="Enter Full Name">
</div>
</div>
<div class="col-sm-4">
<div class="form-group">
<label for="email-address">Email</label>
<input type="email" class="form-control" id="email-address"
aria-describedby="emailHelp" placeholder="Enter email">
</div>
</div>
<div class="col-sm-4">
<button type="submit" class="btn btn-primary" style="margin-top:25px">
Submit
</button>
</div>
</form>
</div>
</section>
</body>
Also, is there a way I can make the form cumulate the total in column 3 when the user hits submit? In other words, in the sentence where it says:
single-use plastic waste from
<strong>
<u>{{ test.approve | sumByColumn: 'amount' }}</u>
</strong> Items per year
would add up the totals each time a user fills out the form.
Here's the full code - https://codepen.io/tampham/pen/RzqLQV
As for getting the difference, here's what I tried so far.
filter('sumByColumn5', function () {
return function (collection, column) {
var total = 0;
collection.forEach(function (item) {
total += (item.amount-item.reducedTotal);
});
return total;
};
})
Any suggestions would be much help, thanks!

You already have the following lines that calculate the totals of column 3 and 5
{{(test.approve | sumByColumn: 'amount') }}
{{(test.approve | sumByColumn4: 'reducedTotal')}}
I think the the easiest solution for you is to get difference between these two using the follwing.
{{(test.approve | sumByColumn: 'amount') - (test.approve | sumByColumn4: 'reducedTotal')}}
Demo

Related

Use computed data inside for each loop in vue.js

I would live to make use of reactive data changes when using v-model for <input> tags.
Now I want to have a value inside a v-for loop to be updated automatically when v-model is triggered.
What I'm doing wrong here ?
<tr v-for="(service, key) in services" :key="key">
<td class="left aligned">
<div class="title" contenteditable="true">{{ service.title }}</div>
<div class="desc" contenteditable="true">{{ service.description }}</div>
</td>
<td class="price">
<input v-model.number="service.price" type="number" min="0" /> € / day
</td>
<td class="quantity">
<input v-model.number="service.quantity" type="number" min="0" />
</td>
<td>
<div class="total">{{ service.total | currency }} €</div>
<div class="tva">+{{ service.total | tva(invoice.tax) }} € ({{ invoice.tax }}%)</div>
</td>
</tr>
Whenever I change the values inside the inputs service.quantity or service.price, they updates automatically, except those values in service.total.
Use a method instead:
export default {
...
methods: {
getServiceTotal({ price, quantity }) {
return quantity * price;
}
}
...
}
And in your template:
<div class="total">{{ getServiceTotal(service) | currency }} €</div>

Store the total and have it cumulate on submit

How do you store the total and have it cumulate each time a user hits submit?
For instance, Cumulative Total = # would add up the total of column 3 each time a user submits their info.
<body ng-app="Test">
<section style="margin-top:80px">
<h3>Plastic Calculator Form</h3>
<div ng-controller="TestController as test" >
<p>To date, <strong><u># of people who pledged</u></strong> Earthlings have pledged to reduce their single-use plastic waste from <strong><u>{{ test.approve | sumByColumn: 'amount' }}</u></strong> Items per year to <strong><u>{{(test.approve | sumByColumn: 'amount') - (test.approve | sumByColumn4: 'reducedTotal')}}</u></strong>. That's a reduction of <strong><u>{{ test.approve | sumByColumn4: 'reducedTotal' }}</u></strong> per year! Do your part. Make a pledge!</p>
<table class="table">
<tr>
<th>Single-Use Plastic Items</th>
<th>Enter the Number You Use Per Week</th>
<th>The Number You Use Per Year is:</th>
<th>How Many Less Can You Use Per Week?</th>
<th>Your Reduced Usage Per Year Would Be:</th>
</tr>
<tr ng-repeat="x in test.approve">
<td> {{ x.name }} </td>
<td> <input class="qty form-control" type="number" ng-model="x.number" ng-change="sumByColumn3()" min="0" restrict-to="[0-9]"/> </td>
<td> {{ x.number*x.amount }} </td>
<td> <input class="qty form-control" type="number" ng-model="x.reducedAmount" ng-change="sumByColumn2()" min="0" restrict-to="[0-9]"/> </td>
<td> {{ x.reducedAmount*x.reducedTotal }} </td>
</tr>
<tr>
<td>TOTALS</td>
<td>{{ test.approve | sumByColumn3: 'number' }}</td>
<td>{{ test.approve | sumByColumn: 'amount' }}</td>
<td>{{ test.approve | sumByColumn2: 'reducedAmount' }}</td>
<td>{{ test.approve | sumByColumn4: 'reducedTotal' }}</td>
</tr>
<tr>
<td colspan="2">Total difference = {{(test.approve | sumByColumn: 'amount') - (test.approve | sumByColumn4: 'reducedTotal')}}</td>
<td colspan="3">
<strong>Cumulative Total = #</strong>
</td>
</tr>
</table>
<form>
<div class="col-sm-4">
<div class="form-group">
<label for="full-name">Name</label>
<input type="text" class="form-control" id="full-name" placeholder="Enter Full Name">
</div>
</div>
<div class="col-sm-4">
<div class="form-group">
<label for="email-address">Email</label>
<input type="email" class="form-control" id="email-address" aria-describedby="emailHelp" placeholder="Enter email">
</div>
</div>
<div class="col-sm-4">
<button type="submit" class="btn btn-primary" style="margin-top:25px">Submit</button>
</div>
</form>
</div>
</section>
</body>
Link to Pen
I am not really sure if its best to do with window.localStorage or sessionStorage or perhaps do it with PHP. I'm experimenting with this now.
Your help will be golden.
I am not really sure if its best to do with window.localStorage or
sessionStorage or perhaps do it with PHP. I'm experimenting with this
now.
Its simple to figure this out. Here is how:
1.) Have these numbers (summation) somehow got anything to do with your backend data? Do you need some kind of server code or functionalities to do this? if yes: use php.
2.) If 1 was false for you, do you want your users to be able to get the numbers or summation back again when they come back again? do you want it to be persistent? then use: localStorage
3.) If 2 was false, use sessionStorage. it is not persistent and is cleared out as soon as the current session is terminated. ie: user closes the tab or browser.
Now if you need some help with code, then modify your question to include those details or open a new question or simply post a comment on this answer of mine. I would try my best to help you out. Happy Coding!

Sum of properties in an object array AngularJS

I am fairly new to both angularjs and javascript and am in need of some guidance. I am making an application which records time logs for a project. One of the columns needs to be delta time - the time difference between starting a log and finishing it and taking away interval time (for example if I started a project at 1pm, finished at 3pm but had a 30 minute break inbetween the delta time would be 2 & 1/2 hours).
Here is my code so far, whatever I try do either comes up with the wrong time or NaN. Any help would be appreciated!
View:
<div class="main" ng-controller="MainController">
<div class="container-fluid">
<div class="header">
<div class="container-fluid">
<h1>{{ title }}</h1>
</div>
</div>
<div class="row container-fluid">
<!--<div class="col-md-4">-->
<div class="panel panel-default">
<div class="panel-body">
<!--<<form ng-submit="addNew(timeLogs)" >-->
<form>
<div class="form-group col-md-6">
<label>Project</label>
<input type="text" class="form-control" placeholder="Project" ng-model="project" >
</div>
<div class="form-group col-md-6">
<label>Phase</label>
<input type="text" class="form-control" placeholder="Phase" ng-model="phase" >
</div>
<div class="form-group col-md-6">
<label>Date</label>
<input type="date" class="form-control" placeholder="dd-MM-yyyy" ng-model="date" >
</div>
<div class="form-group col-md-6">
<label>Start Time</label>
<input type="time" class="form-control" placeholder="HH:mm:ss" ng-model="startTime" required>
</div>
<div class="form-group col-md-6">
<label>Interval Time (mins)</label>
<input type="text" class="form-control without" placeholder="Int Time" ng-model="intTime" >
</div>
<div class="form-group col-md-6">
<label>End Time</label>
<input type="time" class="form-control" placeholder="HH:mm:ss" ng-model="endTime" required>
</div>
<div class="form-group col-md-6">
<label>Comments</label>
<input type="text" class="form-control" placeholder="Comments" ng-model="comments" >
</div>
<button ng-click="addLog()">Add</button>
</form>
</div>
</div>
<!--</div>-->
</div>
<table class="table table-striped col-md-4">
<tr>
<th>Project</th>
<th>Phase</th>
<th>Date</th>
<th>Start Time</th>
<th>Int Time (mins)</th>
<th>Stop Time</th>
<th>Delta Time</th>
<th>Comments</th>
<th>Make Changes</th>
</tr>
<tr data-ng-repeat="log in logs">
<td>{{ log.project }}</td>
<td>{{ log.phase }}</td>
<td>{{ log.date | date:'dd/MM/yyyy' }}</td>
<td>{{ log.startTime | date:'hh:mma' }}</td>
<td>{{ log.intTime }}</td>
<td>{{ log.endTime | date:'hh:mma' }}</td>
<td>{{ log.startTime -- log.endTime | date:'hh:mma' }}</td>
<td>{{ log.comments }}</td>
<td>
<button class="btn btn-primary" ng-click="main.editClickHandler(item)">Edit</button>
<button class="btn btn-danger" ng-click="main.removeClickHandler(item)">Remove</button>
</td>
</tr>
</table>
</div>
</div>
<!-- Modules -->
<script src="js/app.js"></script>
<!-- Controllers -->
<script src="js/controllers/MainController.js"></script>
Controller:
app.controller('MainController', ['$scope', function($scope) {
$scope.title = 'Time Log';
//$scope.promo = 'The most popular books this month.';
$scope.logs = [];
$scope.addLog = function() {
$scope.logs.push({
project: $scope.project,
phase: $scope.phase,
date: $scope.date,
startTime: $scope.startTime,
intTime: $scope.intTime,
endTime: $scope.endTime,
comments: $scope.comments
});
// Clear input fields after push
$scope.project = "";
$scope.phase = "";
$scope.date = "";
$scope.startTime = "";
$scope.intTime = "";
$scope.endTime = "";
$scope.comments = "";
};
$scope.deltaTime = function(logs) {
return $scope.startTime - $scope.endTime;
;
}
}]);
Try like this
$scope.deltaTime = function(logs) {
return new Date($scope.startTime) - new Date($scope.endTime);
}

Build table from angular form data

So I am trying to build a table that takes the form data entered and is stored on the client and pushes each input property into a group to create an object. From there, the table is build using ng-repeat. Code started is below, but nothing is happening. Can anyone assist?
<form class="addClaim" ng-submit="submitClaim(claimInfo)">
<div class="form-group">
<label for="beneSelect">Select your benefit</label>
<select class="form-control" id="beneSelect" >
<option ng-repeat="descr in claim.claimBenes" data-ng-model="claimInfo.providerName">{{ descr.descr }}</option>
</select>
</div>
<div class="form-group">
<label for="start">Date of Service</label>
<div>
<input type="text" class="form-control" id="start" placeholder="--/--/----" data-ng-model="claimInfo.fromDate" style="width: 240px;">
<span>To</span>
<input type="text" class="form-control" id="end" placeholder="--/--/---- (optional)" data-ng-model="claimInfo.toDate" style="width: 240px;">
</div>
</div>
<div class="form-group">
<label for="providerName">Provider Name</label>
<input type="text" class="form-control" id="providerName" data-ng-model="claimInfo.provider">
</div>
<div class="form-group">
<label for="forWhom">For Whom</label>
<input type="text" class="form-control" id="forWhom" data-ng-model="claimInfo.who">
</div>
<div class="form-group" ng-show="claimInfo.benefCode == 'HCFSA'">
<label for="age">Age</label>
<input type="text" class="form-control" id="age" data-ng-model="claimInfo.who">
</div>
<div class="form-group">
<label for="claimAmount">Amount</label>
<input type="text" class="form-control" id="claimAmount" data-ng-model="claimInfo.amount">
</div>
<div class="form-group">
<label for="claimComment">Comments</label>
<textarea class="form-control" rows="5" id="claimComment" data-ng-model="claimInfo.comments"></textarea>
</div>
<div class="form-group">
<label class="control-label"></label>
<div>
<input type="button" class="btn btn-primary" ng-click="saveClaim()" value="add claim" style="float: right;">
</div>
</div>
</form>
The table:
<div class="claimedTable" style="background-color: #ffffff; color: black;">
<table class="table">
<thead>
<tr>
<th>service date</th>
<th>provider</th>
<th>amount</th>
<th>edit</th>
<th>delete</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in claimSubmit">
<td>{{ claimInfo.fromDate }}</td>
<td>{{ claimInfo.provider }}</td>
<td>{{ claimInfo.amount }}</td>
<td><i class="fa fa-pencil-square-o"></i></td>
<td><i class="fa fa-trash-o"></i></td>
</tr>
</tbody>
</table>
</div>
And controller:
$scope.claim = [];
claimsService.getClaim().then(function (results) {
$scope.claim = results.data;
});
// submit all claim objects entered
$scope.claimsSubmit = [];
$scope.claimInfo = {
id: "",
benefitId: "",
isSecIns: "",
isNoResId: "",
expenseTypeId: "",
fromDate: "",
toDate: "",
provider: "",
who: "",
depId: "",
age: "",
amount: "",
comments: "",
isOffset: ""
};
$scope.saveClaim = function() {
$scope.claimsSubmit.push($scope.claimInfo);
//clears scope so form is empty
$scope.claimInfo = {};
}
When I enter data into the fields and click submit, nothing ever leaves nor does it post to the table. The reason I want as an object versus an array is because the table may have multiple line items depending on how many times the form is field out and submitted.
Seems somewhere simple I am going wrong, but cannot figure where. Any help please?
Thanks much.
You have a few issues in your code. Here it is cleaned up a bit...
HTML
<form class="addClaim"> // ng-submit not needed in form tag
ng-repeat bindings should be item. not claimsSubmit.
<tr ng-repeat="item in claimsSubmit">
<td>{{ item.fromDate }}</td>
<td>{{ item.provider }}</td>
<td>{{ item.amount }}</td>
<td><i class="fa fa-pencil-square-o"></i></td>
<td><i class="fa fa-trash-o"></i></td>
</tr>
Controller
$scope.claim = []; // This can be removed.
claimsService.getClaim().then(function (results) {
$scope.claim = results.data;
});
// submit all claim objects entered
$scope.claimsSubmit = [];
$scope.claimInfo = {}; // This just needs to create an object.
$scope.saveClaim = function() {
$scope.claimsSubmit.push($scope.claimInfo);
//clears scope so form is empty
$scope.claimInfo = {};
}
This should be enough to get the form populating the table for you. There is obviously form data missing from the table but it will get you going in the right direction.

Optimize / Speed Up AngularJS HTML rendering - Performance Issue

This is probably not the first question on this topic, but since it took me hours finding out I couldn't find a good solution, I still want to ask you guys here.
I would like to optimize following code, because the page needs a few seconds to load right now. If I take that part out of the page (it is only one part of it), the page loads in max 1 second.
FYI: I only have 4 routes for the student that I test my application with.
<tr ng-repeat="route in student.itin">
<td>
<select ng-options="airline._id as airline.code for airline in ::airlines | orderBy: 'code'" ng-model="route.airline" class="form-control"/>
</td>
<td>
<input type="text" ng-model="route.flight_number" maxlength="4" size="4" class="form-control"/>
</td>
<td>
<input type="text" ng-model="route.class" maxlength="1" size="1" class="form-control"/>
</td>
<td>
<select ng-options="airport._id as airport.code for airport in ::airports | orderBy: 'code'" ng-model="route.departure.airport" class="form-control"/>
</td>
<td>
<div class="form-group has-feedback" ng-class="{'has-error': route.arrival.date < route.departure.date}">
<input type="text" class="form-control" is-open="datepickers['departure_date' + $index]" max-date="route.arrival.date" timepicker-options="timepicker_options" ng-focus="open($event, 'departure_date'+$index)" datetime-picker="{{ ::datetimepicker_format }}" ng-model="route.departure.date" />
<span ng-if="route.arrival.date < route.departure.date" tooltip-placement="right" tooltip="Arrival Date cannot be before Departure Date" tooltip-trigger="mouseenter" class="glyphicon glyphicon-remove form-control-feedback" aria-hidden="true"></span>
</div>
</td>
<td>
<select ng-options="airport._id as airport.code for airport in ::airports | orderBy: 'code'" ng-model="route.arrival.airport" class="form-control"/>
</td>
<td>
<div class="form-group has-feedback" ng-class="{'has-error': route.arrival.date < route.departure.date}">
<input type="text" class="form-control" is-open="datepickers['arrival_date' + $index]" min-date="route.departure.date" timepicker-options="timepicker_options" ng-focus="open($event, 'arrival_date'+$index)" datetime-picker="{{ ::datetimepicker_format }}" ng-model="route.arrival.date" />
<span ng-if="route.arrival.date < route.departure.date" tooltip-placement="right" tooltip="Arrival Date cannot be before Departure Date" tooltip-trigger="mouseenter" class="glyphicon glyphicon-remove form-control-feedback" aria-hidden="true"></span>
</div>
</td>
<td>
<input type="text" ng-model="route.filekey" class="form-control"/>
</td>
<td class="text-right">
<a class="btn btn-danger" ng-click="deleteRoute($index)" tooltip-placement="top" tooltip="Delete route" tooltip-trigger="mouseenter">
<i class="fa fa-trash-o"></i>
</a>
</td>
</tr>
What I have learned from my research is pretty much that I shouldn't use too much ng-repeat, try to minimize data-binding and filters. But after applying everything I have learned, I came up with the code above and don't know how to go on optimizing, since this is not enough.
Thank you
add track by to your ng-repeat
remove filters where it is possible
use one time binding with ::
Or switch to ReactJS.
Try to improve ng-repeat if your AngularJS is above 1.4.1: https://docs.angularjs.org/api/ng/directive/ngRepeat#tracking-and-duplicates
You can try to use sly-repeat directive instead ng-repeat: http://blog.scalyr.com/2013/10/angularjs-1200ms-to-35ms/

Categories