How can I show forms one after another in angularjs? - javascript

I am trying to ask one question at a time like "How much did you score in X", when a user selects any of the given buttons, next question will be displayed, this will continue to a certain limit say 10.
Currently I'm displaying all those questions through a loop ng-repeat.
<div ng-repeat="subcode in subjects">
<label class="control-label" for="radios">How much did you score in SUBJECT {{subcode}}?</label>
<div class="btn-group btn-group-m">
<button ng-repeat="grade in gradebuttons" ng-click="saveclick(subcode,grade)" type="button" class="btn btn-default">{{grade}}</button>
</div>
<br/>
</div>
<button ng-click="calculate()">Calculate</button>
my calculate function uses the subcode,grade from saveclick function to process them and display the result just beneath the button.
Also I'm not sure how do I allow user to select just one button, like if they select A1 and again selects A2 in the same subject, previous A1 should be replaced. At this time all grades are selected from all subjects.

You can use ng-show to show current step by using $index and create a variable like currentStep
<div ng-repeat="subcode in subjects" ng-show="currentStep == $index">
which shows only the current question in the list while hiding others
You should update currentStep everytime you save a click to jump up to next question...
$scope.saveclick = function (subcode,grade) {
$scope.answers.push({'subcode' : subcode, 'grade' : grade});
$scope.currentStep++;
}
here is my PLUNKER

try something like
<div ng-repeat="i in [1,2,3,4,5,6,7,8,9]" ng-click="increment(j)" ng-show="$index+1 == j">
<div >{{$index}} How much did you score in SUBJECT {{i}}</div>
</div>`
increment is the scope method which increments the index.

I think you need something like this:
<div ng-repeat="subcode in subjects">
<label class="control-label" for="radios">How much did you score in SUBJECT {{subcode}}?</label>
<div class="btn-group btn-group-m">
<button ng-repeat="grade in gradebuttons" ng-click="saveclick(subcode,grade)"
type="button" class="btn btn-default" ng-show="selectedGrades[subjects[$parent.$index-1]] || $parent.$index== 0" ng-class="{selected: selectedGrades[subcode] == grade}" >{{grade}}</button>
</div>
<br/>
</div>
<button ng-click="calculate()">Calculate</button>
Your JS code:
$scope.saveclick = function (subcode,grade){
$scope.selectedGrades[subcode] = grade; //replace previous selected grade.
};
$scope.selectedGrades = {};
Try:
ng-show="selectedGrades[subjects[$parent.$index-1]] || $parent.$index== 0" to show 1 question at a time and show next when the previous question has been answered.
ng-class="{selected: selectedGrades[subcode] == grade}" to highlight the current selected grade for the subject.
DEMO
If you need to hide the entire question instead of just buttons, move the ng-show to the question and change it to ng-show="selectedGrades[subjects[$index-1]] || $index== 0"
DEMO
If you need to hide the question as soon as it's answer, try: ng-show="(selectedGrades[subjects[$index-1]] || $index== 0) && !selectedGrades[subcode]"
DEMO

Related

HTML Quiz Multiple Form Submission via Email

I have created a quiz using HTML currently there are 5 questions in total and I have it coded so that only the question being answered appears so users taking the quiz cannot see upcoming questions. The way I have done it using multiple forms so for each question there is a separate form this makes it a pain to be able to send all of the answers to the questions via email, currently it only sends the last questions... Is there a way I can combine my forms into one big form or possibly have a button that submits all my forms?
Any help would be greatly appreciated :)
Currently, it won't let me send code. I'll try again.
Hi and welcome to Stackoverflow!
If I understood correctly, you can split the form in sections like the following:
<form POST="..." onsubmit="onNextStep">
<div class='form-section' id='question-1'>
<!-- code here -->
</div>
<div class='form-section' id='question-2'>
<!-- code here -->
</div>
<div class='form-section' id='question-3'>
<!-- code here -->
</div>
<div class="form-footer">
<button type="submit"> Next </button>
</div>
</form>
and then add an event on button click that increments the current step (0, 1, 2...) and hide all the divs without the correct id and then submit the form when on the final step.
let totalSteps = 3;
let step = 1;
function onNextStep(e) {
const currentStep = step;
const nextStep = step + 1;
// in the last step change the button text
if ( nextStep == totalSteps ) {
document.querySelector('form button[type="submit"]').innerText = "Submit"
}
// If the last step is completed, submit the form.
if ( nextStep > totalSteps ) {
return
}
// prevent form submission
e.preventDefault()
// hide the current section
document.getElementById('question-'+nextStep).style.display = 'block'
// show the next section
document.getElementById('question-'+curentStep).style.display = 'none'
// increment our steps counter
step += 1
}
This example with some adjustments should fit your case.
Just use the one form.
Use the fieldset tag to encapsulate your questions then use javascript to hide and show as needed.
let questions = document.querySelectorAll(".question");
let answerButtons = document.querySelectorAll(".question button");
for (var i = 0; i < answerButtons.length; i++) {
answerButtons[i].addEventListener("click",function() {
//Get Closest question
var question = this.closest(".question");
//Remove Active class
question.classList.remove("active");
//Add active class to next sibling
question.nextElementSibling.classList.add("active");
});
}
.question:not(.active) {
display: none;
}
<form action="">
<fieldset class="question active">
<legend>Question 1 of 3</legend>
<label>What is your name? <input type="text" name="qName"></label>
<button type="button">Submit Answer</button>
</fieldset>
<fieldset class="question">
<legend>Question 2 of 3</legend>
<label>What is your quest? <input type="text" name="qQuest"></label>
<button type="button">Submit Answer</button>
</fieldset>
<fieldset class="question">
<legend>Question 3 of 3</legend>
<label>What is your quest? <input type="text" name="qName"></label>
<button type="submit">Submit Quiz</button>
</fieldset>
</form>

Keep track of which element was clicked,then read data accordingly in Javascript/Jquery

I have 3 buttons/divs with ids as "BTN_a.. b.. c", which respectively enable the visibility of 3 different divs with one or more input fields. BTN_a shows DIV_A_inputs, and hides others.. and so on. The idea is that when the button id="BTN_Post_Wall" is clicked, data checks are performed, and if everything is okay, data is sent to a php file to do stuff. How do I keep track of Which Button was pressed, and which input fields are visible.. so that when "BTN_Post_Wall" is clicked, only those input fields are read. Is there some sort of Global Variable I can change the value of.. e.g. var Pressed = a and where do I add this function? is it possible to add some kind of Dummy attribute to any element like $("#DIV_abc").attrib("dummy") = "A_clicked" and then read it with BTN_Post_Wall?
In other words, if Btn A was clicked, and then if BTN_Post_Wall is clicked, it means then only INP_A value needs to be read, checked and sent as ajax. If button C is pressed, followed by BTN_Post_Wall, then only INP_C_1, INP_C_2, and INP_C_3 have to be handled. Where can I store this info and proceed with just one button?
All help is much appreciated. Thank you so much!!
function CH_ANGE(th, txt)
{ switch(txt)
{ case "a_click":
$("#DIV_A_inputs").show();
$("#DIV_B_inputs").hide();
$("#DIV_C_inputs").hide();
break;
case "b_click":
$("#DIV_A_inputs").hide();
$("#DIV_B_inputs").show();
$("#DIV_C_inputs").hide();
break;
case "c_click":
$("#DIV_A_inputs").hide();
$("#DIV_B_inputs").hide();
$("#DIV_C_inputs").show();
break;
}
MAIN_UI.php file is as follows:
<div id="DV_post_type">
<div id="BTN_a" onclick="CH_ANGE(this, 'a_click')">Button A</div>
<div id="BTN_b" onclick="CH_ANGE(this, 'b_click')">Button B</div>
<div id="BTN_c" onclick="CH_ANGE(this, 'c_click')">Button C</div>
<button id="BTN_Post_Wall" onClick="POST_AJAX_INP_to_PHP_BUTTON()">POST</button>
</div>
<div id="DIV_abc">
<div id="DIV_A_inputs">Div_A and other content
<input TYPE="TEXT" ID="inp_A" NAME="INP_A">
</div>
<div id="DIV_B_inputs">Div_B and other content
<input TYPE="TEXT" ID="inp_B_1" NAME="INP_B_1">
<input TYPE="TEXT" ID="inp_B_2" NAME="INP_B_2">
<input TYPE="TEXT" ID="inp_B_3" NAME="INP_B_3">
</div>
<div id="DIV_C_inputs">
<input TYPE="TEXT" ID="inp_C_1" NAME="INP_C_1">
<input TYPE="TEXT" ID="inp_C_2" NAME="INP_C_2">
</div>
</div>

Angular - change the content from Radio button on submit button

I'm stuck in a problem where I want to change a div based on which radio button is clicked. I've been using it without form tag and it changes as soon as I click on the button, NOT ON SUBMIT BUTTON. I want it the other way, i.e, it should submit value on button click and then changes the content, any suggestion what I might've been doing wrong.
It should show different questions based on the radio I select. In the case of YES it shows other and in case of NO, another. Then further questions will be the same. (This logic works fine)
onItemChange(value) {
console.log(value)
this.previous = false;
if (value == 1) {
this.yesOption = true;
} else if (value == 0) {
this.noOption = true;
}
}
Working demo: https://stackblitz.com/edit/angular-ivy-4lhhxh
I created a demo that implements what you asked.
HTML
<div>
<h3>{{ 'Question ' + (currentQuestionIndex+1) }}</h3>
<div>
<div *ngIf="currentQuestionIndex === 0">
<div class="">
<label>Yes</label>
<input value="yes" [(ngModel)]="firstAnswer" type="radio">
</div>
<div class="">
<label>No</label>
<input value="no" [(ngModel)]="firstAnswer" type="radio">
</div>
</div>
<p *ngIf="currentQuestionIndex > 1">Normal question</p>
<p *ngIf="currentQuestionIndex === 1">You selected {{ firstAnswer === 'yes' ? '"Yes"' : '"No"' }} for question 1</p>
</div>
<button (click)="next()">Next</button>
</div>
component.ts
export class AppComponent {
questionsLength = 5;
questions = Array(this.questionsLength);
currentQuestionIndex = 0;
firstAnswer;
next() {
if (this.currentQuestionIndex < this.questionsLength - 1) {
this.currentQuestionIndex++;
}
}
}
You can use ngModel on the radio input and later use that variable to check what has been selected.
Update
If you want to display some divs conditionally:
<ng-container *ngIf="currentQuestionIndex === 1">
<div *ngIf="firstAnswer === 'yes'">You selected "Yes" for question 1</div>
<div *ngIf="firstAnswer === 'no'">You selected "No" for question 1</div>
</ng-container>
If you are not using a form, you need to either:
Store the value somewhere else using [(ngModel)] (don't forget to change configuration to Standalone), or..
Have an object with values and assign individual values in onItemChange callback (if you don't want to use [(ngModel)]
Use #ViewChild to reference the input and get the value (which is.. ugly)
In any case, the logic you currently have in the onItemChange would have to be moved to the nextQuestion.
Per your request, I have made an example on StackBlitz: https://stackblitz.com/edit/angular-ivy-2mwzxd

Issue using Angular, Local Storage and NgIf

I'm currently building an application that is making use of information stored in local storage as the user works their way through the application.
When they get to one particular question, they'll be shown different text and options depending on the choice they select. If they select "one" applicant, then on a following step they will be shown a single input field. If they select "two" applicants they'll be shown two input fields.
I've been able to get this to a certain extent, it's just that it doesn't work exactly how I expect it to. It will only use the value in local storage after the application is reloaded, not during the current session.
Here's a rough example. If I've never used the application before and there is nothing in my local storage and I select "two" applicants:
Screenshot One
On the subsequent step, it only shows me one field (this is default, but there should be two because that's what I selected) and it hasn't populated the text text:
Screenshot Two
Now, if I reload the application and go back to the same question and select "one" this time:
Screenshot Three
This time around, it will show the text associated with two users and the two input fields, even though I selected "one":
Screenshot Four
So it appears to have a "delay" (for want of a better word) where it will only show the choice made on the last session.
I've tried a few variants of how to tackle this, but they all seem to give me the same result, and I've already looked around Stackoverflow and Google to see if anyone has a similar problem but I haven't be able to find anything that helps me.
Here's the relevant code from my component.html:
<mat-step label="Step 2" [stepControl]="secondFormGroup">
<form [formGroup]="secondFormGroup">
<div ng-controller="step2">
<h2>How many people are applying?</h2>
<mat-button-toggle-group>
<div *ngFor="let step2option of step2options">
<mat-button-toggle (click)="getStep2Val(Oname);" class="btn btn-primary step-button" id="{{step2option.id}}" [ngClass]="status ? 'selected' : ''"><span #Oname>{{step2option.text}}</span></mat-button-toggle>
</div>
</mat-button-toggle-group>
<div>You chose <strong>{{ selectedStep2option }}!</strong></div>
<button mat-stroked-button (click)="goToNext()" class="btn btn-secondary continue-btn" [disabled]="selectedStep2option === 'none'">Continue</button>
</div>
</form>
</mat-step>
<mat-step label="Step 3" [stepControl]="thirdFormGroup">
<form [formGroup]="thirdFormGroup">
<div ng-controller="step3">
<h2>What <span *ngIf="users === 'One'">{{text1app}}</span> <span *ngIf="users === 'Two'">{{text2app}}</span>?</h2>
<div class="input-group" *ngIf="users == 'One' || 'Two'" >
<p>Applicant 1</p>
<span class="input-group-addon">£</span>
<input type="number" (change)="getStep3Val()" (keyup)="getStep3Val()" [(ngModel)]="app1income" [ngModelOptions]="{standalone: true}" id="step3appVal" min="0" step="500" data-number-to-fixed="2" data-number-stepfactor="500" />
{{app1income}}
</div>
<div class="input-group" *ngIf="users == 'Two'">
<p>Applicant 2</p>
<span class="input-group-addon">£</span>
<input type="number" (change)="getStep4Val()" (keyup)="getStep4Val()" [(ngModel)]="app2income" [ngModelOptions]="{standalone: true}" id="step4appVal" min="0" step="500" data-number-to-fixed="2" data-number-stepfactor="500" />
{{app2income}}
</div>
<button mat-stroked-button (click)="goToNext()" class="btn btn-secondary continue-btn" [disabled]="app1income === 0">Continue</button>
</div>
</form>
</mat-step>
And from my component.ts:
users: string;
getUsers() {
this.users = this.readLocalStorageValue('Number of applicants');
}
readLocalStorageValue(key: string): string {
return localStorage.getItem(key);
}
selectedStep2option: string = 'none';
step2options = [
{
text: 'One',
id: 'step2one'
},
{
text: 'Two',
id: 'step2two'
}
];
getStep2Val (Oname: any) {
this.selectedStep2option = Oname.textContent;
localStorage.setItem('Number of applicants', Oname.textContent);
}
text1app: string = 'is your income';
text2app: string = 'are your incomes';
At the moment I can't seem to figure out why there is this delay in the choice the user makes. Does anyone have any idea as to why this might be doing this? Or is this a completely long-winded way to go about it and I'm missing an much easier way of having this conditional logic. I'm pretty new to Angular so I could be going down the completely wrong track here.
Any help would be greatly appreciated.
Never mind. I figured it out. It was a simple case of having my getUsers() function call in the wrong place.
It should've been here:
<button mat-stroked-button (click)="goToNext(); getUsers()" class="btn btn-secondary continue-btn" [disabled]="selectedStep2option === 'none'">Continue</button>
Instead it was on an earlier step.
Typical case of once you ask someone for help, the solution jumps in your face.

Change the value of ng-model field based upon a conditional ng-change

I hope you guys can help me.
I want to set the value of one of my AngularJS view fields based upon a (seemingly) simple conditional statement.
And I do believe the answer is going to be so simple, yet I haven't been able to find it after more than an hour of searching and trying stuff.
I think I might be trying to use the wrong directive (I have tried stuff like ng-if and ng-change).
This is what I want to achieve:
When I change the report Frequency to be Weekly (ng-if="reportSettingsData.ReportFrequencyName.ReportFrequencyId == Enum.ReportFrequency.Weekly) set the value of my ng-model field reportSettingsData.ReportFrequencyWeekdayName = "None".
And visa-versa; When I change the report Frequency to be Monthly (ng-if="reportSettingsData.ReportFrequencyName.ReportFrequencyId != Enum.ReportFrequency.Weekly) set the value of my ng-model field reportSettingsData.ReportFrequencyMonthDayName = "None".
<!-- Frequency -->
<div class="col-md-3">
<label>Frequency</label>
<div class="input-dropdown">
<cc-dropdown cc-placeholder="Report Frequency"
ng-model="reportSettingsData.ReportFrequencyName"
ng-options="reportSettingsData.SelectableReportFrequencyNames"
cc-fields="ReportFrequencyName"
ng-change="frequencyChanged()"
cc-key-field="ReportFrequencyId"
cc-allow-search="reportSettingsData.SelectableReportFrequencyNames != null && reportSettingsData.SelectableReportFrequencyNames.length > 5"
name="iFrequencyName">
</cc-dropdown>
</div>
</div>
<!-- Week Days / Month Days -->
<div class="col-md-3">
<label>Frequency Options</label>
<div class="input-dropdown" ng-if="reportSettingsData.ReportFrequencyName.ReportFrequencyId != Enum.ReportFrequency.Weekly">
<cc-dropdown cc-placeholder="Report Frequency Option"
ng-model="reportSettingsData.ReportFrequencyMonthDayName"
ng-options="reportSettingsData.SelectableReportFrequencyMonthDays"
ng-disabled="reportSettingsData.ReportFrequencyName.ReportFrequencyId != Enum.ReportFrequency.Monthly"
cc-fields="ReportFrequencyMonthDayName"
cc-key-field="ReportFrequencyMonthDayId"
cc-allow-search="true"
name="iFrequencyMonthDays">
</cc-dropdown>
</div>
<div class="input-dropdown" ng-if="reportSettingsData.ReportFrequencyName.ReportFrequencyId == Enum.ReportFrequency.Weekly">
<cc-dropdown cc-placeholder="Report Frequency Option"
ng-model="reportSettingsData.ReportFrequencyWeekdayName"
ng-options="reportSettingsData.SelectableReportFrequencyWeekdays"
cc-fields="ReportFrequencyWeekdayName"
cc-key-field="ReportFrequencyWeekdayId"
cc-allow-search="true"
name="iFrequencyWeekdays">
</cc-dropdown>
</div>
</div>
I thank you greatly in advance!
Ng-if directive is used to remove or create a dom element based on condition, refer this https://docs.angularjs.org/api/ng/directive/ngIf.
For your use case it is not required.
Bind to ng-change event and in the function set appropriate value on the model field.
$scope.frequencyChanged = function(){
if($scope.reportSettingsData.ReportFrequencyName.ReportFrequencyId == Enum.ReportFrequency.Weekly){
$scope.reportSettingsData.ReportFrequencyWeekdayName = "None".
}
};
Hope this helps.

Categories