Build a AngularJS Picture MCQ Trivia Quiz Game in Browser Using HTML5 CSS3 and Javascript Full Project For Beginners

 

 

 

index.html

 

 

<html>
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Chicago Loop Quiz</title>
</head>

<body class="container">
  <section ng-app="ngQuiz" ng-controller="ngQuizController" class="quiz">
    <image-preload></image-preload>
    <div class="progress" ng-if="quizProgress.inProgress && quizProgress.currentQuestion <= quizProgress.lastQuestion">
      <span ng-cloak class="counter">Question {{quizProgress.currentQuestionFriendly}} of {{quizProgress.lastQuestion}}</span>
      <div class="progress-bar" progress-bar></div>
    </div>
    <div class="content">
      <!-- intro -->
      <section ng-cloak class="intro fade-in" ng-if="!quizProgress.loading && !quizProgress.inProgress && !quizProgress.finished">
        <div ng-cloak class="row">
          <div class="col-xs-6">
            <h1>{{::quizMetadata.title}}</h1>
            <p>{{::quizMetadata.intro}}</p>
          </div>
          <div class="col-xs-6">
            <img ng-src="{{quizMetadata.introImg}}" />
            <aside class="figure-caption text-xs-right" ng-if="quizMetadata.introImgCredit">Photo credit: {{::quizMetadata.introImgCredit}}</aside>
          </div>
        </div>
        <div class="row">
          <button class="pull-right btn btn-success" ng-click="startQuiz()">Start Quiz</button>
        </div>
      </section>

      <!-- question list -->
      <section ng-cloak class="fade-in question" ng-if="quizProgress.inProgress && quizProgress.currentQuestion <= quizProgress.lastQuestion">
        <div animate-progression>
          <div class="text-center">
            <img class="img-responsive" ng-src="{{quizQuestions[quizProgress.currentQuestion].questionImg}}" />
          </div>

          <p class="question-content">{{quizQuestions[quizProgress.currentQuestion].question}}</p>
          <div class="question-options">
            <div ng-repeat="option in quizQuestions[quizProgress.currentQuestion].options | orderBy: '-'">
              <div class="option" ng-class="{'wrong': quizQuestions[quizProgress.currentQuestion].answerChecked && option.selected && !option.correct, 'correct': option.correct && quizQuestions[quizProgress.currentQuestion].answerChecked, 'dim': quizQuestions[quizProgress.currentQuestion].answerChecked}">
                <input type="radio" name="option" id="{{$index}}" ng-click="answerQuestion({selected: option.name})" ng-disabled="quizQuestions[quizProgress.currentQuestion].answerChecked">
                <label for="{{$index}}">{{option.name}}</label>
              </div>
              <div class="row feedback" ng-if="quizQuestions[quizProgress.currentQuestion].answerChecked && option.correct">
                <span ng-bind-html="quizQuestions[quizProgress.currentQuestion].feedback"></span>
              </div>
            </div>
          </div>

          <div class="row">
            <button ng-if="quizProgress.currentQuestion === -1" class="btn btn-primary" ng-click="startQuiz()">Start Quiz</button>
            <button ng-if="quizQuestions[quizProgress.currentQuestion].answerChecked && quizProgress.currentQuestionFriendly !== quizProgress.lastQuestion" class="btn btn-primary pull-right" ng-click="nextQuestion()">Next Question <i class="fa fa-arrow-right" aria-hidden="true"></i></button>
            <button ng-if="!quizQuestions[quizProgress.currentQuestion].answerChecked" ng-disabled="!quizQuestions[quizProgress.currentQuestion].answered" class="btn btn-primary pull-right" ng-click="checkAnswer()">Check Answer</button>
          </div>
        </div>

        <div class="get-my-results text-center" ng-if="quizProgress.currentQuestionFriendly === quizProgress.lastQuestion && quizQuestions[quizProgress.currentQuestion].answerChecked">
          <button class="pulse btn btn-primary" ng-click="getScore()">Get My Results</button>
        </div>
      </section>

      <section class="loading" ng-if="quizProgress.loading || quizProgress.calculatingScore">
        <div class="loader"></div>
      </section>

      <section class="fade-in" ng-if="!quizProgress.calculatingScore && !quizProgress.inProgress && quizProgress.currentQuestionFriendly === quizProgress.lastQuestion">
        <div class="results">
          <div class="text-center">
            <h1>Your Score</h1>
            <h2>{{score}}</h2>
          </div>
        </div>

        <div class="text-center">
          <button class="start-over btn btn-success" ng-click="startOver()"><i class="fa fa-repeat" aria-hidden="true"></i>Try Again</button>
        </div>
      </section>
  </section>
</body>

</html>

 

 

style.css

 

 

/* With keyframe animations from animate.css */

@import url(https://fonts.googleapis.com/css?family=Open+Sans);

body {
  padding-top: 1.5em;
  font-family: 'Open Sans', sans-serif;
}

.quiz {
  margin-top: 1em;
  min-height: 60vh;
  background: #fff;
  box-shadow: -2px 0px 21px -2px rgba(0, 0, 0, 0.4);
}

.text-center {
  text-align: center;
}

.quiz .question img {
  display: block;
  margin: 0 auto;
}

.quiz button {
  margin-top: 2em;
  user-select: none;
  outline: 0!important;
  text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);
}

.quiz .btn {
  font-size: 1.6rem;
  height: 3.2em;
  transition: all .25s ease;
}

.quiz .btn-primary,
.quiz .btn-success {
  opacity: 0.9;
  background: #4c9cff;
  border-radius: 0;
  border: 0;
  padding: 0.5em 1em;
  text-align: center;
  color: #fff;
}

.quiz .btn-primary:hover {
  opacity: 1;
  background: #4c9cff;
  color: #fff
}

.quiz .btn-success {
  background: #51a351;
}

.quiz .btn-success:hover,
.quiz .btn-success:active {
  background: #4a9e4a;
}

.quiz .btn-primary:disabled,
.quiz .btn-primary:disabled:hover {
  background: #ccc;
}

.quiz .content {
  color: #222;
  padding: .25em 3em 2em 3em;
  margin-bottom: 1em;
}

.quiz .intro {
  margin-top: 2em;
}

.quiz .intro p {
  font-size: 2rem;
}

.quiz aside {
  color: #777;
  font-size: 1.5rem;
  padding-top: 0.25em;
}

.quiz .question {
  margin-top: 2em;
  position: relative;
}

.quiz .question img {
  box-shadow: -2px 0px 21px -2px rgba(0, 0, 0, 0.4);
}

.quiz .question p,
.quiz .intro p {
  font-size: 1.8rem;
  line-height: 1.5;
  margin: 1em 0;
}

.quiz .intro p:last-of-type {
  padding-bottom: 0;
}

.quiz .question-content {
  min-height: 50px;
}

.quiz .question-options {
  margin-left: 1.5rem;
}

.quiz .feedback {
  padding-bottom: .75em;
  margin: -.5em 1em 0 2em;
  animation: .75s roll-in ease;
}

.quiz .progress {
  position: relative;
  margin-bottom: 0;
  background: rgb(181, 181, 181);
  border-radius: 0;
  width: 100%;
}

.quiz .progress-bar {
  background: #4c9cff;
  height: 100%;
  transition: width .4s ease;
}

.quiz .progress .counter {
  position: absolute;
  right: 5px;
  top: 0;
  font-weight: normal;
  color: #fff;
}

.quiz .get-my-results {
  font-size: 2.4rem;
  margin-bottom: 1em;
}

.quiz button .fa {
  margin-right: .5em;
}

.quiz .start-over {
  margin-top: 20%;
}

.quiz .results {
  padding: 3em;
  margin-top: 2em;
  color: #fff;
  background: #2b9eda;
}

.quiz .results h1 {
  font-size: 2.8rem;
  text-shadow: 1px 2px 1px rgba(0, 0, 0, 0.1);
}

.quiz .results h2 {
  font-size: 2.4rem;
  text-shadow: 1px 2px 1px rgba(0, 0, 0, 0.1);
}

.quiz .dim {
  opacity: 0.5;
}

.quiz .dim [type="radio"]:checked + label,
.quiz .dim [type="radio"]:not(:checked) + label {
  cursor: initial;
}

@keyframes fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.loader,
.loader:before,
.loader:after {
  border-radius: 50%;
}

.loader:before,
.loader:after {
  position: absolute;
  content: '';
}

.loader:before {
  width: 5.2em;
  height: 10.2em;
  background: #0dc5c1;
  border-radius: 10.2em 0 0 10.2em;
  top: -0.1em;
  left: -0.1em;
  -webkit-transform-origin: 5.2em 5.1em;
  transform-origin: 5.2em 5.1em;
  -webkit-animation: load2 2s infinite ease 1.5s;
  animation: load2 2s infinite ease 1.5s;
}

.loader {
  font-size: 11px;
  text-indent: -99999em;
  margin: 55px auto;
  margin-top: 15em;
  position: relative;
  width: 10em;
  height: 10em;
  box-shadow: inset 0 0 0 1em #ffffff;
  -webkit-transform: translateZ(0);
  -ms-transform: translateZ(0);
  transform: translateZ(0);
}

.loader:after {
  width: 5.2em;
  height: 10.2em;
  background: #0dc5c1;
  border-radius: 0 10.2em 10.2em 0;
  top: -0.1em;
  left: 5.1em;
  -webkit-transform-origin: 0px 5.1em;
  transform-origin: 0px 5.1em;
  -webkit-animation: load2 2s infinite ease;
  animation: load2 2s infinite ease;
}

.quiz .loading {
  margin-top: 10em;
}


/* custom radio controls */

.quiz .option {
  margin-bottom: .75em;
  transition: all .25s ease;
}

.quiz [type="radio"]:checked,
.quiz [type="radio"]:not(:checked) {
  position: absolute;
  left: -9999px;
}

.quiz [type="radio"]:checked + label,
.quiz [type="radio"]:not(:checked) + label {
  position: relative;
  font-weight: normal;
  padding-left: 28px;
  cursor: pointer;
  line-height: 20px;
  display: inline-block;
  color: #666;
}

.quiz [type="radio"]:checked + label:before,
.quiz [type="radio"]:not(:checked) + label:before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  width: 20px;
  height: 20px;
  border: 1px solid #ddd;
  border-radius: 100%;
  background: #fff;
}

.quiz .correct [type="radio"] + label::before,
.quiz .wrong [type="radio"] + label::before {
  border: 0;
  font-size: 1.2rem;
  animation: .25s roll-in ease;
}

.quiz .correct [type="radio"] + label::after,
.quiz .wrong [type="radio"] + label::after {
  display: none;
}

.quiz .correct [type="radio"] + label:before {
  content: '\f00C';
  font-family: "FontAwesome"!important;
  color: #09b39c;
}

.quiz .wrong [type="radio"] + label:before {
  content: '\f00d';
  font-family: "FontAwesome"!important;
  color: #b05747;
}

.quiz [type="radio"]:checked + label:after,
.quiz [type="radio"]:not(:checked) + label:after {
  content: '';
  width: 12px;
  height: 12px;
  background: #ea7373;
  position: absolute;
  top: 4px;
  left: 4px;
  border-radius: 100%;
  -webkit-transition: all 0.2s ease;
  transition: all 0.2s ease;
}

.quiz [type="radio"]:not(:checked) + label:after {
  opacity: 0;
  -webkit-transform: scale(0);
  transform: scale(0);
}

.quiz [type="radio"]:checked + label:after {
  opacity: 1;
  -webkit-transform: scale(1);
  transform: scale(1);
}

@keyframes load2 {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}

@keyframes pulse {
  from {
    -webkit-transform: scale3d(1, 1, 1);
    transform: scale3d(1, 1, 1);
  }
  50% {
    -webkit-transform: scale3d(1.05, 1.05, 1.05);
    transform: scale3d(1.05, 1.05, 1.05);
  }
  to {
    -webkit-transform: scale3d(1, 1, 1);
    transform: scale3d(1, 1, 1);
  }
}

@keyframes fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.pulse {
  -webkit-animation-name: pulse;
  animation: pulse 1s infinite;
}

.fade-in {
  animation: fade .75s ease;
}

.question-animate {
  animation: fade .7s ease;
}

.loader,
.loader:before,
.loader:after {
  border-radius: 50%;
}

.loader:before,
.loader:after {
  position: absolute;
  content: '';
}

.loader:before {
  width: 5.2em;
  height: 10.2em;
  background: #0dc5c1;
  border-radius: 10.2em 0 0 10.2em;
  top: -0.1em;
  left: -0.1em;
  -webkit-transform-origin: 5.2em 5.1em;
  transform-origin: 5.2em 5.1em;
  -webkit-animation: load2 2s infinite ease 1.5s;
  animation: load2 2s infinite ease 1.5s;
}

.loader {
  font-size: 11px;
  text-indent: -99999em;
  margin: 55px auto;
  position: relative;
  width: 10em;
  height: 10em;
  box-shadow: inset 0 0 0 1em #ffffff;
  -webkit-transform: translateZ(0);
  -ms-transform: translateZ(0);
  transform: translateZ(0);
}

.loader:after {
  width: 5.2em;
  height: 10.2em;
  background: #0dc5c1;
  border-radius: 0 10.2em 10.2em 0;
  top: -0.1em;
  left: 5.1em;
  -webkit-transform-origin: 0px 5.1em;
  transform-origin: 0px 5.1em;
  -webkit-animation: load2 2s infinite ease;
  animation: load2 2s infinite ease;
}

@keyframes load2 {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}

@keyframes roll-in {
  0% {
    top: 10px;
    opacity: 0;
  }
  100% {
    top: 0;
    opacity: 1;
  }
}

 

See also  Angular 9 ngx-input-mask Directive Example to Take Form Fields Mask Input For Validating Phone Numbers,Credit Cards & Dates in Browser Full Project For Beginners

 

script.js

 

 

angular.module('ngQuiz', ['ngSanitize'])

.controller('ngQuizController', function($scope, $timeout, quizProgress, scoreKeeper) {
  $scope.quizProgress = quizProgress;

  $scope.quizData = {
    "quizMetadata": {
      "title": "Loop Quiz",
      "intro": "Do you know the real scoop on the Loop? It’s time to find out!",
      "introImg": "http://interactive.wttw.com/sites/default/files/styles/small-hero/public/B12_b.jpg",
      "introImgCredit": "Alan Brunettin"
    },
    "quizQuestions": [{
      "question": "The Chicago Loop got its name from:",
      "questionImg": "http://interactive.wttw.com/sites/default/files/styles/hero/public/Q1.jpg",
      "feedback": "Before the “L” came to the Loop, steam-powered cable cars circulated downtown, giving the area its name. Later, the elevated tracks and trains of the “L” made the Loop even more accessible to people throughout the Chicago region.",
      "options": [{
        "name": "The “L” tracks that circle the area.",
        "correct": false
      }, {
        "name": "Cable cars that circulated downtown before the “L” was built.",
        "correct": true
      }, {
        "name": "A turnaround circle for horse-drawn carriages.",
        "correct": false
      }]
    }, {
      "question": "What caused the Great Chicago Fire?",
      "questionImg": "http://interactive.wttw.com/sites/default/files/styles/hero/public/Q2.jpg",
      "feedback": "The fire did start in the vicinity of the O’Leary’s barn, but whether a cow kicked over a lantern, or a cinder came from a neighboring chimney, or a drunken neighbor dropped his pipe onto a pile of hay, or a meteor strike occurred (all theories that have been, ahem, hotly debated), no one knows for sure what happened in that barn, and the fire’s initial spark has never been definitively established.",
      "options": [{
        "name": "Mrs. O’Leary’s cow.",
        "correct": false
      }, {
        "name": "A meteor strike.",
        "correct": false
      }, {
        "name": "No one knows for sure.",
        "correct": true
      }]
    }, {
      "question": "What Chicago Loop building, now demolished, is considered the “first skyscraper”?",
      "questionImg": "http://interactive.wttw.com/sites/default/files/styles/hero/public/Q3.jpg",
      "feedback": "The nine-story Home Insurance Building, completed in 1885, was the first building fully framed with metal columns and beams, and so was considered to be the first skyscraper. It was demolished in 1931. Its architect, William LeBaron Jenney, is considered the father of the American skyscraper for his structural engineering innovations.",
      "options": [{
        "name": "The Home Insurance Building.",
        "correct": true
      }, {
        "name": "The Auditorium Building and Theater.",
        "correct": false
      }, {
        "name": "The Sears Tower.",
        "correct": false
      }]
    }, {
      "question": "Architectural preservationist Richard Nickel said, “Great architecture has only two natural enemies.” What are they, according to Nickel?",
      "questionImg": "http://interactive.wttw.com/sites/default/files/styles/hero/public/Q4.jpg",
      "feedback": "Richard Nickel was a young photography student at Illinois Institute of Technology when he first encountered Louis Sullivan’s work. He began documenting Sullivan buildings in photographs; later, he fought for their preservation.<br/><br/> When he couldn’t save the buildings, he salvaged ornament from them. Nickel lost his life in the old Chicago Stock Exchange Building  when it partially collapsed during its demolition in 1972.",
      "options": [{
        "name": "\"Time and pigeons\"",
        "correct": false
      }, {
        "name": "\"Water and stupid men\"",
        "correct": true
      }, {
        "name": "\"Earthquakes and fires\"",
        "correct": false
      }]
    }, {
      "question": "Louis Sullivan’s motto was:",
      "questionImg": "http://interactive.wttw.com/sites/default/files/styles/hero/public/Q5.jpg",
      "feedback": "Sullivan was famous for his idea that form follows function. His designs, such as for the Carson Pirie Scott department store (shown here), expressed the buildings’ purpose with an honesty and elegance that foreshadowed modern architecture.<br/><br/>He wrote: “What is the chief characteristic of the tall office building? It is lofty ... It must be tall, every inch of it tall ... a proud and soaring thing, rising in sheer exultation … without a single dissenting line.”",
      "options": [{
        "name": "\"Form follows function.\"",
        "correct": true
      }, {
        "name": "\"Less is more.\"",
        "correct": false
      }, {
        "name": "\"God is in the details.\"",
        "correct": false
      }]
    }, {
      "question": "Ludwig Mies van der Rohe said:",
      "questionImg": "http://interactive.wttw.com/sites/default/files/styles/hero/public/Q6_0.jpg",
      "feedback": "Mies’ aesthetic was influenced by his experience with Walter Gropius and the German Bauhaus, and by his desire to demonstrate that “less is more.” In Chicago, Mies’ most iconic project (shown here) is the Chicago Federal Center,  whose three buildings illustrate his stark, elegant modernism. The Federal Center also defied previous expectations of what civic structures should look like.<br/><br/>Like Louis Sullivan,  Mies believed that every element of a structure should work as part of a unified whole. In a 1958 interview, he said, “Architecture is a language … and if you are really good, you can be a poet.”",
      "options": [{
        "name": "\"Less is more.\"",
        "correct": true
      }, {
        "name": "\"Mind the gap.\"",
        "correct": false
      }, {
        "name": "\"Make every brick count.\"",
        "correct": false
      }]
    }, {
      "question": "Architect Bruce Graham once famously demonstrated how the Sears Tower (now Willis Tower) would be constructed using:",
      "questionImg": "http://interactive.wttw.com/sites/default/files/styles/hero/public/Q7.jpg",
      "feedback": "Architect Bruce Graham and structural engineer Fazlur Khan of Skidmore, Owings & Merrill employed an innovative construction approach — based on the concept of bundled tubes — to lend stability to the tall structure. Graham famously used a pack of cigarettes to demonstrate the concept to a peer.",
      "options": [{
        "name": "LEGO® blocks",
        "correct": false
      }, {
        "name": "A pack of cigarettes",
        "correct": true
      }, {
        "name": "A supercomputer",
        "correct": false
      }]
    }, {
      "question": "The “Chicago School” style of architecture includes a façade design that reflects:",
      "questionImg": "http://interactive.wttw.com/sites/default/files/styles/hero/public/Q8.jpg",
      "feedback": "The Marquette Building (shown here) serves as an example of the Chicago School style of architecture. It has a three-part façade that parallels a classical column — a clearly identified base, a vertical shaft of floors above, and an ornamented cornice that signifies the capital, or top, of the column.",
      "options": [{
        "name": "A political dynasty",
        "correct": false
      }, {
        "name": "A tree’s base, trunk and leaves",
        "correct": false
      }, {
        "name": "The three parts of a classical column",
        "correct": true
      }]
    }, {
      "question": "The “Chicago Window” is known for:",
      "questionImg": "http://interactive.wttw.com/sites/default/files/styles/hero/public/Q9.jpg",
      "feedback": "The Chicago window has a large, fixed central pane of glass, flanked by two operable narrow sashes. This window design became popular in the 1890s partly because it allowed for natural light and ventilation year round.",
      "options": [{
        "name": "A large fixed center pane",
        "correct": true
      }, {
        "name": "Louvered panels",
        "correct": false
      }, {
        "name": "Stained glass inserts",
        "correct": false
      }]
    }, {
      "question": "Before the advent of the steel frame skeleton, early skyscrapers were supported by:",
      "questionImg": "http://interactive.wttw.com/sites/default/files/styles/hero/public/Q10.jpg",
      "feedback": "In early tall buildings, such as the Monadnock building (shown here), the masonry was “load bearing.” That means the massive granite base of the Monadnock actually supported the full weight of the building’s 16-story walls. It was possibly the tallest skyscraper constructed in this manner, inspiring wonder at the time it was built.<br/><br/>Masonry construction as seen in the Monadnock had its limitations and problems, including extensive settling of the weight into Chicago’s clay soils. Later buildings benefited from the innovative use of steel-frame construction, which allowed for more height without the need for a hulking stone foundation at street level.",
      "options": [{
        "name": "Massive wooden piers",
        "correct": false
      }, {
        "name": "Load-bearing, exterior masonry walls",
        "correct": true
      }, {
        "name": "Neoclassical columns",
        "correct": false
      }]
    }]
  };

  $scope.quizQuestions = $scope.quizData.quizQuestions;
  $scope.quizMetadata = $scope.quizData.quizMetadata;
  quizProgress.lastQuestion = $scope.quizQuestions.length;
  quizProgress.loading = false;

  $scope.startQuiz = function() {
    quizProgress.inProgress = true;
    quizProgress.currentQuestion = 0;
    quizProgress.imageToPreload = 1;
  };

  $scope.nextQuestion = function() {
    if (quizProgress.currentQuestion < quizProgress.lastQuestion) {
      quizProgress.currentQuestion = quizProgress.currentQuestion + 1;
      quizProgress.currentQuestionFriendly = quizProgress.currentQuestionFriendly + 1;
      quizProgress.imageToPreload = quizProgress.imageToPreload + 1;
    }
  };

  $scope.answerQuestion = function(data) {
    $scope.quizQuestions[quizProgress.currentQuestion].answered = true;
    angular.forEach($scope.quizQuestions[quizProgress.currentQuestion].options, function(obj) {
      if (obj.name === data.selected) {
        obj.selected = true;
      } else {
        obj.selected = false;
      }
    });
  };

  $scope.checkAnswer = function() {
    $scope.quizQuestions[quizProgress.currentQuestion].answerChecked = true;

    angular.forEach($scope.quizQuestions[quizProgress.currentQuestion].options, function(obj) {
      if (obj.selected) {
        if (obj.correct) {
          $scope.quizQuestions[quizProgress.currentQuestion].answerWasRight = true;
        } else {
          $scope.quizQuestions[quizProgress.currentQuestion].answerWasRight = false;
        }
      }
    });
  };

  $scope.getScore = function() {
    quizProgress.inProgress = false;
    quizProgress.finished = true;
    quizProgress.calculatingScore = true;
    $scope.score = scoreKeeper.calculateScore($scope.quizQuestions);

    $timeout(function() {
      quizProgress.calculatingScore = false;
    }, 1500);
  };

  $scope.startOver = function() {
    angular.forEach($scope.quizQuestions, function(obj) {
      obj.answered = false;
      obj.answerWasRight = false;
      obj.answerChecked = false;

      angular.forEach(obj.options, function(option) {
        option.selected = false;
      });
    });

    quizProgress.inProgress = true;
    quizProgress.finished = false;
    quizProgress.currentQuestion = 0;
    quizProgress.currentQuestionFriendly = 1;
  };
})

.factory('quizProgress', function() {
  return {
    currentQuestion: 0,
    imageToPreload: 0,
    currentQuestionFriendly: 1,
    lastQuestion: 0,
    loading: true,
    inProgress: false,
    finished: false,
    calculatingScore: false
  };
})

.service('scoreKeeper', function() {
  this.calculateScore = function(quizQuestions) {
    var rightAnswers = 0;
    angular.forEach(quizQuestions, function(obj) {
      if (obj.answerWasRight) {
        rightAnswers += 1;
      }
    });

    return ((rightAnswers / quizQuestions.length) * 100).toFixed() + '%';
  };
})

.directive('progressBar', function(quizProgress) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      scope.$watch('quizProgress', function(newVal, oldVal) {
        if (newVal) {
          element.css('width', ((quizProgress.currentQuestionFriendly / quizProgress.lastQuestion) * 100 + '%'));
        }
      }, true);
    }
  };
})

.directive('imagePreload', function(quizProgress) {
  return {
    restrict: 'EA',
    template: "<img style='display:none;' ng-src='{{quizQuestions[quizProgress.imageToPreload].questionImg}}'/>"
  };
})

.directive('animateProgression', function(quizProgress, $timeout) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      scope.$watch('quizProgress.currentQuestion', function(newVal, oldVal) {
        if (newVal) {
          element.addClass('question-animate');
          $timeout(function() {
            element.removeClass('question-animate');
          }, 1500);
        }
      });
    }
  };
});

Leave a Reply