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.
Related
I'm trying to compare a selected response from a form to the correct answer, so that I can show a "Correct!" or "Incorrect!" page next. I'm using jQuery to establish what the selected answer was for any given question, but I'm having trouble figuring out how to target the actual content of the response option instead of just it's value or some other component from the HTML, because these will be different for every question set.
Here is the html template for the questions and responses from script store.js
function renderQuestion() {
console.log("hello");
let questions = STORE.questions[questionNumber];
const questionTemplate = $( `
<div class="container" align="center">
${questions.image}
<p>${questions.questionText}<br></p>
<form method="post" onsubmit="return nextQuestion()">
<input type="radio" name="choice">${questions.responses[0]}<br>
<input type="radio" name="choice">${questions.responses[1]}<br>
<input type="radio" name="choice">${questions.responses[2]}<br>
<input type="radio" name="choice">${questions.responses[3]}<br>
<button type="submit" id="choose" value="submit">Submit</button>
</form>
</div>`);
$("main").html(questionTemplate);
}
here is the function I'm working on- the console should be logging the text of the response option but it's showing "on" when I use .val(), or undefined or some other randomness depending on what method I try:
function checkAnswer() {
$("main").on("click","#choose",function(event){
let questions = STORE.questions[questionNumber];
event.preventDefault();
console.log("clicked");
let chosenAnswer=$("input[name=choice]:checked").val();
console.log(chosenAnswer);
here is the rest of that function, displaying the correct! or incorrect! screens. It's always showing the incorrect screen right now, because I can't get the chosenAnswer variable setup correctly.
if (!chosenAnswer) {
alert ("Select One");
return;
}
if(chosenAnswer===questions.answer) {
const correctResponse = $(`
<div class="container" align="center">
${questions.image}
<h4>${questions.answer}</h4>
<p>Correct!<p>
<button type="submit" id="next" value="submit">Next</button>
</div>`);
$("main").html(correctResponse);}
else{
const inCorrectResponse = $(`
<div class="container" align="center">
${questions.image}
<p> Incorrect. <br> The correct answer is:</p>
<h4>${questions.answer}</h4>
<button type="submit" id="next" value="submit">Next</button>
</div>`);
$("main").html(inCorrectResponse);
nextQuestion();}
})
}
These are some example questions from store.js. I'm using "answer" to be able to compare the selected response to the correct response.
const STORE = {
questions: [ {
image: `<div class="image"> <img src="nettles.svg", alt="mystery plant illustration"> </div>`,
questionText: "Which plant provides the most minerals and nutrients.",
responses: [
"Licorice <i>Glycyrrhiza glabra</i>",
"Jiagulon <i>Gynostemma pentaphyllum</i>",
"Lemon Balm <i>Melissa Officianlis</i>",
"Nettles <i>Urtica dioica</i>"
],
answer: "Nettles <i>Urtica dioica</i>"
},
{
questionText: "Which Plant is known for lowering high cholesterol, high blood pressure, and improving heart function as well as improving memory, and preventing hair loss?",
responses: [
"Jiagulon <i>Gynostemma pentaphyllum</i>",
"Licorice <i>Glycyrrhiza glabra</i>",
"Nettles <i>Urtica dioica</i>",
"Lemon Balm <i>Melissa Officianlis</i>"
],
answer: "Jiagulon <i>Gynostemma pentaphyllum</i>"
},
]
}
I've tried a bunch of different suggestions from what I've been able to research, but I think I'm just not familiar enough with form submissions and jQuery.
<input type="radio" name="choice">${questions.responses[0]}
please take a look at your input element, it would return "on" since you did not assign a value for it.
it should be
<input type="radio" name="choice" value="${questions.responses[0]}">${questions.responses[0]}
Long story short, I have this div inside my app.component.html:
<div class="col-lg-6 search-div">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search for...">
<span class="input-group-btn">
<button class="btn btn-default" type="button">Go!</button>
</span>
</div>
</div>
Which shows:
And I would like for it to show available values according to a function I have in the my app.component.ts:
public getUsers() {
return this.restService.getUsers().subscribe(
jsonElements => {
var users = jsonElements;
},
error => this.errorMessage = <any>error);
}
I can even pre-store the result:
users = this.getUsers();
But then how would I filter by users?
Is there an easy way to accomplish this ?
There is already an HTML solution for what you want, the 'datalist' tag does what you want. The only problem with it is that it does not have great browser support. You can read more at https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist.
So you would use it like
<input list="users"/></label>
<datalist>
<option *ngFor='let user of users' value="user">
</datalist>
You're looking for an autocomplete.
You can find an example here with a plunker but others are available as well.
I have a form within a bootstrap modal. I would like the input fields to display the past values that the user entered the first time they filled out the form, which I am retrieving from a cloudant database. I would like these input fields to be editable so that the user can resubmit the form with any changes they may have. However, I am stuck when trying to display the past information in the input fields. I can't find any reason why these value of the input fields are not being changed.
The javascript that adds my buttons to my boostrap list-group:
var loadIotPanel = function(iotsJSON)
{
for(var iot in iotsJSON)
{
var button = $('<button/>').text(iotsJSON[iot].appID).addClass('list-group-item iot').attr({name:iotsJSON[iot].appID, "aria-label": "Quick View IoT", "data-toggle": "modal", "data-target": "#quick-view-iot-modal", type: "button"});
$('#iot-list').append(button);
}
};
The html where my button will be placed within my list-group:
<div class="row">
<div class="col-lg-4 col-md-6 col-sm-12 col-sm-12 dash-col">
<button name="edit-iots" aria-label="Edit IoTs" data-toggle="modal" data-target="#edit-iots-modal" type="button" class="icon"><span class="glyphicon glyphicon-edit gray"></span></button>
<p class="fancy-font dash-item-title">Your IoTs</p>
<button name="add-iot" aria-label="Add IoT" data-toggle="modal" data-target="#connect-iot-modal" type="button" class="icon"><span class="glyphicon glyphicon-plus gray"></span></button>
<div class="list-group iot" id="iot-list"><!-- buttons will be placed here --></div>
</div>...
The modal that pops up when clicking a button:
<div class="modal fade" id="quick-view-iot-modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="quick-view-iot-h4"></h4>
</div>
<div class="modal-body">
<form id="edit-iot-form" method="post">
IoT Name: <br>
<input type="text" name="iot-name" class="iot-value" required><br>
Organization ID: <br>
<input type="text" name="org-id" class="iot-value" readonly required><br>
Authentication Method: <br>
<input type="text" name="auth-method" class="iot-value" value="apikey" readonly><br>
API Key: <br>
<input type="text" name="api-key" class="iot-value" readonly required><br>
Authentication Token: <br>
<input type="text" name="auth-token" class="iot-value" readonly required><br>
</form>
<button name="more" type="button" class="fancy-font page-button">More</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
The javascript that adds the content to modal. It is within a main method that is called when document is ready:
$('.iot').click(
function()
{
var iotName = event.target.name;
getIots(loadIotQuickView, iotName);
$('h4#quick-view-iot-h4.modal-title').text(event.target.name);
});
The getIots() function: (it includes parameter variable=null because I also use it in another part of code where the varaible parameter is not used. This method sends an ajax post to a servlet, which then responds with an array of iot objects)
var getIots = function(callback, variable=null)
{
var iotsJSON = null;
$.post("DashboardServlet", {loadIotPanel: "true"}, function(response)
{
iotsJSON = response;
callback(response, variable);
});
The loadIotQuickView() function: (This is where I believe I am getting problems)
var loadIotQuickView = function(iotsJSON, iotName)
{
var currentIoT = null;
for(var iot in iotsJSON)
{
if(iotsJSON[iot].appID = iotName)
currentIoT = iotsJSON[iot];
}
if(currentIoT == null)
return;
$('.iot-value[name="iot-name"]').attr("value",currentIoT.appId);
};
I've tried numerous jquery selectors but none of the input field values within the form will change. I've stepped through the code and all of my variables have the correct values that its just the last line that's not executing how I want. I am unsure if there is an issue with my jquery selector or if it is something else. Thanks in advance!
UPDATE:
I've tried the following selectors:
$('.iot-value[name="iot-name"]')
$('input[name="iot-name"]')
$('.iot-value')
$('#connect-iot-modal').find('input[name="iot-name"]')
I've also tried adding an id of "edit-iot-name" to my input field:
$('#edit-iot-name')
$('#connect-iot-modal #edit-iot-name')
But none of these have worked, which leads me to believe that it must not be an issue with my selector.
UPDATE:
I've also tried using .val(currentIoT.appID) with all of the previous selectors. Still not working.
I'm not sure why, but adding the id of the modal that my form is in, which is #quick-view-iot-modal, to my selector worked. However for some reason it only works when I use .val() and not when I use .attr(). So the final result is:
$('#quick-view-iot-modal #edit-iot-name').val(currentIoT.appID);
I'm not sure why it is required to add the id of the modal, and I'm not sure why it doesn't work like this:
$('#quick-view-iot-modal #edit-iot-name').attr("value",currentIoT.appID);
But it works! If anyone knows why it only works with this combination, please let me know!
try:
$('.iot-value[name="iot-name"]').val(currentIoT.appId);
Your selector is pretty weird as well. why not just refer to the input by name?
$('input[name="iot-name"]').val(currentIoT.appId);
In your code here:
$('.iot-value[name="iot-name"]')
"iot-name" is a string literal, and it will not evaluate to the value of your iot-name variable.
I'm guessing that you are looking to use the variable's value in your selector, which would look like this:
$('.iot-value[name="' + iot-name + '"]')
I have been struggling with this problem for 3 hours. The realisation that you must reference the object through the modal div is the winner.
I was trying to do 2 things:
populate the href in an <a> button on my modal
set the value of another field using an onChange()
so I end up with:
$("#modal-form #linkbtn").attr("href", url);
$('#modal-form #inputfield").val(newVal);
Thanks so much for this hint.
LISTEN!
i've got a good solution for all of you guys!
$("#exampleModal").modal("show");
$(function () {
$("#exampleModal #ticket_id").val("your_value_variable");
});
try this way after you load your modal show it then use DOM ready event then set your value to it input text and amazingly it works! this is the easiest and simplest way from me
I have a list of products:
For each product they can select a time type (per hour, per day etc).
When they have done so and clicked book, it adds the product to cart;
this is done inside addToCart below on the line that is bolded.
addToCart: function (resultId, cartId) {
var that = this;
this.shoppingCart.forEach(function (cartItem, cartIndex) {
cartItem.added = false;
if (cartIndex == cartId)
{
cartItem.added = true;
that.results.forEach(function (resultItem, resultIndex) {
if (resultItem.id == resultId) {
that.shoppingCart.$set(cartIndex,
{
productTimeType: cartItem.productTimeType,
quantity : cartItem.quantity
});
var numberOfBookings = (parseInt(resultItem.numberBookings, 10) + cartItem.quantity);
that.results.$set(resultIndex, {
numberBookings: numberOfBookings,
name: resultItem.name,
quantity: resultItem.quantity,
id: resultItem.id,
category_id: resultItem.category_id,
description: resultItem.description,
image: resultItem.image,
created_at: resultItem.created_at,
updated_at: resultItem.updated_at
});
The html:
<tr v-for="result in results">
<td>
<form class="form-inline" #submit.prevent='addToCart(result.id, $index)'>
<input v-model="shoppingCart[$index].quantity" class="form-control" placeholder="Quantity" name="quantity" type="text">
<select v-model="shoppingCart[$index].productTimeType" class="form-control input-lg"><option value="" selected="selected">All types</option><option value="1">Whole day</option><option value="2">Half day</option><option value="3">Per hour</option></select>
<input class="btn btn-warning" type="submit" value="add to cart">
</form>
When I debug this, and console.log the values it's doing it perfectly. Then it seems like there's some sort of refresh happening, and all the fields are reset on the page to what they were before, and no values are updated.
Change the type of your input to button instead of submit
<input class="btn btn-warning" type="button" value="add to cart">
Ok,in my case the issue was with the fact that I was outputting the select box with Laravel using Laravel Collective's package, and each time it did so, it generated the markup with a certain option selected. This was resetting the dropdown.
It would seem that there are better ways to work with VueJs and the backend like fetching the data or the html from the server and passing that to VueJs to generate the dropdown (if the dropdown is dynamic). I will follow an approach similar to this.
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