I have an application that tests people on their times tables. The sum is presented to the user and then they have to enter their answer into the input field.
The majority of this works but the value of the input field shows as undefined rather than the value that the user enters.
let timesTableNumber = 2;
let listOfTables = [2,3,4,5,6,7,8,9,10,11,12];
let spellingItems = listOfTables.length;
let spellingItemShown = 0;
let checks = 0;
let answers = {
rightAnswers: 0,
wrongAnswers: [],
numberOfSpellings:spellingItems,
spellingGroup: "{{spelling.group}}",
spellingId: "{{spelling._id}}",
spellingcreatedBy: "{{spelling.createdBy}}",
user: "{{user._id}}"
};
var checkSpellings = setInterval(function() {
if (spellingItemShown > checks) {
checkAnswer();
}
if (spellingItemShown < spellingItems){
document.getElementById('spellings').innerHTML = timesTableNumber + 'x' + listOfTables[spellingItemShown];
document.getElementById('answer').innerHTML = timesTableNumber * listOfTables[spellingItemShown];
//hide the spelling to be tested for x seconds
var hideSpellings = setInterval(function() {
document.getElementById('spellings').style.visibility = 'hidden';
document.getElementById('form').style.removeProperty( 'visibility' );
document.getElementById('spelling').focus();
clearInterval(hideSpellings);
}, 3000);
document.getElementById('spellings').style.removeProperty( 'visibility' );
document.getElementById('form').style.visibility = 'hidden';
spellingItemShown ++;
} else{
//We're done!
console.log('there were '+ answers.rightAnswers + ' right answers and the wrong answers were '+ answers.wrongAnswers);
//post to server desired info....
// axios.post('/spellings', answers);
//showResults();
console.log(answers);
clearInterval(checkSpellings);
}
}, 7000);
function checkAnswer(){
console.log('checkAnswer:');
var correctAns = timesTableNumber * listOfTables[spellingItemShown];
var userAns = document.getElementById('spelling').value;
console.log('correctAns', correctAns);
console.log('userAns', userAns);
// debugger;
if (userAns == correctAns){
console.log('FOOOOOO');
answers.rightAnswers ++;
} else {
console.log('yo');
answers.wrongAnswers.push(document.getElementById('spellings').innerHTML);
}
document.getElementById("spelling").value = "";
checks++
}
<div class="row">
<div class="col-xs-12 col-sm-8 col-md-6 col-sm-offset-2 col-md-offset-3">
<div id="spellingTest">
<h2 id="spellings"></h2>
<p id="answer" class="answer" style="visibility:hidden"></p>
<div id="form" class="spellings" style="visibility:hidden">
<label for="spelling"> attempt</label>
<input type="number" class="form-control" id="spelling" name="spelling">
</div>
<h3 id="spellingResults">Your results will show below at the end of the test.</h3>
</div>
</div>
</div>
Can anyone help me understand why this is happening and how to resolve it?
Edit - I have resolved the undefined issue by changing the value of userAns to var userAns = document.getElementById('spelling').value; However there is now the issue that the correct answer is always one ahead of the actual correct answer e.g. correct answer for 2x2 shows as 6 rather than 4 and 3x2 shows as 8 rather than 6
Related
I'm working on an ASP.NET Core project and need to get the value of the checked input[type="radio"] when clicking on the inputs.
This is my HTMl markup:
#if (Model.ProductColors.Any())
{
<div class="fs-sm mb-4"><span class="text-heading fw-medium me-1">رنگ:</span><span class="text-muted" id="colorValue"></span></div>
<div class="fs-sm mb-4"><span class="text-heading fw-medium me-1">کدرنگ:</span><span class="text-muted" id="colorCode"></span></div>
<div class="checkBox position-relative me-n4 mb-3">
#{int j = 1;
}
#foreach (var item in Model.ProductColors)
{
<div onclick="doActiveRadioButton('color_#j')" id="div_color_#j" class="productColor form-check form-option form-check-inline mb-2">
<input #((j==1)?"checked":"") class="test form-check-input" type="radio" name="color" id="color_#j" data-bs-label="colorOption" value="#item.ColorId">
<label class="form-option-label rounded-circle" for="color1"><span class="form-option-color rounded-circle" style="background-image: url(/Images/ProductThumbs/#item.ImageName)"></span></label>
</div>
j++;
}
I've tried to get the value at the end of below codes:
<script>
function doActiveRadioButton(id) {
var slides = document.querySelectorAll(".productColor input");
console.log(slides.length);
for (var i = 0; i < slides.length; i++) {
slides[i].removeAttribute("checked");
}
var s = document.getElementById(id);
s.setAttribute("checked", "checked");
var g = document.querySelectorAll(".productColor label");
for (var i = 0; i < g.length; i++) {
g[i].style.border = "1px solid #e3e9ef";
}
var d = document.querySelector("#div_" + id + " label");
d.style.border = "1px solid #fe696a";
var radioId = document.querySelector('.productColor input[type = "radio"]:checked');
console.log(radioId);
var c = document.querySelector("#colorCode");
c.innerHTML = "green!";
}
</script>
When I use console.log() to log the radioId, I mean the following part:
var radioId = document.querySelector('.productColor input[type = "radio"]:checked').value;
console.log(radioId);
For the first time, it works correctly and showing me the true radioId (for example 9), but when I click on the input for the second time or more, it shows me the following error:
Uncaught TypeError: Cannot read properties of null (reading 'value')
at doActiveRadioButton (2008:1621)
at HTMLDivElement.onclick (2008:745)
Would anybody explain it to me and give me some sulotions or alternatives please?
Well, you look for the input that is checked. When it is checked you'll find it. When you uncheck it, it is no longer found and document.querySelector returns null. That means that the value property no longer exists.
You might want to make a check first if the element is found or not.
const productColorInput = document.querySelector('.productColor input[type="radio"]:checked')
if (productColorInput !== null) {
const radioId = productColorInput.value;
console.log(radioId);
}
Or check the checked property instead of querying a checked input. (This might be more solid as it always returns an element).
const productColorInput = document.querySelector('.productColor input[type="radio"]');
if (productColorInput.checked === true) {
const radioId = productColorInput.value;
console.log(radioId);
}
I'm learning JS and created an app game in which a user guesses random day and random month. When the user gets both of them right, I want to replace the question mark with a heart icon from JS icons. Somehow it doesn't work.
I tried this code:
if (guessDay === secretDay && guessMonth === secretMonth) {
document.getElementById("victory").innerHTML = "💖";
}
I also tried replacing the heart icon with a word: "Victory" but it didn't work either.
Full code below:
let secretMonth = Math.trunc(Math.random() * 12) + 1;
let secretDay = Math.trunc(Math.random() * 31) + 1;
console.log(secretMonth, secretDay);
document.querySelector(".btn-month").addEventListener("click", function () {
const guessMonth = Number(document.querySelector(".guess-month").value);
if (guessMonth === secretMonth) {
document.querySelector(
".hint-month"
).textContent = `You got the month right.`;
document.querySelector(".left").style.backgroundColor = "blue";
} else if (guessMonth >= secretMonth) {
document.querySelector(".hint-month").textContent = `Go lower.`;
document.querySelector(".left").style.backgroundColor = "#d9480f";
} else {
document.querySelector(".hint-month").textContent = `Go higher.`;
document.querySelector(".left").style.backgroundColor = "#d9480f";
}
});
document.querySelector(".btn-day").addEventListener("click", function () {
const guessDay = Number(document.querySelector(".guess-day").value);
if (guessDay === secretDay) {
document.querySelector(".hint-day").textContent = `You got the day right.`;
document.querySelector(".right").style.backgroundColor = "blue";
} else if (guessDay >= secretDay) {
document.querySelector(".hint-day").textContent = `Go lower.`;
document.querySelector(".right").style.backgroundColor = "#d9480f";
} else {
document.querySelector(".hint-day").textContent = `Go higher.`;
document.querySelector(".right").style.backgroundColor = "#d9480f";
}
});
document.querySelector(".btn-reset").addEventListener("click", function () {
document.querySelector(".hint-day").textContent = "";
document.querySelector(".hint-month").textContent = "";
document.querySelector(".right").style.backgroundColor = "#d9480f";
document.querySelector(".left").style.backgroundColor = "#d9480f";
document.querySelector(".guess-month").value = "";
document.querySelector(".guess-day").value = "";
});
if (guessDay === secretDay && guessMonth === secretMonth) {
document.getElementById("victory").innerHTML = "victory";
}
<div class="wrapper">
<header>
<h1>Guess my birthday</h1>
<div class="divider"><span id="victory">?</span></div>
</header>
<main>
<section class="left">
<div class="label-container">
<p class="range">Between 1-12</p>
<p class="label">month</p>
</div>
<input class="guess guess-month" type="number" min="0" max="12" />
<button class="btn btn-month">Check</button>
<p class="hint hint-month"></p>
</section>
<section class="right">
<div class="label-container">
<p class="range">Between 1-31</p>
<p class="label">day</p>
</div>
<input class="guess guess-day" type="number" min="0" max="31" />
<button class="btn btn-day">Check</button>
<p class="hint hint-day"></p>
</section>
<button class="btn btn-reset">Reset</button>
</main>
</div>
The logic is correct but the code is not running at the right moment in the right scope. The conditional check happens at the same time as registering event handlers.
// register month click
// register day click
// register reset click
// too early to check the guess, no guesses have been made yet
if (guessDay === secretDay && guessMonth === secretMonth) {
document.getElementById("victory").innerHTML = "victory";
}
In order to fix the problem, there are two steps.
Put the victory check in a helper function to call on both the day and month submit if the guess is right.
Keep track of the day and month guess in the parent scope to allow checking for victory after guessing either value.
let secretMonth = Math.trunc(Math.random() * 12) + 1;
let secretDay = Math.trunc(Math.random() * 31) + 1;
// keep track of last day and month guess in parent scope
let guessMonth;
let guessDay;
// in click event handler set outer scope variable (no const)
guessMonth = Number(document.querySelector(".guess-month").value);
In terms of checking for victory it could be a helper function.
function checkVictory() {
if (guessDay === secretDay && guessMonth === secretMonth) {
document.getElementById("victory").innerHTML = "victory";
}
}
// in click event handler
if (guessDay === secretDay) {
// update styles
checkVictory();
}
I had to change the conditions for the month. Because after I checked the victory for the day and styles were applied, the same style was supposed to be applied to the month div but only the victory for both was applied. Therefore the game must be done in the predifined order. Guess the day first, then guess the month and the month styling must be applied together with the victory styling. (I removed the victory for the month and applied victory for the game instead.
I am making a quiz app that will basically fetch the questions and answers from an API and display it to the webpage. It works fine, but the error handling isn't working. I have a if...else statement that will check if a user has selected the right answer, and if they did, play a sound and display "Nice job" to the user. If they did not, then tell the user that they need to try again. The behavior that I'm getting is very weird. Sometimes when I have chose the correct answer, it says it is not correct. It happens when there is spaces within the answer. For single words such as "true", "false" or "Hello" works fine. I logged the answer to the console stored in a variable called answer_container, when I logged it to the console, the answer and my choice are exactly the same. I have tried using === and == operators to see if that would work, but the result is the same. I have posted the full code including my HTML so that you can see what it is happening. Note it took me couple of tries to get the weird behavior to display.
Here is what I have tried:
var showAnswer = document.getElementById('showAnswer');
var button_score = document.getElementById('ShowScore');
var answer_container;
var url = 'https://opentdb.com/api.php?amount=1';
var score = 0;
var html_container = [];
async function fetchData() {
document.getElementById('next').disabled = true;
document.getElementById('msgSuccess').innerHTML = '';
document.getElementById('check').disabled = false;
document.getElementById('showAnswer').disabled = false;
var getData = await fetch(url);
var toJS = await getData.json();
answer_container = toJS.results[0].correct_answer;
var container = [];
for (var i = 0; i < toJS.results[0].incorrect_answers.length; i++) {
container.push(toJS.results[0].incorrect_answers[i]);
}
container.push(toJS.results[0].correct_answer);
container.sort(func);
function func(a, b) {
return 0.5 - Math.random();
}
html_container = [];
container.forEach(function(choices) {
html_container.push(`
<option value=${choices}>
${choices}
</option>
`)
});
document.getElementById('choice').innerHTML = html_container.join();
if (toJS.results[0].type === 'boolean') {
document.getElementById('type').innerHTML =
`This question is a ${toJS.results[0].category} question <br>
It is a true/false question<br>
Difficulty level: ${toJS.results[0].difficulty} <br>
Question: ${toJS.results[0].question}<br>
`;
} else {
document.getElementById('type').innerHTML =
`This question is a ${toJS.results[0].category} question <br>
It is a ${toJS.results[0].type} choice question <br>
Difficulty level: ${toJS.results[0].difficulty} <br>
Question: ${toJS.results[0].question}<br>
`;
}
}
fetchData();
showAnswer.addEventListener('click', function() {
document.getElementById('answer_element').innerHTML = "The answer to this question is " + answer_container;
document.getElementById('answer_element').style.display = "block";
setTimeout(function() {
document.getElementById('answer_element').style.display = "none";
}, 3000);
});
function check() {
var select_answer = document.getElementById('choice').value;
var audio = document.getElementById('audio');
if (select_answer == answer_container) {
score++;
document.getElementById('showAnswer').disabled = true;
document.getElementById('msgSuccess').innerHTML = "Nice job, keep going!";
document.getElementById('next').disabled = false;
document.getElementById('check').disabled = true;
audio.play();
console.log(answer_container);
}
if (select_answer != answer_container) {
score--;
document.getElementById('msgSuccess').innerHTML = "Keep trying, you will get it!";
document.getElementById('next').disabled = true;
console.log(answer_container);
}
}
<!DOCTYPE html>
<html>
<head>
<title>
Quiz App
</title>
</head>
<body>
<div id="type">
</div>
<label>
Select Your Answer...
</label>
<select id="choice">
</select>
<button id="showAnswer">
Show Answer
</button>
<p id="answer_element">
</p>
<button onclick="check()" id="check">
Check
</button>
<p id="msgSuccess">
</p>
<button id="next" onclick="fetchData()">
Next Question
</button>
<audio id="audio">
<source src="https://www.theharnishes.com/khanacademy.mp3" type="audio/mp3">
</audio>
</body>
</html>
You're using the expression select_answer == answer_container to determine if the choice is the correct answer.
select_answer comes from the value attribute of the option you've selected. However, when an answer value contains whitespace, HTML interprets only up to the first whitespace as the "value". When answers like North America come up, the option's value attribute is only North.
When generating your options in your HTML, you need to properly encapsulate them in double quotes ", like so:
html_container.push(`
<option value="${choices}">
${choices}
</option>
`)
Tangential, but it would probably be cleaner if you generated your elements with document.createElement() and Node.appendChild(); in this instance the quotes required to properly set the value attribute on each option would have been added for you.
Nice game!
The issue here is the text is getting truncated on whitespace in the HTML, so the value you're comparing it too doesn't match.
You need quotes in the HTML option to preserve white space.
<option value=${choices} <- picks the first word
<option value="${choices}" <- allows the whole string with spaces
var showAnswer = document.getElementById('showAnswer');
var button_score = document.getElementById('ShowScore');
var answer_container;
var url = 'https://opentdb.com/api.php?amount=1';
var score = 0;
var html_container = [];
async function fetchData() {
document.getElementById('next').disabled = true;
document.getElementById('msgSuccess').innerHTML = '';
document.getElementById('check').disabled = false;
document.getElementById('showAnswer').disabled = false;
var getData = await fetch(url);
var toJS = await getData.json();
console.log(toJS)
answer_container = toJS.results[0].correct_answer;
var container = [];
for (var i = 0; i < toJS.results[0].incorrect_answers.length; i++) {
container.push(toJS.results[0].incorrect_answers[i]);
}
container.push(toJS.results[0].correct_answer);
container.sort(func);
function func(a, b) {
return 0.5 - Math.random();
}
html_container = [];
container.forEach(function (choices) {
html_container.push(`
<option value="${choices}">
${choices}
</option>
`)
});
document.getElementById('choice').innerHTML = html_container.join();
if (toJS.results[0].type === 'boolean') {
document.getElementById('type').innerHTML =
`This question is a ${toJS.results[0].category} question <br>
It is a true/false question<br>
Difficulty level: ${toJS.results[0].difficulty} <br>
Question: ${toJS.results[0].question}<br>
`;
}
else {
document.getElementById('type').innerHTML =
`This question is a ${toJS.results[0].category} question <br>
It is a ${toJS.results[0].type} choice question <br>
Difficulty level: ${toJS.results[0].difficulty} <br>
Question: ${toJS.results[0].question}<br>
`;
}
}
fetchData();
showAnswer.addEventListener('click', function () {
document.getElementById('answer_element').innerHTML = "The answer to this question is " + answer_container;
document.getElementById('answer_element').style.display = "block";
setTimeout(function () {
document.getElementById('answer_element').style.display = "none";
}, 3000);
});
function check() {
var select_answer = document.getElementById('choice').value;
var audio = document.getElementById('audio');
console.log(select_answer, answer_container)
if (select_answer == answer_container) {
score++;
document.getElementById('showAnswer').disabled = true;
document.getElementById('msgSuccess').innerHTML = "Nice job, keep going!";
document.getElementById('next').disabled = false;
document.getElementById('check').disabled = true;
audio.play();
console.log(answer_container);
}
if (select_answer != answer_container) {
score--;
document.getElementById('msgSuccess').innerHTML = "Keep trying, you will get it!";
document.getElementById('next').disabled = true;
console.log(answer_container);
}
}
<!DOCTYPE html>
<html>
<head>
<title>
Quiz App
</title>
</head>
<body>
<div id="type">
</div>
<label>
Select Your Answer...
</label>
<select id="choice">
</select>
<button id="showAnswer">
Show Answer
</button>
<p id="answer_element">
</p>
<button onclick="check()" id="check">
Check
</button>
<p id="msgSuccess">
</p>
<button id="next" onclick="fetchData()">
Next Question
</button>
<audio id="audio">
<source src="https://www.theharnishes.com/khanacademy.mp3" type="audio/mp3">
</audio>
</body>
</html>
I am developing application in which I have feeds or some timeline. here is my ng-repeat code:
<div ng-repeat="x in feeds" class="fd-feed-card">
<div class="fd-feed-usr-img">
<img ng-src="{{x.user.media[0].small}}" class="fd-img fd-img-br border-style">
</div>
<div class="ft-16 fd-feed-usr-name">
<span><b>{{x.user.name}}</b></span><span class="ft-12 fd-feed-created-time plx prm">{{x.feed.createdTimeStamp | readableTime}}</span>
</div>
<div ng-style="imgStyle">
<img ng-src="{{x.feed.media[0].medium}}" class="fd-img objectcover image-blur">
</div>
<div ng-if="x.feed.total_comments > 0 || x.feed.total_likes >0">
<p class="mll"><span on-tap="openCommentModal(x.feed._id, $index, x.feed)" class="prm" ng-if="x.feed.total_comments > 0">{{x.feed.total_comments}} Comment</span><span ng-if="x.feed.total_likes>0" on-tap="openUserModal(x.feed._id)">{{x.feed.total_likes}} Likes</span>
</p>
</div>
<div class="fd-feed-distance">
<span class="plx prm ft-16">{{x.distance}} <span class="ft-10">mil</span></span>
</div>
</div>
here every feed contains username, userimage and 400*400px image of feed and distance. after this im using ionic infinite scroll like this:
<ion-infinite-scroll on-infinite="getDashboardFeed()" distance="1%" ng-if="!noMoreFeedContent"></ion-infinite-scroll>
in my javascript code, i am calling API with pagination having 5 feeds at a time. here it is my javascript code:
$scope.getDashboardFeed = function(start) {
var _start = start || false;
var params = {}
params.offset = offset;
params.limit = limit;
Posts.getAllFeeds(params).success(function(res) {
if (_start) {
$scope.feeds = [];
}
if (res.data.length < limit) {
$scope.noMoreFeedContent = true;
} else {
$scope.noMoreFeedContent = false;
}
for (var i = 0; i < res.data.length; i++) {
var markerPos = new google.maps.LatLng(res.data[i].feed.location[0], res.data[i].feed.location[1]);
var currentLatLng = new google.maps.LatLng(res.data[i].location.location[0], res.data[i].location.location[1])
var distance = google.maps.geometry.spherical.computeDistanceBetween(markerPos, currentLatLng) * 0.000621371;
res.data[i].distance = distance.toFixed(2);
for (var j = 0; j < res.data[i].feed.likes.length; j++) {
if (uid == res.data[i].feed.likes[j].user) {
res.data[i].isLiked = true;
break;
} else {
res.data[i].isLiked = false;
}
}
$scope.feeds.push(res.data[i]);
}
offset = offset + limit;
if (_start) {
$scope.$broadcast('scroll.refreshComplete');
} else {
$scope.$broadcast('scroll.infiniteScrollComplete');
}
})
.error(function(err) {
})
};
im also calculating distance of every feed based on current location. and checking if i liked the post or not.
Now the problem is when feed is loaded to 25,30 , the scroll becomes laggy in my android . Im also using native scrolling given in this link ,
i have read also more blogs like this
but i didnt get much help. I have to load 1000s of feeds here where every feed contains 400*400px picture.
i also tried collection-repeat. it didnot work either.
Is there any other approach I can try to fix my scroll perfomance?
Anybody can help me with that?
I had same issue, especially when using images in ng-repeat.
Check out my answer here
When a user hovers over the stars, I want to show the message You rated <b>{{rate1}} star.</b><a ng-click="showMe()" class="modifyIt"><b > modify?</b></a>, and if the user has clicked on the rating I want to show 'Thanks for rating' (see html below for my logic). But after this if the user hovers again over the stars I want to show You rated <b>{{rate1}} star.</b><a ng-click="showMe()" class="modifyIt"><b > modify?</b></a> again.
Issue is once rated, it shows 'Thanks for rating' always. How to fix this?
Please see my attempt at doing this below, and it would be helpful if someone can point out the error I have made. Thanks!
<div class="user">
<uib-rating ng-model="rate" max="5" read-only="isReadonly" on-titles="['one','two','three']" aria-labelledby="default-rating" class="readOnlyRating "></uib-rating>
<div class=" arrow_box rt" ng-show="showRatings">
<div class="ratingName">
<h5><b>Give your rating here..</b></h5>
</div>
<div class="stars">
<uib-rating ng-model="rate1" ng-click="rating(rate1)" max="5" read-only="isReadonly1" on-hover="hoveringOver(value)" on-leave="overStar = null" titles="['one','two','three']" aria-labelledby="default-rating" class="readOnlyRating "></uib-rating>
</div>
</div>
<div ng-mouseleave="hoverOut()" class="arrow_box rt" ng-show="ratevalue ">
<h5 class="ratedPopover"> Thanks for rating </h5>
</div>
<div class="arrow_box rt" ng-hide="showRatings">
<h5 class="ratedPopover">You rated <b>{{rate1}} star.</b><a ng-click="showMe()" class="modifyIt"><b > modify?</b></a>
</h5>
</div>
</div>
here is my directive file
scope.rating = function (rate) {
scope.ratevalue = rate;
if ($localStorage[localStorageRatingKey] == undefined) {
previousRatingValue = 0;
$localStorage[localStorageRatingKey] = scope.ratevalue;
} else {
previousRatingValue = $localStorage[localStorageRatingKey];
$localStorage[localStorageRatingKey] = scope.ratevalue;
}
ratingService.update({
companyId : scope.details._id,
userRating : scope.ratevalue,
previousRatingValue : previousRatingValue
}, scope.details, successCallback, errorCallback);
function successCallback(res) {
// console.log("coming from callback");
scope.rate = res.avgRatings;
scope.reviewsCount = res.totalRatingsCount;
}
function errorCallback(res) {
NotificationFactory.error('Failed to update the product rating...', res.data.message);
}
};
scope.showMe = function () {
scope.showRatings = !scope.showRatings;
console.log("showme :" + scope.showRatings);
}
scope.hoverOut = function () {
if ($localStorage[localStorageRatingKey]) {
scope.showRatings = !scope.showRatings;
} else {
scope.showRatings = true;
}
console.log("hoverOut ShowRatings:" + scope.showRatings);
}
if ($localStorage[localStorageRatingKey]) {
scope.showRatings = false;
} else {
scope.showRatings = true;
}
Instead of using ratevalue to show the message 'Thanks for rating', I would suggest using a flag like hasjustRated. In your code initialize this to false
at the beginning of this function definition: scope.rating = function (rate) { ... }
Also at the end of the success callback, add the following lines:
scope.hasjustRated = true;
Then on leave of hover, reset this value to false. I suggest adding a clear function for on leave that would do all the necessary steps when leaving hover.
Also what the showMe function does is a bit unclear.