Way to have *ngFor loop repeat itself x number of times - javascript

Currently working on an app that calculates golf handicap so it's a simple form that takes 5 inputs of type number (18 hole score, 9 hole score, course rating, slope rating & score differential) however I will need that grouping of 5 inputs anywhere from 3-20 times (so anywhere from 45 - 100 total inputs).
Just to get it to work I haven't done any form related elements in the HTML (i.e. labels, id, name, etc.) so I am currently just using an h4 and an input to get it to work and then i'll go back and add all the extra form related stuff.
The way I am doing it now is I am using an *ngFor to loop through to give me the name of the field and then I have an input type number both inside a div so one grouping of those 5 names & inputs comes through but I want to know is there a way/how can I get it so there will be these 5 inputs repeated 3 times (instead of just repeating the HTML 3 separate times which seems excessive)? The reason for the initial 3 is that in order to calculate I need at least 3 'groupings' worth of data to do the math.
I will then need to add a button so users can add groupings for more inputs but I figure lets start here and i'll worry about adding later. I decided to go with the Template drive approach since it's such a simple form compared to a Reactive form. I know Reactive forms seem to be a better choice for dynamic forms but this form isn't so much 'dynamic' as I just want to be able to add more of the same things when users click a button.
Here is what I have so far:
HTML:
<div *ngFor="let fun of test; let i = index">
<h4>{{fun}} : {{i + 1}}</h4>
<input type="number">
</div>
TS:
test: Array <any> = [
'18 Hole Score',
'9 Hole Score',
'Course Rating',
'Slope Rating',
'Score Differential'
]
This is what it looks like, so I would want to be able to copy and repeat this group of 5 inputs a total of 3 times (and then have on a button click the ability to add a new extra grouping)

You can simply put your code inside another *ngFor. You can get a number input and make array repeatTimes from that number.
For example:
<div *ngFor="let repeat of repeatTimes">
<div *ngFor="let fun of test; let i = index">
<h4>{{fun}} : {{i + 1}}</h4>
<input type="number">
</div>
</div>
TS preferably in ngOnInit:
let repeatCount = 5;
let repeatTimes = [];
for(let i = 0; i < repeat; i++)
{
repeatTimes.push(i);
}

Related

ng-disabled on inputs from ng-repeat loop

I'm displaying inputs basing on array like this
<div data-ng-repeat="n in langInput.values">
<input type="text"
id="auction_name_{{n.selected}}"
class="form-control"
name="auction_name_{{$index}}"
data-ng-model="inputs.auction_name[$index + 1]"
data-ng-minlength="5"
data-ng-maxlength="60"
required />
<span data-ng-show="sellItem['auction_name_'+$index].$error.required">Wymagane!</span>
It also give's me ability of angularjs validation. Next after <form> is closed I want to create "next" button but I also want to do validation there so if user don't fullfill required inputs he will not be able to click it.
Array which I'm ng-repeating on is:
$scope.langInput = {
count: 3,
values: [
{
id: "1",
selected: "pl"
},
{
id: "2",
selected: "eng"
}
],
add: function () {
if (this.count < 7) {
this.values.push({id: this.count, selected: "eng"});
this.count += 1;
console.log(this.values);
}
},
remove: function () {
if (this.count > 2) {
this.values.pop();
this.count -= 1;
console.log(this.count);
}
}
};
I know I can use this ng-disabled directive however I don't know how I can check this inputs which are displayed in loop because its name is changing depending on $index of loop.
I've created plunker
My situation is that I know that I can disable button when some of element is invalid by ng-disabled="sellItem.$error" but in my form in real project I have this form much bigger and I have many ways of acomplishing form so in the end when user finish fullfilling form user still got some of inputs which are not even shown invalid.
So I can't use ng-disabled="sellItem.$error" because after user complete form he still got invalid inputs in background.
I also can not split form to many little forms because it will call 1 endpoint on submit.
What I did in real project is inject 3 different buttons and show them on correct step. Every of this button need to have ng-disabled to not let user to go to next step without completing step' inputs.
So intead of ng-disabled="sellItem.$error" I need to specify all inputs in ng-disabled of one step ( which is about 5 inputs ).
So it would look something like this:
ng-disabled="sellItem.first_input.$error &&
sellItem.second_input.$error && ..."
And I would do this but then I come to problem that I can't "loop" inside of ng-disabled and I want to "loop" inside it because names of inputs are generated by JS
name="auction_name_{{n.id}}"
they and not constant they change, user can add more inputs and delete them
at page start I have two inputs which after JS run are name="auction_name_1" and name="auction_name_2" (due to binding interpolated value) and then user can and third one name="auction_name_3"so I can't also hardcode them within ng-disabled.
I don't know how I can check this inputs which are displayed in loop because its name is changing depending on $index of loop.
Generally one stores the input as a property of the object in the array so that it stays with the object as its position in the array changes.
Also use the id property of the object:
<form name="sellItem" ng-submit="submit()">
<div data-ng-repeat="n in langInput.values">
<input type="text"
id="auction_name_{{n.selected}}"
class="form-control"
̶n̶a̶m̶e̶=̶"̶a̶u̶c̶t̶i̶o̶n̶_̶n̶a̶m̶e̶_̶{̶{̶$̶i̶n̶d̶e̶x̶}̶}̶"̶
name="auction_name_{{n.id}}"
̶d̶a̶t̶a̶-̶n̶g̶-̶m̶o̶d̶e̶l̶=̶"̶i̶n̶p̶u̶t̶s̶.̶a̶u̶c̶t̶i̶o̶n̶_̶n̶a̶m̶e̶[̶$̶i̶n̶d̶e̶x̶ ̶+̶ ̶1̶]̶"̶
data-ng-model="n.input"
data-ng-minlength="5"
data-ng-maxlength="60"
required />
<span data-ng-show="sellItem['auction_name_'+n.id].$error.required">Wymagane!</span>
<span data-ng-show="sellItem['auction_name_'+n.id].$error.minlength">Za krótkie!</span>
<span data-ng-show="sellItem['auction_name_'+n.id].$error.maxlength">Za długie!</span>
</div>
<button type="submit" ng-disabled="sellItem.$error">
{{Submit}}
</button>
</form>
Be sure to generate unique values for the id property.
Update
Added Submit button.
For more information, see
AngularJS Developer Guide - forms
AngularJS <form> Directive API Reference
AngularJS ng-submit Directive API Reference

Save state of multiple Dynamic Components on ReactJS

Hi I have this component structure:
<ScheduleApp />
<ScheduleForm />
<TeamField />
My ScheduleApp contains a form called ScheduleForm and under this form I have a field where users can specify a number of teams and depends on the number the number of TeamField is created.
My form looks like this:
And what I wanted is to save all the teams' names under my ScheduleApp component. I can save all the other states with no problem, example: the No. of Teams field with no problem but I'm stuck on how to save the Team Name fields in an array.
Here is my poor attempt on saving the array but it looks like it saves all the keystrokes I've made probably because I triggered it onChange event.
How am I suppose to solve this problem and just save the dynamic components on the parent components' state?
Now here are my codes on jsfiddle for some reason I can't make it run on the site but will post it there for easier access.
Hope I made it clear. Any help would be much appreciated!
You are pushing the current content of text box into the array on every change/keystroke. Instead what you should do is text box 1 should only modify the first index in your array. And text box 2 should only modify second field in your array and so on. On each change, replace entire content with new content.
Or a cleaner approach would be to store a teams object. And send a team number field too in the on change handler against which you can store the team name.
<input className="form-control" type="text" ref="teamName"
onChange={this.handleChange.bind(null, 'team1')} /> // pass any index or string instead of team1
...
handleChange(teamIndex, teamName) {
let { teams } = this.state;
teams[teamIndex] = teamName;
this.setState({teams: teams};
}

Selecting a subset of a JSON object & counting it

I'm having a hell of a time here, probably because I'm very new to Angular and I don't quite grok everything yet.
First the scenario, then hopefully some code:
I have a button that fetches a JSON object from an API call. It becomes $scope.collectors.
$http.post('get', $scope.formData).success(function(data) {
$scope.collectors = data.results;
...
Then I take that and make a big list of these items with checkboxes, so you can pick and choose which ones you want to work with. When you've selected the ones you want, you click another button to collect all of these together and bulk operate on them.
So that's the overall story. They task I'm having trouble with is twofold. First, I'm simply trying to count the number of items that are checked. I've done it like this:
JS:
$scope.selectedCollectors = {};
HTML:
<div ng-repeat="collector in collectors">
<input type="checkbox" name="collector-id"
value="{{collector.id}}"
ng-model="selectedCollectors[collector.id]">
</div>
<p>Debug: {{ selectedCollectors }}</p>
<p>There are {{ selectedCollectors.length }} items checked</p>
When I select items, the output of selectedCollectors is as expected:
{"8596784":true,"7458347":true}
But {{ selectedCollectors.length }} never increments or shows anything at all.
The second thing is basically what I'm trying to do is get the subset of the original JSON object to work with, based on the users selection. Other than looping through each item in $scope.collectors and comparing the ID to the IDs in selectedCollectors, is there a better more Angular-ish way to get this subset?
Something makes me feel like I should take this JSON object and turn it into a pure array, but maybe not...
Any advice or help is appreciated.
Here is my solution. http://jsfiddle.net/wittwerj/962wm/
First, I let angular add a "selected" property to the checked collector objects:
<div ng-repeat="collector in collectors">
<input type="checkbox" name="collector-id" value="{{collector.id}}"
ng-model="collector.selected" />
</div>
Then a second ng-repeat creates a filtered subset of selected collectors (see this question):
<div ng-repeat="collector in (selectedCollectors = (collectors | filter:{selected: true}))">
Note that the second ng-repeat is not generating any markup - just the selectedCollectors array, which can be accessed like a scope variable.

restricting the user to enter data in only one among all text fields available in jsp

Rs. 5 Rs.10 Rs.20 Rs.50 Rs.100 Rs.500 Rs.1000
There are seven text fields mentioned as above in a row of the table.
The requirement is we need to restrict the user to enter data in only one of the seven text fields displayed.Remember that there are more than one row of such which were iterated using logic:iterate.
Please share the code for validating it.
As you have not provided the complete details, I am considering it as a Web Application, if it is not a web application then similar logic can be implemented in whatever technology it is.
1. TextField 1 onFocus="validate()"
2. TextField 2 onFocus="validate()"
3. TextField 3 onFocus="validate()"
4. TextField 4 onFocus="validate()"
5. TextField 5 onFocus="validate()"
-----
function validate(){
var a1 = document.getElementById("textField1");
var a2 = document.getElementById("textField2");
var a3 = document.getElementById("textField3");
var a4 = document.getElementById("textField4");
var a5 = document.getElementById("textField5");
if(a1.trim() == ''){
//hide all textFields other then textField1
}
if(a2.trim() == ''){
//hide all textFields other then textField2
}
}
this is one way you can do it, if number of textfield is fixed and less in number. if it is more then some dynamic logic will be needed.
Also for dynamic stuff, you can pass id on validate(this) call and simply keep that and hide others in function.
I missed your iterate stuff,
in that case you can just pass row id to validate function and in the function you try executing for loop for 7 times and similarly hide all the textfield having id ending with row id given(this depends on logic you have given an id to your textfields.)

Creating a javascript that creates a dynamic total depending on radio box checked in html form

Dearest stackoverflow friends,
I am creating an online html form and have created a javascript function to dynamically (not completely sure I'm using this word correctly) display the total due in membership fees at the bottom of the form as options are selected. The total fee depends on one's membership type, country, and method of payment. It worked perfectly when all I was calculating was the membership type and postage according to country (I used drop down forms for these two options). Now I'd like to add the third term to the equation (the method of payment - one has a choice of cheque or paypal) but I can't get it to work. I'm using radio buttons this time.
My totalling function is this (without "+ getPaypalfee()" it works just fine):
function getAmountDue()
{
var amountDue = getMembershipPrice() + getExtraPostagePrice() + getPaypalfee();
document.getElementById('amountDue').innerHTML ="Amount Due: $"+amountDue;
}
The javascript I wrote to return the paypal fee is this (it's become very convoluted and I'm not sure where I've gone wrong and how to restart!):
var paymentmethod_Fee = new Array();
paymentmethod_Fee["cheque"]=0;
paymentmethod_Fee["paypal"]=2;
function getPaypalfee()
{
var paypalFee=0;
for (var i=0; i < document.membershipform.payment_method.length; i++)
{
if (document.membershipform.payment_method[i].checked)
{
var selectedPaymentmethod = document.membershipform.payment_method[i].value;
}
}
paypalFee = paymentmethod_Fee[selectedPaymentmethod.value];
return paypalFee;
}
The html for the radio buttons looks like this:
<p>I will make payment via: <BR>
<input type="radio" id="payment_method" name="payment_method" value="cheque" checked="yes" onchange="getAmountDue()">Cheque
<input type="radio" id="payment_method" name="payment_method" value="paypal" onchange="getAmountDue()">Paypal (Add $2)
Any insights into the flaw in my logic is greatly appreciated! I'm a javascript novice and radio buttons seem to be my nemesis (I'd like to learn how to use them rather than replace them with a drop-down menu or something I know how to do already).
Thank you!
Arrays shouldn't be used to create mappings between items. What you're looking for is an object:
var fees = {
cheque: 0,
paypal: 2
};
As for your error, it's this line right here:
paypalFee = paymentmethod_Fee[selectedPaymentmethod.value];
paymentmethod_Fee is already a string. It doesn't have a value attribute.
Don't use more than one element with the same id. Doing so creates glitches. OVER 9000 glitches. So, don't use duplicate ids. Just don't. It is a maxim of web development. It will serve you well. Follow it to the letter. Or, you will have glitches. I am sure you don't want glitches. Rid yourself of glitches. Don't use duplicate ids.
(preceding paragraph tl;dr: Always have unique ids, or you get glitches.)
You should wrap your radio buttons in a div with id payment_methods. Then, use document.getElementById("payment_methods").childNodes[i] to access each successive button.
(By the way, two radio buttons with the same name are mutually exclusive, so the buttons should have identical names but different ids.)
You are using checked correctly. It's just how you're accessing elements that's causing glitches.
Hope this gets rid of your glitches.

Categories

Resources