Grab values from dynamic form content angularPrevent users from submitting a form by hitting EnterHow to prevent buttons from submitting formsForm values are not changing even on page reloadAngular/RxJs When should I unsubscribe from `Subscription`JavaScript - How to pass/store value from function to form hidden field?Angular 4 - using objects for option values in a select listAngular 5 get Material Select ValueDynamic mat-select option in form-arrayHorizontally aligning different types of material form control componentsnested forms and .control vs .value - help needed
Extension of 2-adic valuation to the real numbers
Was there a Viking Exchange as well as a Columbian one?
Can we say “you can pay when the order gets ready”?
Can an Area of Effect spell cast outside a Prismatic Wall extend inside it?
Why does nature favour the Laplacian?
How to stop co-workers from teasing me because I know Russian?
How to have a sharp product image?
Check if a string is entirely made of the same substring
What is the optimal strategy for the Dictionary Game?
Apply MapThread to all but one variable
Which big number is bigger?
How could Tony Stark make this in Endgame?
How to denote matrix elements succinctly?
can anyone help me with this awful query plan?
Was there a shared-world project before "Thieves World"?
555 timer FM transmitter
Does tea made with boiling water cool faster than tea made with boiled (but still hot) water?
What are the characteristics of a typeless programming language?
As an international instructor, should I openly talk about my accent?
Can SQL Server create collisions in system generated constraint names?
How to fry ground beef so it is well-browned
What happened to Captain America in Endgame?
If a planet has 3 moons, is it possible to have triple Full/New Moons at once?
How did Captain America manage to do this?
Grab values from dynamic form content angular
Prevent users from submitting a form by hitting EnterHow to prevent buttons from submitting formsForm values are not changing even on page reloadAngular/RxJs When should I unsubscribe from `Subscription`JavaScript - How to pass/store value from function to form hidden field?Angular 4 - using objects for option values in a select listAngular 5 get Material Select ValueDynamic mat-select option in form-arrayHorizontally aligning different types of material form control componentsnested forms and .control vs .value - help needed
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
I am working with a back-end API that I query for flight data, which I then loop over and display the data. My template code looks like this...
<form novalidate #form="ngForm">
<div class="flight-table">
<header fxLayout="row" fxLayoutAlign="space-between">
<div fxFlex="25">Flights</div>
<div fxFlex="17">Class</div>
<div fxFlex="18">Price (AED)</div>
<div fxFlex="15">PAX</div>
<div fxFlex="25">Total</div>
</header>
<main>
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between" *ngFor="let flight of data.flights; let i = index">
<p fxFlex="25">flight['flightName']</p>
<p fxFlex="17">flight['flightClass']</p>
<p fxFlex="18"> number</p>
<p fxFlex="15" fxLayout="column">
<mat-select placeholder="Ticket(s)">
<mat-option *ngFor="let pax of counter" [value]="pax"> pax </mat-option>
</mat-select>
</p>
<p fxFlex="25">AED 0</p>
</div>
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between">
<p class="capitalize" fxFlex="75"><strong>Total transport</strong></p>
<p class="center-text" fxFlex="25"><strong>AED 0</strong></p>
</div>
</main>
</div>
</form>
When a user selects a number of tickets from the PAX dropdown, I'd like to update both the row total
and the total transport
. I'd need to be able to grab the value of the PAX select box
and multiply it by flight['flightPrice']
but I can't quite figure out how to, because I can't know how many items are in the flights array. What you see is just one row but there could be more.
Also, I'd like to capture the value for each row. I've thought about adding a hidden form field for each row or sth like that. I'm not quite sure how to deal with this.
Is there some better way?
Update
I'm struggling with how to capture the selected rows. I've tried adding a hidden input field in each row like so..
<input
matInput
[name]="flight['flightName']-flight['flightClass']-pax-flight['flightPrice']"
[value]="total"
ngModel>
That doesn't seem to work. The goal is to have each selected row stored in an object like so...
The dashes separate the flightName
, flightClass
, pax
and flightPrice
with the value being the total (pax * flightPrice)
and pax the number of passengers.
flights:
lufthansa-business-2-60: 120,
flyEmirates-first-3-50: 150
How should I go about it?
html angular angular-forms
add a comment |
I am working with a back-end API that I query for flight data, which I then loop over and display the data. My template code looks like this...
<form novalidate #form="ngForm">
<div class="flight-table">
<header fxLayout="row" fxLayoutAlign="space-between">
<div fxFlex="25">Flights</div>
<div fxFlex="17">Class</div>
<div fxFlex="18">Price (AED)</div>
<div fxFlex="15">PAX</div>
<div fxFlex="25">Total</div>
</header>
<main>
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between" *ngFor="let flight of data.flights; let i = index">
<p fxFlex="25">flight['flightName']</p>
<p fxFlex="17">flight['flightClass']</p>
<p fxFlex="18"> number</p>
<p fxFlex="15" fxLayout="column">
<mat-select placeholder="Ticket(s)">
<mat-option *ngFor="let pax of counter" [value]="pax"> pax </mat-option>
</mat-select>
</p>
<p fxFlex="25">AED 0</p>
</div>
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between">
<p class="capitalize" fxFlex="75"><strong>Total transport</strong></p>
<p class="center-text" fxFlex="25"><strong>AED 0</strong></p>
</div>
</main>
</div>
</form>
When a user selects a number of tickets from the PAX dropdown, I'd like to update both the row total
and the total transport
. I'd need to be able to grab the value of the PAX select box
and multiply it by flight['flightPrice']
but I can't quite figure out how to, because I can't know how many items are in the flights array. What you see is just one row but there could be more.
Also, I'd like to capture the value for each row. I've thought about adding a hidden form field for each row or sth like that. I'm not quite sure how to deal with this.
Is there some better way?
Update
I'm struggling with how to capture the selected rows. I've tried adding a hidden input field in each row like so..
<input
matInput
[name]="flight['flightName']-flight['flightClass']-pax-flight['flightPrice']"
[value]="total"
ngModel>
That doesn't seem to work. The goal is to have each selected row stored in an object like so...
The dashes separate the flightName
, flightClass
, pax
and flightPrice
with the value being the total (pax * flightPrice)
and pax the number of passengers.
flights:
lufthansa-business-2-60: 120,
flyEmirates-first-3-50: 150
How should I go about it?
html angular angular-forms
add a comment |
I am working with a back-end API that I query for flight data, which I then loop over and display the data. My template code looks like this...
<form novalidate #form="ngForm">
<div class="flight-table">
<header fxLayout="row" fxLayoutAlign="space-between">
<div fxFlex="25">Flights</div>
<div fxFlex="17">Class</div>
<div fxFlex="18">Price (AED)</div>
<div fxFlex="15">PAX</div>
<div fxFlex="25">Total</div>
</header>
<main>
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between" *ngFor="let flight of data.flights; let i = index">
<p fxFlex="25">flight['flightName']</p>
<p fxFlex="17">flight['flightClass']</p>
<p fxFlex="18"> number</p>
<p fxFlex="15" fxLayout="column">
<mat-select placeholder="Ticket(s)">
<mat-option *ngFor="let pax of counter" [value]="pax"> pax </mat-option>
</mat-select>
</p>
<p fxFlex="25">AED 0</p>
</div>
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between">
<p class="capitalize" fxFlex="75"><strong>Total transport</strong></p>
<p class="center-text" fxFlex="25"><strong>AED 0</strong></p>
</div>
</main>
</div>
</form>
When a user selects a number of tickets from the PAX dropdown, I'd like to update both the row total
and the total transport
. I'd need to be able to grab the value of the PAX select box
and multiply it by flight['flightPrice']
but I can't quite figure out how to, because I can't know how many items are in the flights array. What you see is just one row but there could be more.
Also, I'd like to capture the value for each row. I've thought about adding a hidden form field for each row or sth like that. I'm not quite sure how to deal with this.
Is there some better way?
Update
I'm struggling with how to capture the selected rows. I've tried adding a hidden input field in each row like so..
<input
matInput
[name]="flight['flightName']-flight['flightClass']-pax-flight['flightPrice']"
[value]="total"
ngModel>
That doesn't seem to work. The goal is to have each selected row stored in an object like so...
The dashes separate the flightName
, flightClass
, pax
and flightPrice
with the value being the total (pax * flightPrice)
and pax the number of passengers.
flights:
lufthansa-business-2-60: 120,
flyEmirates-first-3-50: 150
How should I go about it?
html angular angular-forms
I am working with a back-end API that I query for flight data, which I then loop over and display the data. My template code looks like this...
<form novalidate #form="ngForm">
<div class="flight-table">
<header fxLayout="row" fxLayoutAlign="space-between">
<div fxFlex="25">Flights</div>
<div fxFlex="17">Class</div>
<div fxFlex="18">Price (AED)</div>
<div fxFlex="15">PAX</div>
<div fxFlex="25">Total</div>
</header>
<main>
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between" *ngFor="let flight of data.flights; let i = index">
<p fxFlex="25">flight['flightName']</p>
<p fxFlex="17">flight['flightClass']</p>
<p fxFlex="18"> number</p>
<p fxFlex="15" fxLayout="column">
<mat-select placeholder="Ticket(s)">
<mat-option *ngFor="let pax of counter" [value]="pax"> pax </mat-option>
</mat-select>
</p>
<p fxFlex="25">AED 0</p>
</div>
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between">
<p class="capitalize" fxFlex="75"><strong>Total transport</strong></p>
<p class="center-text" fxFlex="25"><strong>AED 0</strong></p>
</div>
</main>
</div>
</form>
When a user selects a number of tickets from the PAX dropdown, I'd like to update both the row total
and the total transport
. I'd need to be able to grab the value of the PAX select box
and multiply it by flight['flightPrice']
but I can't quite figure out how to, because I can't know how many items are in the flights array. What you see is just one row but there could be more.
Also, I'd like to capture the value for each row. I've thought about adding a hidden form field for each row or sth like that. I'm not quite sure how to deal with this.
Is there some better way?
Update
I'm struggling with how to capture the selected rows. I've tried adding a hidden input field in each row like so..
<input
matInput
[name]="flight['flightName']-flight['flightClass']-pax-flight['flightPrice']"
[value]="total"
ngModel>
That doesn't seem to work. The goal is to have each selected row stored in an object like so...
The dashes separate the flightName
, flightClass
, pax
and flightPrice
with the value being the total (pax * flightPrice)
and pax the number of passengers.
flights:
lufthansa-business-2-60: 120,
flyEmirates-first-3-50: 150
How should I go about it?
html angular angular-forms
html angular angular-forms
edited Mar 10 at 9:49
Nelson King
asked Mar 9 at 9:19
Nelson KingNelson King
1068
1068
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
I would recommend that you create a dedicated component for your basket items.
You then have an isolated scope you can work with and i.e. use [(ngModel)]
to set the selected number of pax on your component (for which you have to import the FormsModule
in your app/feature module).
You can then reuse that value to compute the total price for a flight.
To get the total for the entire transport (sum over all basket items), you'd also need to pass data between components. A BasketService
that keeps track of your basket items can help with that. I created a little stackblitz to demonstrate how to do this: https://stackblitz.com/edit/angular-tpenou
The relevant parts are:
export class BasketItemComponent implements OnDestroy
@Input() flight: Flight;
paxOptions = [0, 1, 2, 3, 4];
pax = 0;
constructor(private basketService: BasketService)
this.basketService.registerBasketItemComponent(this);
ngOnDestroy(): void
this.basketService.removeBasketItemComponent(this);
get total()
return this.flight.flightPrice * this.pax;
And the template:
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between" >
<p fxFlex="25">flight['flightName']</p>
<p fxFlex="17">flight['flightClass']</p>
<p fxFlex="18"> number</p>
<p fxFlex="15" fxLayout="column">
<mat-select placeholder="Ticket(s)" [(ngModel)]="pax">
<mat-option *ngFor="let pax of paxOptions" [value]="pax"> pax </mat-option>
</mat-select>
</p>
<p fxFlex="25">AED total </p>
</div>
And the BasketService
:
export class BasketService
basketItems: BasketItemComponent[] = [];
constructor()
get total()
return this.basketItems.reduce( (a, b) => a + b.total, 0);
registerBasketItemComponent(c: BasketItemComponent)
this.basketItems.push(c);
removeBasketItemComponent(c: BasketItemComponent)
this.basketItems.splice(this.basketItems.indexOf(c), 1);
You would also have to alter your for loop to make use of your newly created custom component:
<form novalidate #form="ngForm">
<div class="flight-table">
<header fxLayout="row" fxLayoutAlign="space-between">
<div fxFlex="25">Flights</div>
<div fxFlex="17">Class</div>
<div fxFlex="18">Price (AED)</div>
<div fxFlex="15">PAX</div>
<div fxFlex="25">Total</div>
</header>
<main>
<app-basket-item [flight]="flight" *ngFor="let flight of data.flights; let i = index">
</app-basket-item>
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between">
<p class="capitalize" fxFlex="75"><strong>Total transport</strong></p>
<p class="center-text" fxFlex="25"><strong>AED transportTotal</strong></p>
</div>
</main>
</div>
</form>
Dude thank you so much for your answer. The solution seems much more involved than I had hoped it would be though. Could it be any shorter?
– Nelson King
Mar 9 at 15:21
2
@NelsonKing Of course you can do it in a shorter fashion, but it's not necessarily ideal from a maintainability perspective. Created an alternative version on stackblitz: stackblitz.com/edit/angular-yz1hqc
– Jan Wendland
Mar 9 at 15:34
I hear you. Thank you so much.
– Nelson King
Mar 9 at 17:31
1
@NelsonKing I adapted the latter stackblitz (stackblitz.com/edit/angular-yz1hqc) with a change listener on the pax element that populates aselectedFlights
object onAppComponent
when the number of pax changes. Have a look and let me know if you have any questions. (Note theconsole.log
ofthis.selectedFlights
which prints the object in the structure you desire)
– Jan Wendland
Mar 10 at 10:09
1
@NelsonKing Maybe typescript is ranting because thereduce
is actually a combination of map and reduce and the type inference has issues with that. Does it work if you write it like this:this.data.flights.map(f => Number.parseFloat(f['flightPrice']) * (f['pax'] || 0)).reduce((total, flightPrice) => total + flightPrice, 0);
? If that's not the issue please fork my stackblitz and mock the data as it is returned from your API so I have somewhere to start from
– Jan Wendland
Mar 11 at 11:56
|
show 5 more comments
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55075802%2fgrab-values-from-dynamic-form-content-angular%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
I would recommend that you create a dedicated component for your basket items.
You then have an isolated scope you can work with and i.e. use [(ngModel)]
to set the selected number of pax on your component (for which you have to import the FormsModule
in your app/feature module).
You can then reuse that value to compute the total price for a flight.
To get the total for the entire transport (sum over all basket items), you'd also need to pass data between components. A BasketService
that keeps track of your basket items can help with that. I created a little stackblitz to demonstrate how to do this: https://stackblitz.com/edit/angular-tpenou
The relevant parts are:
export class BasketItemComponent implements OnDestroy
@Input() flight: Flight;
paxOptions = [0, 1, 2, 3, 4];
pax = 0;
constructor(private basketService: BasketService)
this.basketService.registerBasketItemComponent(this);
ngOnDestroy(): void
this.basketService.removeBasketItemComponent(this);
get total()
return this.flight.flightPrice * this.pax;
And the template:
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between" >
<p fxFlex="25">flight['flightName']</p>
<p fxFlex="17">flight['flightClass']</p>
<p fxFlex="18"> number</p>
<p fxFlex="15" fxLayout="column">
<mat-select placeholder="Ticket(s)" [(ngModel)]="pax">
<mat-option *ngFor="let pax of paxOptions" [value]="pax"> pax </mat-option>
</mat-select>
</p>
<p fxFlex="25">AED total </p>
</div>
And the BasketService
:
export class BasketService
basketItems: BasketItemComponent[] = [];
constructor()
get total()
return this.basketItems.reduce( (a, b) => a + b.total, 0);
registerBasketItemComponent(c: BasketItemComponent)
this.basketItems.push(c);
removeBasketItemComponent(c: BasketItemComponent)
this.basketItems.splice(this.basketItems.indexOf(c), 1);
You would also have to alter your for loop to make use of your newly created custom component:
<form novalidate #form="ngForm">
<div class="flight-table">
<header fxLayout="row" fxLayoutAlign="space-between">
<div fxFlex="25">Flights</div>
<div fxFlex="17">Class</div>
<div fxFlex="18">Price (AED)</div>
<div fxFlex="15">PAX</div>
<div fxFlex="25">Total</div>
</header>
<main>
<app-basket-item [flight]="flight" *ngFor="let flight of data.flights; let i = index">
</app-basket-item>
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between">
<p class="capitalize" fxFlex="75"><strong>Total transport</strong></p>
<p class="center-text" fxFlex="25"><strong>AED transportTotal</strong></p>
</div>
</main>
</div>
</form>
Dude thank you so much for your answer. The solution seems much more involved than I had hoped it would be though. Could it be any shorter?
– Nelson King
Mar 9 at 15:21
2
@NelsonKing Of course you can do it in a shorter fashion, but it's not necessarily ideal from a maintainability perspective. Created an alternative version on stackblitz: stackblitz.com/edit/angular-yz1hqc
– Jan Wendland
Mar 9 at 15:34
I hear you. Thank you so much.
– Nelson King
Mar 9 at 17:31
1
@NelsonKing I adapted the latter stackblitz (stackblitz.com/edit/angular-yz1hqc) with a change listener on the pax element that populates aselectedFlights
object onAppComponent
when the number of pax changes. Have a look and let me know if you have any questions. (Note theconsole.log
ofthis.selectedFlights
which prints the object in the structure you desire)
– Jan Wendland
Mar 10 at 10:09
1
@NelsonKing Maybe typescript is ranting because thereduce
is actually a combination of map and reduce and the type inference has issues with that. Does it work if you write it like this:this.data.flights.map(f => Number.parseFloat(f['flightPrice']) * (f['pax'] || 0)).reduce((total, flightPrice) => total + flightPrice, 0);
? If that's not the issue please fork my stackblitz and mock the data as it is returned from your API so I have somewhere to start from
– Jan Wendland
Mar 11 at 11:56
|
show 5 more comments
I would recommend that you create a dedicated component for your basket items.
You then have an isolated scope you can work with and i.e. use [(ngModel)]
to set the selected number of pax on your component (for which you have to import the FormsModule
in your app/feature module).
You can then reuse that value to compute the total price for a flight.
To get the total for the entire transport (sum over all basket items), you'd also need to pass data between components. A BasketService
that keeps track of your basket items can help with that. I created a little stackblitz to demonstrate how to do this: https://stackblitz.com/edit/angular-tpenou
The relevant parts are:
export class BasketItemComponent implements OnDestroy
@Input() flight: Flight;
paxOptions = [0, 1, 2, 3, 4];
pax = 0;
constructor(private basketService: BasketService)
this.basketService.registerBasketItemComponent(this);
ngOnDestroy(): void
this.basketService.removeBasketItemComponent(this);
get total()
return this.flight.flightPrice * this.pax;
And the template:
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between" >
<p fxFlex="25">flight['flightName']</p>
<p fxFlex="17">flight['flightClass']</p>
<p fxFlex="18"> number</p>
<p fxFlex="15" fxLayout="column">
<mat-select placeholder="Ticket(s)" [(ngModel)]="pax">
<mat-option *ngFor="let pax of paxOptions" [value]="pax"> pax </mat-option>
</mat-select>
</p>
<p fxFlex="25">AED total </p>
</div>
And the BasketService
:
export class BasketService
basketItems: BasketItemComponent[] = [];
constructor()
get total()
return this.basketItems.reduce( (a, b) => a + b.total, 0);
registerBasketItemComponent(c: BasketItemComponent)
this.basketItems.push(c);
removeBasketItemComponent(c: BasketItemComponent)
this.basketItems.splice(this.basketItems.indexOf(c), 1);
You would also have to alter your for loop to make use of your newly created custom component:
<form novalidate #form="ngForm">
<div class="flight-table">
<header fxLayout="row" fxLayoutAlign="space-between">
<div fxFlex="25">Flights</div>
<div fxFlex="17">Class</div>
<div fxFlex="18">Price (AED)</div>
<div fxFlex="15">PAX</div>
<div fxFlex="25">Total</div>
</header>
<main>
<app-basket-item [flight]="flight" *ngFor="let flight of data.flights; let i = index">
</app-basket-item>
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between">
<p class="capitalize" fxFlex="75"><strong>Total transport</strong></p>
<p class="center-text" fxFlex="25"><strong>AED transportTotal</strong></p>
</div>
</main>
</div>
</form>
Dude thank you so much for your answer. The solution seems much more involved than I had hoped it would be though. Could it be any shorter?
– Nelson King
Mar 9 at 15:21
2
@NelsonKing Of course you can do it in a shorter fashion, but it's not necessarily ideal from a maintainability perspective. Created an alternative version on stackblitz: stackblitz.com/edit/angular-yz1hqc
– Jan Wendland
Mar 9 at 15:34
I hear you. Thank you so much.
– Nelson King
Mar 9 at 17:31
1
@NelsonKing I adapted the latter stackblitz (stackblitz.com/edit/angular-yz1hqc) with a change listener on the pax element that populates aselectedFlights
object onAppComponent
when the number of pax changes. Have a look and let me know if you have any questions. (Note theconsole.log
ofthis.selectedFlights
which prints the object in the structure you desire)
– Jan Wendland
Mar 10 at 10:09
1
@NelsonKing Maybe typescript is ranting because thereduce
is actually a combination of map and reduce and the type inference has issues with that. Does it work if you write it like this:this.data.flights.map(f => Number.parseFloat(f['flightPrice']) * (f['pax'] || 0)).reduce((total, flightPrice) => total + flightPrice, 0);
? If that's not the issue please fork my stackblitz and mock the data as it is returned from your API so I have somewhere to start from
– Jan Wendland
Mar 11 at 11:56
|
show 5 more comments
I would recommend that you create a dedicated component for your basket items.
You then have an isolated scope you can work with and i.e. use [(ngModel)]
to set the selected number of pax on your component (for which you have to import the FormsModule
in your app/feature module).
You can then reuse that value to compute the total price for a flight.
To get the total for the entire transport (sum over all basket items), you'd also need to pass data between components. A BasketService
that keeps track of your basket items can help with that. I created a little stackblitz to demonstrate how to do this: https://stackblitz.com/edit/angular-tpenou
The relevant parts are:
export class BasketItemComponent implements OnDestroy
@Input() flight: Flight;
paxOptions = [0, 1, 2, 3, 4];
pax = 0;
constructor(private basketService: BasketService)
this.basketService.registerBasketItemComponent(this);
ngOnDestroy(): void
this.basketService.removeBasketItemComponent(this);
get total()
return this.flight.flightPrice * this.pax;
And the template:
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between" >
<p fxFlex="25">flight['flightName']</p>
<p fxFlex="17">flight['flightClass']</p>
<p fxFlex="18"> number</p>
<p fxFlex="15" fxLayout="column">
<mat-select placeholder="Ticket(s)" [(ngModel)]="pax">
<mat-option *ngFor="let pax of paxOptions" [value]="pax"> pax </mat-option>
</mat-select>
</p>
<p fxFlex="25">AED total </p>
</div>
And the BasketService
:
export class BasketService
basketItems: BasketItemComponent[] = [];
constructor()
get total()
return this.basketItems.reduce( (a, b) => a + b.total, 0);
registerBasketItemComponent(c: BasketItemComponent)
this.basketItems.push(c);
removeBasketItemComponent(c: BasketItemComponent)
this.basketItems.splice(this.basketItems.indexOf(c), 1);
You would also have to alter your for loop to make use of your newly created custom component:
<form novalidate #form="ngForm">
<div class="flight-table">
<header fxLayout="row" fxLayoutAlign="space-between">
<div fxFlex="25">Flights</div>
<div fxFlex="17">Class</div>
<div fxFlex="18">Price (AED)</div>
<div fxFlex="15">PAX</div>
<div fxFlex="25">Total</div>
</header>
<main>
<app-basket-item [flight]="flight" *ngFor="let flight of data.flights; let i = index">
</app-basket-item>
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between">
<p class="capitalize" fxFlex="75"><strong>Total transport</strong></p>
<p class="center-text" fxFlex="25"><strong>AED transportTotal</strong></p>
</div>
</main>
</div>
</form>
I would recommend that you create a dedicated component for your basket items.
You then have an isolated scope you can work with and i.e. use [(ngModel)]
to set the selected number of pax on your component (for which you have to import the FormsModule
in your app/feature module).
You can then reuse that value to compute the total price for a flight.
To get the total for the entire transport (sum over all basket items), you'd also need to pass data between components. A BasketService
that keeps track of your basket items can help with that. I created a little stackblitz to demonstrate how to do this: https://stackblitz.com/edit/angular-tpenou
The relevant parts are:
export class BasketItemComponent implements OnDestroy
@Input() flight: Flight;
paxOptions = [0, 1, 2, 3, 4];
pax = 0;
constructor(private basketService: BasketService)
this.basketService.registerBasketItemComponent(this);
ngOnDestroy(): void
this.basketService.removeBasketItemComponent(this);
get total()
return this.flight.flightPrice * this.pax;
And the template:
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between" >
<p fxFlex="25">flight['flightName']</p>
<p fxFlex="17">flight['flightClass']</p>
<p fxFlex="18"> number</p>
<p fxFlex="15" fxLayout="column">
<mat-select placeholder="Ticket(s)" [(ngModel)]="pax">
<mat-option *ngFor="let pax of paxOptions" [value]="pax"> pax </mat-option>
</mat-select>
</p>
<p fxFlex="25">AED total </p>
</div>
And the BasketService
:
export class BasketService
basketItems: BasketItemComponent[] = [];
constructor()
get total()
return this.basketItems.reduce( (a, b) => a + b.total, 0);
registerBasketItemComponent(c: BasketItemComponent)
this.basketItems.push(c);
removeBasketItemComponent(c: BasketItemComponent)
this.basketItems.splice(this.basketItems.indexOf(c), 1);
You would also have to alter your for loop to make use of your newly created custom component:
<form novalidate #form="ngForm">
<div class="flight-table">
<header fxLayout="row" fxLayoutAlign="space-between">
<div fxFlex="25">Flights</div>
<div fxFlex="17">Class</div>
<div fxFlex="18">Price (AED)</div>
<div fxFlex="15">PAX</div>
<div fxFlex="25">Total</div>
</header>
<main>
<app-basket-item [flight]="flight" *ngFor="let flight of data.flights; let i = index">
</app-basket-item>
<div class="flights-body--row" fxLayout="row" fxLayoutAlign="space-between">
<p class="capitalize" fxFlex="75"><strong>Total transport</strong></p>
<p class="center-text" fxFlex="25"><strong>AED transportTotal</strong></p>
</div>
</main>
</div>
</form>
edited Mar 9 at 14:32
answered Mar 9 at 14:09
Jan WendlandJan Wendland
785415
785415
Dude thank you so much for your answer. The solution seems much more involved than I had hoped it would be though. Could it be any shorter?
– Nelson King
Mar 9 at 15:21
2
@NelsonKing Of course you can do it in a shorter fashion, but it's not necessarily ideal from a maintainability perspective. Created an alternative version on stackblitz: stackblitz.com/edit/angular-yz1hqc
– Jan Wendland
Mar 9 at 15:34
I hear you. Thank you so much.
– Nelson King
Mar 9 at 17:31
1
@NelsonKing I adapted the latter stackblitz (stackblitz.com/edit/angular-yz1hqc) with a change listener on the pax element that populates aselectedFlights
object onAppComponent
when the number of pax changes. Have a look and let me know if you have any questions. (Note theconsole.log
ofthis.selectedFlights
which prints the object in the structure you desire)
– Jan Wendland
Mar 10 at 10:09
1
@NelsonKing Maybe typescript is ranting because thereduce
is actually a combination of map and reduce and the type inference has issues with that. Does it work if you write it like this:this.data.flights.map(f => Number.parseFloat(f['flightPrice']) * (f['pax'] || 0)).reduce((total, flightPrice) => total + flightPrice, 0);
? If that's not the issue please fork my stackblitz and mock the data as it is returned from your API so I have somewhere to start from
– Jan Wendland
Mar 11 at 11:56
|
show 5 more comments
Dude thank you so much for your answer. The solution seems much more involved than I had hoped it would be though. Could it be any shorter?
– Nelson King
Mar 9 at 15:21
2
@NelsonKing Of course you can do it in a shorter fashion, but it's not necessarily ideal from a maintainability perspective. Created an alternative version on stackblitz: stackblitz.com/edit/angular-yz1hqc
– Jan Wendland
Mar 9 at 15:34
I hear you. Thank you so much.
– Nelson King
Mar 9 at 17:31
1
@NelsonKing I adapted the latter stackblitz (stackblitz.com/edit/angular-yz1hqc) with a change listener on the pax element that populates aselectedFlights
object onAppComponent
when the number of pax changes. Have a look and let me know if you have any questions. (Note theconsole.log
ofthis.selectedFlights
which prints the object in the structure you desire)
– Jan Wendland
Mar 10 at 10:09
1
@NelsonKing Maybe typescript is ranting because thereduce
is actually a combination of map and reduce and the type inference has issues with that. Does it work if you write it like this:this.data.flights.map(f => Number.parseFloat(f['flightPrice']) * (f['pax'] || 0)).reduce((total, flightPrice) => total + flightPrice, 0);
? If that's not the issue please fork my stackblitz and mock the data as it is returned from your API so I have somewhere to start from
– Jan Wendland
Mar 11 at 11:56
Dude thank you so much for your answer. The solution seems much more involved than I had hoped it would be though. Could it be any shorter?
– Nelson King
Mar 9 at 15:21
Dude thank you so much for your answer. The solution seems much more involved than I had hoped it would be though. Could it be any shorter?
– Nelson King
Mar 9 at 15:21
2
2
@NelsonKing Of course you can do it in a shorter fashion, but it's not necessarily ideal from a maintainability perspective. Created an alternative version on stackblitz: stackblitz.com/edit/angular-yz1hqc
– Jan Wendland
Mar 9 at 15:34
@NelsonKing Of course you can do it in a shorter fashion, but it's not necessarily ideal from a maintainability perspective. Created an alternative version on stackblitz: stackblitz.com/edit/angular-yz1hqc
– Jan Wendland
Mar 9 at 15:34
I hear you. Thank you so much.
– Nelson King
Mar 9 at 17:31
I hear you. Thank you so much.
– Nelson King
Mar 9 at 17:31
1
1
@NelsonKing I adapted the latter stackblitz (stackblitz.com/edit/angular-yz1hqc) with a change listener on the pax element that populates a
selectedFlights
object on AppComponent
when the number of pax changes. Have a look and let me know if you have any questions. (Note the console.log
of this.selectedFlights
which prints the object in the structure you desire)– Jan Wendland
Mar 10 at 10:09
@NelsonKing I adapted the latter stackblitz (stackblitz.com/edit/angular-yz1hqc) with a change listener on the pax element that populates a
selectedFlights
object on AppComponent
when the number of pax changes. Have a look and let me know if you have any questions. (Note the console.log
of this.selectedFlights
which prints the object in the structure you desire)– Jan Wendland
Mar 10 at 10:09
1
1
@NelsonKing Maybe typescript is ranting because the
reduce
is actually a combination of map and reduce and the type inference has issues with that. Does it work if you write it like this: this.data.flights.map(f => Number.parseFloat(f['flightPrice']) * (f['pax'] || 0)).reduce((total, flightPrice) => total + flightPrice, 0);
? If that's not the issue please fork my stackblitz and mock the data as it is returned from your API so I have somewhere to start from– Jan Wendland
Mar 11 at 11:56
@NelsonKing Maybe typescript is ranting because the
reduce
is actually a combination of map and reduce and the type inference has issues with that. Does it work if you write it like this: this.data.flights.map(f => Number.parseFloat(f['flightPrice']) * (f['pax'] || 0)).reduce((total, flightPrice) => total + flightPrice, 0);
? If that's not the issue please fork my stackblitz and mock the data as it is returned from your API so I have somewhere to start from– Jan Wendland
Mar 11 at 11:56
|
show 5 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55075802%2fgrab-values-from-dynamic-form-content-angular%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown