Core Functionality and Requirements
- Up on selecting an answer, its background changes to yellow (selected state) and the interface automatically avdances to the next question.
- The progress indicator at the top updates when moving to the next question.
- The selected answer's corresponding score is recorded for final result calculation.
- Users can swipe right to review previous questions.
- Navigation to the next question is disabled if the current question is unanswered.
- Upon completing the final question, the assessment result page is displayed.
Data Structure
The quiz questions and answers are defined in a JSON structure. Each question contains a list of possible enswers, each with associated text, score value, and order.
{
"Questions": [
{
"Question": "Your Age Range:",
"AnswerList": [
{"Text": "Under 30", "Score": 5, "OrderNo": 0},
{"Text": "30-39", "Score": 4, "OrderNo": 1},
{"Text": "40-49", "Score": 3, "OrderNo": 2},
{"Text": "50-59", "Score": 2, "OrderNo": 3},
{"Text": "Over 60", "Score": 1, "OrderNo": 4}
]
}
]
}
HTML Structure
<div ng-controller="QuizController as ctrl">
<div class="progress-container">
<ul>
<li ng-repeat="q in ctrl.questions track by $index">
<span class="step">{{$index + 1}}</span>
</li>
</ul>
<div class="progress-info">Completed {{ctrl.currentStep}}/{{ctrl.totalQuestions}}</div>
</div>
<ul class="questions-list" id="questionsContainer">
<li ng-repeat="question in ctrl.questions track by $index" class="question-slide">
<div class="question-text">{{$index + 1}}. {{question.Question}}</div>
<ul class="answers">
<li ng-repeat="answer in question.AnswerList"
ng-click="ctrl.selectAnswer(answer, $parent.$index)"
ng-class="{'selected': answer.isSelected}">
{{ctrl.optionLabels[$index]}}. {{answer.Text}}
</li>
</ul>
</li>
</ul>
<div ng-show="ctrl.showResults">
<span>Total Score: {{ctrl.totalScore}}</span>
</div>
</div>
Controller Implementation
angular.module('quizApp', [])
.controller('QuizController', ['$scope', '$http', function($scope, $http) {
var self = this;
self.optionLabels = ['A', 'B', 'C', 'D', 'E'];
self.questions = [];
self.totalScore = 0;
self.showResults = false;
self.currentStep = 0;
self.totalQuestions = 0;
// Load question data
$http.get('/api/questions').then(function(response) {
self.questions = response.data.Questions;
self.totalQuestions = self.questions.length;
});
// Handle answer selection
self.selectAnswer = function(chosenAnswer, questionIndex) {
var currentQuestion = self.questions[questionIndex];
// Deselect all answers for this question
currentQuestion.AnswerList.forEach(function(ans) {
ans.isSelected = false;
});
// Select the clicked answer
chosenAnswer.isSelected = true;
// Move to next question if available
if (questionIndex < self.totalQuestions - 1) {
self.navigateToQuestion(questionIndex + 1);
} else {
self.calculateFinalScore();
self.showResults = true;
}
self.updateProgress();
};
self.navigateToQuestion = function(targetIndex) {
// Implementation for smooth transition between questions
};
self.calculateFinalScore = function() {
self.totalScore = self.questions.reduce(function(sum, q) {
var selected = q.AnswerList.find(function(ans) {
return ans.isSelected;
});
return sum + (selected ? selected.Score : 0);
}, 0);
};
self.updateProgress = function() {
self.currentStep = self.questions.filter(function(q) {
return q.AnswerList.some(function(ans) {
return ans.isSelected;
});
}).length;
};
// Touch event handlers for swipe navigation
var touchStartX = 0;
var touchThreshold = 50;
document.getElementById('questionsContainer').addEventListener('touchstart', function(e) {
touchStartX = e.touches[0].clientX;
});
document.getElementById('questionsContainer').addEventListener('touchend', function(e) {
var touchEndX = e.changedTouches[0].clientX;
var deltaX = touchEndX - touchStartX;
if (Math.abs(deltaX) > touchThreshold) {
if (deltaX > 0 && self.currentStep > 0) {
// Swipe right - go to previous question
self.navigateToQuestion(self.currentStep - 1);
} else if (deltaX < 0 && self.currentStep < self.totalQuestions - 1) {
// Swipe left - go to next question
self.navigateToQuestion(self.currentStep + 1);
}
}
});
}]);
Key CSS Styles
.question-slide {
position: absolute;
width: 100%;
transition: transform 0.3s ease;
transform: translate3d(100%, 0, 0);
}
.question-slide.active {
transform: translate3d(0, 0, 0);
}
.answers li.selected {
background-color: #ffeb3b;
}
.step {
display: inline-block;
width: 30px;
height: 30px;
border-radius: 50%;
background-color: #e0e0e0;
text-align: center;
line-height: 30px;
}
.step.completed {
background-color: #4caf50;
color: white;
}