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>
Related
I am creating a dynamic form where I am getting the form fields form api.
I am using ng-container & ng-template to reuse the formgroup multiple times but it's not working as expected. When I am using usual div it's working as expected.
https://stackblitz.com/edit/angular-ivy-hqc49t
You can use FormGroup instances instead of formGroupName, because template loses context of formGroup:
Stackblitz
<ng-container
*ngTemplateOutlet="
fieldsTemplate;
context: {
formGroup: formGroundUse.get('groundUses')
}
"
>
</ng-container>
<div formArrayName="groundUsesArray">
groundUsesArray
<ng-container *ngFor="let data of groudUse.controls">
<ng-container
*ngTemplateOutlet="
fieldsTemplate;
context: {
formGroup: data
}
"
>
</ng-container>
</ng-container>
<ng-template #fieldsTemplate let-formGroup="formGroup">
<div [formGroup]="formGroup">
<tr>
<td class="input-container">
<label for="">title</label>
<input type="text" class="form-input" formControlName="title" />
</td>
<td class="input-container">
<label for="">value</label>
<input type="text" class="form-input" formControlName="value" />
</td>
<td class="input-container">
<label for="">percentage</label>
<input type="number" class="form-input" formControlName="percentage" />
</td>
</tr></div
></ng-template>
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!
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
I want to build a pop-up modal edit form to change individual table values in a dynamic grid. Right now, the input fields appear on button click using the function editToggle(i). No more than 4 input fields will ever appear because they are meant to edit the 4 values in my data model. However, the input fields (and values) are being dynamically generated with *ngFor. I need some way to pass/copy those input fields to my modal to edit there instead of on the grid itself (where they currently appear after clicking the edit button).
I have tried to use [(ngModel)] to clone but it does not work. I have tried to pass them using functions but the values return null. Because the HTML only shows one input field (because they are being dynamically created with *ngFor) I do not know of a way to individually pass the values.
<div>
<table align="center">
<tr>
<th>
List of Providers
</th>
</tr>
</table>
<table id="thetable" align="center">
<tr>
<th>Application ID</th>
<th>Client Name</th>
<th>Version</th>
<th>API Key</th>
<th>Protected Secret</th>
<th>EDIT/DELETE</th>
</tr>
<tr ng-app="tblRowApp" *ngFor="let prov of providers; let i = index">
<td *ngFor="let col of columns">
<span class="field" *ngIf="i !== index">
{{prov[col]}}
</span>
<span *ngIf="i === index">
<input [(ngModel)]="inputClientName" class="table" value="{{prov[col]}}" (change)="EditItem(i, col, $event.target.value)" type="text" placeholder="{{prov[col]}}">
</span>
<td>
<span *ngIf="editing && i === index">
<button (click)="save()">Save</button>
</span>
<span *ngIf="i !== index">
<button class="edit" name="editButton" (click)="editToggle(i); openEditForm()">/</button>
<button class="delete" (click)="deleteRow(i)">x</button>
</span>
</td>
</tr>
</table>
<!-- The EDITING Modal -->
<div id="editForm" class="modal_edit">
<div class="modal-content_edit">
<span (click)="save()" class="close">×</span>
<h2 style="margin-bottom: 70px">Edit OAuthAppProvider</h2>
<div>
<label style="margin-bottom: 20px">
Client Name:
</label>
<input [(ngModel)]="inputClientName" id="editClientName" type="text">
</div>
<div>
<label style="margin-bottom: 20px">
Version
</label>
<input id="editClientVersion" type="text">
</div>
<div>
<label style="margin-bottom: 20px">
API Key:
</label>
<input id="editClientAPIKey" type="text">
</div>
<div>
<label style="margin-bottom: 20px">
Protected Secret
</label>
<input id="editClientProtectedSecret" type="text">
</div>
<button style="float: right" class="add" (click)="save()">
<h4 style="font-style: bold">Save</h4>
</button>
<button class="cancel" (click)="save()">
<h4 style="font-style: bold">Cancel</h4>
</button>
</div>
</div>
</div>
export const PROVIDERS: any[] =
[
{
AppID: "11",
ClientName: "sampleclientname1",
apiKey: "sampleapikey1",
Version: "1.0",
protectedsecret: "samplesecret1"
},
{
AppID: "12",
ClientName: "sampleclientname2",
apiKey: "sampleapikey2",
Version: "1.0",
protectedsecret: "samplesecret2"
},
{
AppID: "13",
ClientName: "sampleclientname3",
apiKey: "sampleapikey3",
Version: "1.0",
protectedsecret: "samplesecret3"
},
{
AppID: "14",
ClientName: "sampleclientname4",
apiKey: "sampleapikey4",
Version: "1.0",
protectedsecret: "samplesecret4"
}
]
You can set a variable named something like selectedRowData and set the provider as its value when the user clicks the edit button. The value attribute of the inputs on the modal can be set to the properties of the selected row. It's difficult to tell what the functionality of the other methods is supposed to be without the component code so I made some assumptions. Let me know if you have any other questions about it.
Here's a link to a StackBlitz.
EDIT
The data is only being bound one way via the [value] attribute and there isn't a form object keeping track of all the changes like there would be using Reactive Forms so a model should be created first.
I commented out the original solution and added updates below. The selectedRowData variable is instantiated with a provider object with empty properties. The modal has been updated to use two-way binding with [(ngModel)]. The StackBlitz has also been updated.
The table is updated as the user types their edits into the form. The save button doesn't need to be used unless the data needs to be persisted somewhere.
Check out the Angular Forms Documentation it should help with how to pass form data around between components. What you've created here is similar to Template-driven Forms.
Component
// selectedRowData = null;
selectedRowData = {
AppID: "",
ClientName: "",
apiKey: "",
Version: "",
protectedsecret: ""
};
editToggle(rowData) {
this.selectedRowData = rowData;
}
Table
<div>
<table align="center">
<tr>
<th>
List of Providers
</th>
</tr>
</table>
<table id="thetable" align="center">
<tr>
<th>Application ID</th>
<th>Client Name</th>
<th>Version</th>
<th>API Key</th>
<th>Protected Secret</th>
<th>EDIT/DELETE</th>
</tr>
<tr ng-app="tblRowApp" *ngFor="let prov of providers; let i = index">
<td *ngFor="let col of columns">
<span class="field" *ngIf="i !== index">
{{prov[col]}}
</span>
<span *ngIf="i === index">
<input [(ngModel)]="inputClientName" class="table" value="{{prov[col]}}"
(change)="EditItem(value)" type="text" placeholder="{{prov[col]}}">
</span>
<td>
<span *ngIf="editing && i === index">
<button (click)="save()">Save</button>
</span>
<span *ngIf="i !== index">
<button class="edit" name="editButton" (click)="editToggle(prov); openEditForm()">/</button>
<button class="delete" (click)="deleteRow(i)">x</button>
</span>
</td>
</tr>
</table>
Modal
<!-- The EDITING Modal -->
<div id="editForm" class="modal_edit">
<div class="modal-content_edit">
<span (click)="save()" class="close">×</span>
<h2 style="margin-bottom: 70px">Edit OAuthAppProvider</h2>
<div>
<label style="margin-bottom: 20px">
Client Name:
</label>
<!-- <input id="editClientName" type="text" [value]="selectedRowData?.ClientName"> -->
<input id="editClientName" type="text" [(ngModel)]="selectedRowData.ClientName">
</div>
<div>
<label style="margin-bottom: 20px">
Version
</label>
<!-- <input id="editClientVersion" type="text" [value]="selectedRowData?.Version"> -->
<input id="editClientVersion" type="text" [(ngModel)]="selectedRowData.Version">
</div>
</div>
<div>
<label style="margin-bottom: 20px">
API Key:
</label>
<!-- <input id="editClientAPIKey" type="text" [value]="selectedRowData?.apiKey"> -->
<input id="editClientAPIKey" type="text" [(ngModel)]="selectedRowData.apiKey">
</div>
<div>
<label style="margin-bottom: 20px">
Protected Secret
</label>
<!-- <input id="editClientProtectedSecret" type="text" [value]="selectedRowData?.protectedsecret"> -->
<input id="editClientProtectedSecret" type="text" [(ngModel)]="selectedRowData.protectedsecret">
</div>
<button style="float: right" class="add" (click)="save()">
<h4 style="font-style: bold">Save</h4>
</button>
<button class="cancel" (click)="save()">
<h4 style="font-style: bold">Cancel</h4>
</button>
</div>
</div>
</div>
I have a shopping cart and a page that shows all products in a table. I am able to remove products, but I want to be able to change their quantity as well.
My table consists of an input field that you can change the quantity in, when clicking on an 'update' cart button below, I am sending the productname and the quantity to my PHP script. The problem is, it always posts the first product.
Probably because all have the same classname, how can I fix that?
This is what my table looks like:
<div class="col-md-8">
<div class="kl-title-block clearfix text-left tbk-symbol--line tbk-icon-pos--after-title">
<h2 class="tbk__title montserrat fs-34 fw-semibold black winkelmandtitle">Uw Winkelmand</h2>
<span class="tbk__symbol ">
<span></span>
</span>
<h4 class="tbk__subtitle fs-22 fw-thin">Bent u niets vergeten?</h4>
</div>
<div class="table-responsive">
<table class="table carttable">
<thead>
<tr>
<th>Verwijder</th>
<th>Afbeelding</th>
<th>Product</th>
<th>Prijs</th>
<th>Aantal</th>
<th>Totaal</th>
</tr>
</thead>
<tbody>
<tr>
<td>×</td>
<td>
<a href="baden/bad-13" class="product-title">
<img class="attachment-shop_thumbnail" src="images/defaultimage.jpg" alt="Bad 13" title="Bad 13">
</a>
</td>
<td>
<a href="baden/bad-13" class="product-title">
Bad 13
</a>
</td>
<td>€ 1500</td>
<td>
<div class="quantity">
<input type="number" step="1" min="0" name="quantity" id="Bad 13" value="1" title="Qty" class="input-text qty quantityclass text" size="4">
</div>
</td>
<td>€ 1500</td>
</tr>
</tbody>
<tbody>
<tr>
<td>×</td>
<td>
<a href="baden/bad-14" class="product-title">
<img class="attachment-shop_thumbnail" src="images/defaultimage.jpg" alt="Bad 14" title="Bad 14">
</a>
</td>
<td>
<a href="baden/bad-14" class="product-title">
Bad 14
</a>
</td>
<td>€ 800</td>
<td>
<div class="quantity">
<input type="number" step="1" min="0" name="quantity" id="Bad 14" value="1" title="Qty" class="input-text qty quantityclass text" size="4">
</div>
</td>
<td>€ 800</td>
</tr>
</tbody>
<tbody>
<tr>
<td>×</td>
<td>
<a href="baden/bad1" class="product-title">
<img class="attachment-shop_thumbnail" src="cms/images/bad.jpg" alt="Bad 1" title="Bad 1">
</a>
</td>
<td>
<a href="baden/bad1" class="product-title">
Bad 1
</a>
</td>
<td>€ 1000</td>
<td>
<div class="quantity">
<input type="number" step="1" min="0" name="quantity" id="Bad 1" value="1" title="Qty" class="input-text qty quantityclass text" size="4">
</div>
</td>
<td>€ 1000</td>
</tr>
</tbody>
</table>
<input type="submit" class="button updatebutton" name="update_cart" value="Wijzig winkelmand">
</div>
</div>
And this is my jquery script that fires an ajax post.
//Wijzig winkelmand met het aantal producten
tpj('.cartsection').on('click', '.updatebutton', function(event) {
var $edit = tpj('.quantityclass').attr('id'),
$aantal = tpj('.quantity').find( "input[name='quantity']" ).val(),
url = 'includes/cartoverzicht.php';
var posting = tpj.post( url, { edit: $edit, aantal: $aantal} );
posting.done(function( data ) {
var content = tpj( data );
tpj( "#cartresult" ).empty().append( content );
});
});
The problem is, when I look in network this is always posted no matter what product I clicked:
edit:Bad 13
aantal:1
How can I fix that?
Can I maybe post all quantities to my php script? What would be the best solution?
You are hitting problems because you are only ever grabbing the first selector. You have also designed your API to only send one update when it looks like you want to send the whole updated set.
Below is the way to go if you want to update the quantities for the whole cart.
$('.updatebutton').on('click', function(event) {
var elements = $('.quantity input[name="quantity"]'),
url = 'includes/cartoverzicht.php',
postBody = [];
for (var i=0; i<elements.length; i++) {
var element = $(elements[i]);
postBody.push({
edit: element.attr('id'),
aantal: element.val()
})
}
var posting = $.post( url, JSON.stringify(postBody) );
posting.done(function( data ) {
var content = $( data );
$( "#cartresult" ).empty().append( content );
});
});
The issue is here:
var $edit = tpj('.quantityclass').attr('id'),
you are using a class selector to get the value, it always return the first element value. Instead use this
See this example:
$(document).ready(function(){
$('.list').click(function(){
console.log( $('.list').html() );
});
$('.listing').click(function(){
console.log( $(this).html() );
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>
First list (It always return the first element value)
</p>
<li class="list">One</li>
<li class="list">Two</li>
<li class="list">Three</li>
<p>
Another List (It always return the clicked element value)
</p>
<li class="listing">One</li>
<li class="listing">Two</li>
<li class="listing">Three</li>