How to create a class that will manage goods in JS? - javascript

I do not know how to create a class that will manage the goods.
1. Sort by price
2. Sort by name
I created a constructor that creates objects.
class Products {
constructor(name,price,description,img){
this.name = name;
this.price = price;
this.description = description;
this.img = img;
}
}
var nike = new Products("Nike", 100, "new-shoes","img/nike.png");
var adidas = new Products("Adidas", 120, "classic-shoes","img/adidas.png");
var puma = new Products("Puma",150,"new-shoes","img/puma.png");
var jordan = new Products("Jordan", 170, "outlet-shoes", "img/jordan.png");
var converse = new Products("Converse",70,"outlet-shoes","img/convrse.png")
var nikeAirMax = new Products("Nike Air Max", 200, "shoes","img/nikeAirMax.png");
var newBal = new Products("New Balance 990",179,"new-shoes","img/newBal.png");
var arrGoods = [nike,adidas,puma,jordan,nikeAirMax,converse,newBal];
Then created a function that displays the goods in the HTML file.
function addGoods(item){
for (let i = 0; i<arrGoods.length; i++){
document.getElementById("products").innerHTML += `<div class="info-goods">
<div class="img"><img src=${item[i].img}></div>
<div class="name">${item[i].name}</div>
<div class="price">${item[i].price}</div>
<div class="description">${item[i].description}</div>
</div>`
}
}
addGoods(arrGoods);
created functions that are sorted (by price and by name)
function sortByPrise() {
var div = document.querySelector("#products");
if (div){
div.innerHTML = '';
this.PriseSort(arrGoods);
addGoods(arrGoods);
};
}
function sortByName() {
var div = document.querySelector("#products");
if (div){
div.innerHTML = '';
nameSort(arrGoods);
addGoods(arrGoods);
};
}
function PriseSort(arr){
arr.sort(function(a,b){
return a.price - b.price;
});
};
function nameSort(arr){
arr.sort(function(a,b){
if(a.name > b.name){
return 1;
}
if (a.name < b.name){
return -1;
How to add these functions to another class (for example, class Menedger)

Add all of the data into an array of objects.
Pass a selector string and the array of objects to the constructor. The selector is for the <table> (a table is far better than divs but it can be easily changed if divs are preferred)
Add a method that will add rows from a given array of objects. see .addRows() in demo.
Add a method that sorts an array of objects and passes it along to .addRows(). see .sortCol() in demo.
As a bonus the <th> will sort by column when clicked. The callback isn't part of the class because it's way out of the scope of the question.
const items = [
{name: "Nike", price: 100, desc: "new-shoes", img: "https://www.iconsdb.com/icons/preview/red/nike-xxl.png"},
{name: "Adidas", price: 120, desc: "classic-shoes", img:"https://www.vouchercodes.co.uk/static/v10/images/merchant/logo/128px/1524_160119151356.png"},
{name: "Puma",price: 150,desc: "new-shoes", img:"https://www.freepnglogos.com/uploads/puma-logo-png-1.png"},
{name: "Jordan", price: 170, desc: "outlet-shoes", img:"https://www.svgimages.com/svg-image/s8/air-jordan-logo-256x256.png"},
{name: "Converse",price: 70,desc: "outlet-shoes", img:"https://d13genyhhfmqry.cloudfront.net/widget/mp_340806_2019-04-06-01-57-52-000851.jpg"},
{name: "Nike Air Max",price: 200,desc: "shoes", img:"https://www.iconsdb.com/icons/preview/red/nike-xxl.png"},
{name: "New Balance 990",price: 179,desc: "new-shoes", img:"https://www.vouchercodes.co.uk/static/v10/images/merchant/logo/128px/4484_160309151253.png"}];
class Products {
constructor(selector, items) {
this.table = document.querySelector(selector);
this.items = [...items];
}
addRows(array) {
const rng = document.createRange();
rng.selectNodeContents(this.table);
rng.deleteContents();
for (let item of array) {
let row = `
<tr>
<td><img src='${item.img}' width='50'></td>
<td>${item.name}</td>
<td>${item.price}</td>
<td>${item.desc}</td>
</tr>`;
this.table.insertAdjacentHTML('beforeend', row);
}
}
sortCol(key = 'name', descending = false) {
if (this.items[0].hasOwnProperty(key)) {
const compare = key => {
return (a, b) => {
if (a[key] < b[key]) return descending ? 1 : -1;
if (a[key] > b[key]) return descending ? -1 : 1;
return 0;
};
};
let sorted = this.items.sort(compare(key));
this.addRows(sorted);
}
return false;
}
}
const shoes = new Products('.main', items);
shoes.addRows(items);
const head = document.querySelector('.head');
function callback(e) {
const clicked = e.target;
if (clicked.matches('th')) {
let key = clicked.className;
if (clicked.dataset.dir === '1') {
shoes.sortCol(key, true);
clicked.dataset.dir = '0';
} else {
shoes.sortCol(key);
clicked.dataset.dir = '1';
}
}
return false;
}
head.addEventListener('click', callback);
<table class='catalog'>
<thead class='head'>
<tr>
<th class='name' data-dir='0' colspan='2'>Name</th>
<th class='price' data-dir='0'>Price</th>
<th class='desc' data-dir='0'>Desc</th>
</tr>
</thead>
<tbody class='main'></tbody>
</table>

I would not make the products in the product class. Just keep the product class like:
class Products {
constructor(name, price, description, img){
this.name = name;
this.price = price;
this.description = description;
this.img = img;
}
}
}
Then you can create a Manager class:
class Manager {
constructor() {
this.products = this._createProducts()
}
_createProducts() {
let nike = new Products("Nike", 100, "new-shoes","img/nike.png");
let adidas = new Products("Adidas", 120, "classic-shoes","img/adidas.png");
return [nike, adidas]
}
sortByName() {
this.products.sort(function(prod1, prod2) {
return prod1.name - prod2.name;
});
}
getHTMLRepresentation() {
productsHTML = this.products.map(function(product) {
// return html for each product in the array
return `<div class="info-goods">
<div class="img"><img src=${item[i].img}></div>
<div class="name">${item[i].name}</div>
<div class="price">${item[i].price}</div>
<div class="description">${item[i].description}</div>
</div>`
)));
return productsHTML;
}
}
Now just create an instance of your manager class and call functions on it:
Manager manager = new Manager();
manager.sortByName()
// call a function to create html..
document.querySelector("#products").innerHTML = manager.getHTMLRepresentation();

Related

Jquery: I want to add data to a simple html table column wise

I have 3 JavaScript objects, each of which contain one column data (It has 8 entries). I want to add this data to a html table. I am able to retrieve the column data using nth child but not insert.
code snippet:
countNovels = {
Ramesh: 5,
Kumar: 10,
Sameera: 15,
}
countTales = {
Ramesh: 2,
Kumar: 6,
Sameera: 8,
}
<table id="Summary" cellspacing="0">
<tr>
<th >Name</th>
<th >No. of Novels</th>
<th >No. of Fairytales</th>
<th >Total</th>
</tr>
<tbody></tbody>
</table>
var col = "<td style=\"max-width : 40px\">" + countNovels.Ramesh + "</td><td style=\"max-width : 40px\">" + countNovels.Kumar + "</td><td style=\"max-width : 40px\">" + countNovels.Sameera + "</td>";
$('#Summary td:nth-child(1)').text(col);
This is not actual code.
I want the output something like this
Please do help.
It was a nice question :)
The snippet I created works with any number of source objects (so any number of columns in the end).
The transformation function is not ideal - it could generate a better return format (so the HTML template generation would be simpler).
const countNovels = {
Ramesh: 5,
Kumar: 10,
Sameera: 15,
}
const countTales = {
Ramesh: 2,
Kumar: 6,
Sameera: 8,
}
// transformation function
const transformObject = (arr) => {
const r = arr.reduce((acc, c) => {
// key - countNovels, countTales
// obj - the source object content
// k1 - the name of the person
// v1 - the value of key-name (e.g. countTales-Ramesh = 2)
const [
[key, obj]
] = Object.entries(c)
Object.entries(obj).forEach(([k1, v1]) => {
if (typeof acc[k1] === 'undefined') acc[k1] = {}
acc[k1][key] = v1
})
return acc
}, {})
return r
}
// running transformation with two objects
const transformed = transformObject([{
countNovels
},
{
countTales
}
])
// just a utility function
const wrapTd = (item) => {
return `<td>${item}</td>`
}
// creating the HTML template
const addToTable = (obj) => {
let html = ''
for (key in obj) {
const total = Object.values(obj[key]).reduce((a, c) => a + c, 0)
// creating the columns for the numbers (including total)
let values = ''
Object.values(obj[key]).forEach(e => {
values += wrapTd(e)
})
values += wrapTd(total)
// adding name and numbers to rows
const template = `
<tr>
${wrapTd(key)}
${values}
</tr>
`
html += template
}
return html
}
// adding HTML string to DOM
document.getElementById('tablebody').innerHTML = addToTable(transformed)
<table id="Summary" cellspacing="0">
<tr>
<th>Name</th>
<th>No. of Novels</th>
<th>No. of Fairytales</th>
<th>Total</th>
</tr>
<tbody id="tablebody"></tbody>
</table>
On page load, grab both the objects iterate over them and add rows to the last of the table.
window.onload = function() {
const countNovels = {
Ramesh: 5,
Kumar: 10,
Sameera: 15,
};
const countTales = {
Ramesh: 2,
Kumar: 6,
Sameera: 8,
};
function renderTable() {
const tableRows = Object.entries(countNovels).reduce((acc, curr, index) => {
const name = (curr[0] || '');
const novels = curr[1];
const tales = countTales[curr[0]];
const total = novels + tales;
acc.push({
name,
novels,
tales,
total
});
return acc;
}, []);
const tableBody = document.querySelector('#Summary');
for (const tableRow of tableRows) {
let newRow = tableBody.insertRow(-1);
Object.values(tableRow).forEach((curr, index) => {
let newCell = newRow.insertCell(index);
let newText = document.createTextNode(curr);
newCell.appendChild(newText);
});
}
}
renderTable();
};
table,
th,
td {
border: 1px solid black;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<table id="Summary">
<tr>
<th>Name</th>
<th>No. of Novels</th>
<th>No. of Fairytales</th>
<th>Total</th>
</tr>
<tbody></tbody>
</table>
</body>
</html>

How to update order quantity (increment and decrement) in shopping cart?

I have this following code for the shopping cart with pure Javascript which can add multiply products into cart. Any clue on how to update the product quantity when the user click the + and - button in the cart without changing the order of the item in the cart?
Each button already have the product id as primary key. My idea is I could remove (using pop) the selected object using .filter() and then add (using push) back updated object into the list. But doing so will change the order of the cart.
var productList = [
{ id: 101, product: "Logitech Mouse", unitprice: 45.0 },
{ id: 102, product: "Logitech Keyboard", unitprice: 50.0 },
{ id: 103, product: "HP Mouse", unitprice: 35.0 }
];
var cart = [];
cart.length = 0;
const createCartHTMLElements = object => {
// Check type
if (typeof object !== "object") return false;
// Start our HTML
var html = "<table><tbody>";
// Loop through members of the object
debugger;
object.forEach(function(item) {
html += `<tr><td>${item.product}</td>\
<td>${item.unitprice.toFixed(2)}</td>\
<td>\
<button class="plus-btn" data-id="${item.id}">+</button>\
<label id="quantity">${item.quantity}</label>\
<button class="minus-btn" data-id="${item.id}">-</button>\
</td>\
<td>${item.total.toFixed(2)}</td>\
<td><i class="fa fa-remove del" data-id="${item.id}"></i></td>\
</tr>`;
});
// Finish the table:
html += "</tbody></table>";
// Return the table
return html;
};
const populateProducts = arrOfObjects => {
// Start our HTML
var html = "";
// Loop through members of the object
arrOfObjects.forEach(function(item) {
html += `<div class="column"><div class="card">\
<h2>${item.product}</h2>
<p class="price">RM ${item.unitprice.toFixed(2)}</p>
<p><button class=AddToCart data-id="${
item.id
}">Add to Cart</button></p>\
</div></div>`;
});
return html;
};
window.addEventListener("load", function() {
document.getElementById("productRow").innerHTML = populateProducts(
productList
);
var addToCart = document.getElementsByClassName("AddToCart");
Array.prototype.forEach.call(addToCart, function(element) {
element.addEventListener("click", function() {
debugger;
// Filter the selected "AddToCart" product from the ProductList list object.
// And push the selected single product into shopping cart list object.
productList.filter(prod => {
if (prod.id == element.dataset.id) {
prod.quantity = 1;
prod.total = prod.unitprice;
cart.push(prod);
document.getElementById(
"shoppingCart"
).innerHTML = createCartHTMLElements(cart);
return;
}
});
});
});
});
<div id="shoppingCartContainer">
<div id="shoppingCart"></div>
</div>
<hr />
<div id="productRow"></div>
You use ids multiple times; You should instead apply a class to <label id="quantity">${item.quantity}</label> so that it is <label class="quantity">${item.quantity}</label>. Also please add class price to the price and class total to the total.
Then, you can increase or lower the amount:
$(document.body).on('click', '.plus-btn', function(){
var $tr = $(this).closest('tr');
//update the quantity;
var $quantity = $tr.find('.quantity');
var n = $quantity.html();
var i = parseInt(n) + 1;
$quantity.html(i);
//update the total price
var $price = $tr.find('.price');
var price = parseFloat($price.html());
var $total = $tr.find('.total');
$total.html(i*price);
});
$(document.body).on('click', '.minus-btn', function(){
var $tr = $(this).closest('tr');
//update the quantity;
var $quantity = $tr.find('.quantity');
var n = $quantity.html();
var i = parseInt(n) - 1;
if(i<0) i = 0;
$quantity.html(i);
//update the total price
var $price = $tr.find('.price');
var price = parseFloat($price.html());
var $total = $tr.find('.total');
$total.html(i*price);
});

Undefined input value in table

I am having a problem with a table I'm making with Javascript. The table itself and its functions are working quite nice, but the one thing I am struggling with is submitting the value, and making it be not "undefined".
Provided code is below(values and functions are named in Norwegian, but I hope it is understandable nevertheless).
let skjema = document.getElementById("skjema");
let inpAar = document.getElementById("inpAar");
let inpPromille = document.getElementById("inpPromille");
let inpFart = document.getElementById("inpFart");
let tabell = document.getElementById("tabell");
let lovbruddene = new Map();
lovbruddene.set("2008" , { promille: 9631, fart: 9863});
lovbruddene.set("2009" , { promille: 8593, fart: 12217});
lovbruddene.set("2010" , { promille: 8363, fart: 14920});
lovbruddene.set("2011" , { promille: 8128, fart: 14929});
lovbruddene.set("2012" , { promille: 8514, fart: 15425});
function lagreData(evt){
evt.preventDefault();
if (!lovbruddene.has(inpAar.value)) {
lovbruddene.set(inpAar.value, {})
}
let lovbrudd = lovbruddene.get(inpAar.value);
lovbrudd.promille = Number(inpPromille.value);
lovbrudd.fart = Number(inpFart.value);
lagTabell();
}
function finnAar(){
if (lovbruddene.has(inpAar.value)) {
let lovbrudd = lovbruddene.get(inpAar.value);
inpPromille.value = lovbrudd.promille;
inpFart.value = lovbrudd.fart;
} else {
inpPromille = "";
inpFart = "";
}
}
function slett(key){
lovbruddene.delete(key);
lagTabell();
}
function lagTabell() {
tabell.innerHTML = "";
for ( let [key, lovbrudd] of lovbruddene) {
tabell.innerHTML += `
<tr>
<td>${key}</td>
<td>${lovbrudd.promille}</td>
<td>${lovbrudd.fart}</td>
<td>${lovbrudd.fart + lovbrudd.promille}</td>
<td>
<button onclick="slett('${key}')"class="button tiny">X</button>
</td>
</tr>
`;
}
}
lagTabell();
inpAar.addEventListener("input", finnAar);
skjema.addEventListener("submit", lagreData);

How to select quantity of individual cartItems in KnockoutJS

Hello im fairly new to knock out and im trying to have my array cartItems auto select their quantity from a drop down. Here is my code:
VIEW
<div data-bind="foreach: cartItems">
<h3 data-bind="text: fullname"></h3>
<p data-bind="text: sku"></p>
<select data-bind="quantityDropdown: number"></select>
</div>
VIEWMODEL
var number = 50;
ko.bindingHandlers.quantityDropdown = {
update: function (element) {
for (var i = 1; i < number + 1; i++) {
var selectedQty = "";
for (var x = 0; x < self.cartItems().length; x++) {
var itemqty = parseFloat(self.cartItems()[x].qty, 10);
if (i === itemqty) {
selectedQty = " selected='selected'";
}
}
// Add each option element to the select here
$(element).append("<option value='" + i + "' " + selectedQty + " class='quantity'>" + i + "</option>");
}
}
};
Now i put two items in the cart and the drop down appears. But the "selected" number is the same for both items in the cart? I know its because its not item specific. but I'm not sure how to make it item specific in Knockoutjs.
Working example:
http://jsfiddle.net/GSvnh/5085/
view :
<div data-bind="foreach: CartItems">
<h3 data-bind="text: FullName"></h3>
<p data-bind="text: Sku"></p>
<select name="qty" class="form-control" data-bind="foreach: QuantityDropdown ,value:SelectedQuantity">
<option data-bind="value: Value,text:Name"></option>
</select>
</div>
VM:
$(function () {
var MainViewModel = function () {
var self = this;
self.CartItems = ko.observableArray([]);
//For example you get below array of objects as response
var response = [{ fullname: "ABC", sku: "1234567789", qty: 12 },
{ fullname: "AAA", sku: "2323227789", qty: 20 },
{ fullname: "BBB", sku: "2311227789", qty: 33 }
];
//you map your response and for each item you create a new CartItemViewModel
self.CartItems($.map(response, function (item) {
return new CartItemViewModel(item);
}));
}
var CartItemViewModel = function (data) {
var self = this;
var number = 50;
self.FullName = ko.observable(data.fullname);
self.Sku = ko.observable(data.sku);
self.QuantityDropdown = ko.observableArray();
for (var i = 1; i < number + 1; i++) {
self.QuantityDropdown.push({ Value: i, Name: i });
}
self.SelectedQuantity = ko.observable(parseFloat(data.qty, 10));
self.SelectedQuantity.subscribe(function (newValue) {
alert("selected Qty : "+ newValue);
})
}
ko.applyBindings(new MainViewModel());
})

HTML Javascript Self-assessment quiz/questionnaire

Hi so i got a very basic JavaScript HTML quiz working, however what i want to end up with is an assessment type quiz that has lets say 15 questions based on 3 categories (e.g. Alcoholism, depression, drug abuse) e.g.
How often to you drink alcohol?
- All the time
- Occasionally
- Never
the player answers all 15 questions and at the end depending on how they answered the questions they get assigned a category e.g. your category is Drug Abuse etc.
I'm thinking that maybe each category has its own counter and a value is applied to each of the possible answers e.g. All the time gives a score of 3, occasionally scores a 2 etc. As the player answers the questions, the values get stored in the corresponding category and at the end the scores for each category are added up and the category with the highest score gets assigned to the player?
Any help with this would be appreciated :)
HTML:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h2 id="test_status"></h2>
<div id="test"></div>
</body>
</html>
CSS:
<style>
div#test {
border:#000 1px solid;
padding: 10px 40px 40px 40px;
}
</style>
JS:
<script>
var pos = 0, test, test_status, question, choice, choices, chA, chB, chC, correct = 0;
var questions = [
["How often do you drink?", "All the time", "Often", "Never", "B"],
["Do you ever feel sad for no reason?", "All the time", "Often", "Never", "C"],
["Have you ever tried drugs", "All the time", "Often", "Never", "C"],
["Do you feel uneasy around people", "All the time", "Often", "Never", "C"]
];
function _(x) {
return document.getElementById(x);
}
function renderQuestion () {
test = _("test");
if(pos >= questions.length) {
test.innerHTML = "<h2>Your Category is </h2>";
_("test_status").innerHTML = "Test Completed";
pos = 0;
correct = 0;
return false;
}
_("test_status").innerHTML = "Question "+(pos+1)+" of"+questions.length;
question = questions[pos] [0];
chA = questions[pos] [1];
chB = questions[pos] [2];
chC = questions[pos] [3];
test.innerHTML = "<h3>"+question+"</h3>";
test.innerHTML += "<input type='radio' name='choices' value='A'> "+chA+"<br>";
test.innerHTML += "<input type='radio' name='choices' value='B'> "+chB+"<br>";
test.innerHTML += "<input type='radio' name='choices' value='C'> "+chC+"<br><br>";
test.innerHTML +="<button onclick='checkAnswer()'>submit Answer</button>";
}
function checkAnswer() {
choices = document.getElementsByName("choices");
for (var i=0; i<choices.length; i++) {
if(choices[i].checked) {
choice = choices[i].value;
}
}
if(choice == questions[pos] [4]) {
correct++;
}
pos++;
renderQuestion();
}
window.addEventListener("load", renderQuestion, false);
</script>
The executable Javascript snippet its generated by TypeScript(a public GIT repository is available on this bucket), The quiz its organized by arguments and categories; below you can see the UML diagram.
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Categories;
(function (Categories) {
var QuestionCategory = (function () {
function QuestionCategory(value) {
this.Value = value;
}
return QuestionCategory;
})();
Categories.QuestionCategory = QuestionCategory;
var AQuestionCategory = (function (_super) {
__extends(AQuestionCategory, _super);
function AQuestionCategory() {
_super.call(this, 1);
}
return AQuestionCategory;
})(QuestionCategory);
Categories.AQuestionCategory = AQuestionCategory;
var BQuestionCategory = (function (_super) {
__extends(BQuestionCategory, _super);
function BQuestionCategory() {
_super.call(this, 2);
}
return BQuestionCategory;
})(QuestionCategory);
Categories.BQuestionCategory = BQuestionCategory;
var CQuestionCategory = (function (_super) {
__extends(CQuestionCategory, _super);
function CQuestionCategory() {
_super.call(this, 3);
}
return CQuestionCategory;
})(QuestionCategory);
Categories.CQuestionCategory = CQuestionCategory;
})(Categories || (Categories = {}));
var Questions;
(function (Questions) {
var Answer = (function () {
function Answer(text, value) {
this.Text = text;
this.Value = value;
}
return Answer;
})();
Questions.Answer = Answer;
var Question = (function () {
function Question(text, id, category, answers) {
this.Text = text;
this.ID = id;
this.Category = category;
this.Answers = answers;
}
Question.prototype.Render = function () {
var _this = this;
var dContainer = document.createElement("div");
var dQuestion = document.createElement("h3");
dQuestion.innerHTML = this.Text;
dContainer.appendChild(dQuestion);
var dCategory = document.createElement("div");
dCategory.innerHTML = 'Category: ' + this.Category.Value;
dContainer.appendChild(dCategory);
dContainer.appendChild(document.createElement("br"));
var counter = 0;
this.Answers.forEach(function (a) {
var __id = _this.ID + counter;
var dRadio = document.createElement("input");
dRadio.setAttribute('type', 'radio');
dRadio.setAttribute('id', __id);
dRadio.setAttribute('data-category', _this.Category.Value + '');
dRadio.setAttribute('value', a.Value + '');
dRadio.setAttribute('name', _this.ID);
var dLabel = document.createElement("label");
dLabel.innerHTML = a.Text;
dLabel.setAttribute('For', __id);
dContainer.appendChild(dRadio);
dContainer.appendChild(dLabel);
counter++;
});
dContainer.appendChild(document.createElement("hr"));
return dContainer;
};
return Question;
})();
Questions.Question = Question;
var QuestionCollection = (function () {
function QuestionCollection(questions) {
this.Questions = questions;
}
QuestionCollection.prototype.Render = function () {
var div = document.createElement("div");
this.Questions.forEach(function (q) {
div.appendChild(q.Render());
});
return div;
};
return QuestionCollection;
})();
Questions.QuestionCollection = QuestionCollection;
var QuestionArgument = (function () {
function QuestionArgument(name, collection) {
this.Collection = collection;
this.Name = name;
}
QuestionArgument.prototype.Render = function () {
var div = document.createElement("div");
var h1Arg = document.createElement("h1");
h1Arg.innerHTML = this.Name;
div.appendChild(h1Arg);
div.appendChild(document.createElement("hr"));
div.appendChild(this.Collection.Render());
return div;
};
return QuestionArgument;
})();
Questions.QuestionArgument = QuestionArgument;
var QuizManager = (function () {
function QuizManager(hook, arguments) {
this.Arguments = arguments;
this.Hook = hook;
}
QuizManager.prototype.Render = function () {
var _this = this;
this.Arguments.forEach(function (arg) {
_this.Hook.appendChild(arg.Render());
});
var btn = document.createElement('input');
btn.setAttribute('type', 'button');
btn.setAttribute('value', 'Done');
btn.onclick = function (e) {
_this.Compute();
};
this.Hook.appendChild(btn);
};
QuizManager.prototype.Compute = function () {
var _this = this;
var cats = [], dxCat = [], dxCatTotValue = [];
this.Arguments.forEach(function (arg) {
arg.Collection.Questions.forEach(function (q) {
if (cats.length > 0) {
if (cats.indexOf(q.Category) === -1)
cats.push(q.Category);
}
else
cats.push(q.Category);
});
});
cats.forEach(function (c) {
var p = document.querySelectorAll('input[data-category =\'' + c.Value + '\']:checked');
var tv = 0;
for (var i = 0; i < p.length; i++) {
if (parseInt(p[i]['value']) != NaN)
tv += parseInt(p[i]['value']);
}
dxCatTotValue.push({ "Cat": c.Value, "TVal": tv });
});
this.Hook.appendChild(document.createElement("hr"));
var summariH2 = document.createElement("h2");
summariH2.innerHTML = 'Summary';
dxCatTotValue.sort(this.Compare);
dxCatTotValue.forEach(function (catValue) {
var entryDiv = document.createElement("div");
entryDiv.innerHTML = 'Category ' + catValue['Cat'] + ': ' + catValue['TVal'];
_this.Hook.appendChild(entryDiv);
});
this.Hook.appendChild(document.createElement("hr"));
};
QuizManager.prototype.Compare = function (a, b) {
if (a['TVal'] > b['TVal'])
return -1;
if (a['TVal'] < b['TVal'])
return 1;
return 0;
};
return QuizManager;
})();
Questions.QuizManager = QuizManager;
})(Questions || (Questions = {}));
window.onload = function () {
var CCat = new Categories.CQuestionCategory();
var BCat = new Categories.BQuestionCategory();
var ACat = new Categories.AQuestionCategory();
var q1 = new Questions.Question('Do you eat Apples?', 'q1', CCat, [new Questions.Answer('All the time', 1), new Questions.Answer('Occasionally', 2), , new Questions.Answer('Never', 3)]);
var q2 = new Questions.Question('Do you like Pears?', 'q2', BCat, [new Questions.Answer('Yes', 1), new Questions.Answer('No', 2)]);
var fruitsquestions = new Questions.QuestionCollection([q1, q2]);
var fruitsArguments = new Questions.QuestionArgument('Fruits', fruitsquestions);
var q3 = new Questions.Question('Do you eat Onions?', 'q3', ACat, [new Questions.Answer('Yes', 1), new Questions.Answer('No', 2)]);
var q4 = new Questions.Question('Do you like Cucumbers?', 'q4', CCat, [new Questions.Answer('All the time', 1), new Questions.Answer('Occasionally', 2), , new Questions.Answer('Never', 3)]);
var vegetablesQuestions = new Questions.QuestionCollection([q3, q4]);
var vegetablesArguments = new Questions.QuestionArgument('Vegetables', vegetablesQuestions);
var quiz = new Questions.QuizManager(document.getElementById("content"), [fruitsArguments, vegetablesArguments]);
quiz.Render();
};
<div id="content"></div>
The TypeScript source:
module Categories {
export class QuestionCategory {
Value: number;
Text: string;
constructor(value: number) { this.Value = value; }
}
export class AQuestionCategory extends QuestionCategory {
constructor() { super(1); }
}
export class BQuestionCategory extends QuestionCategory {
constructor() { super(2); }
}
export class CQuestionCategory extends QuestionCategory {
constructor() { super(3); }
}
}
module Questions {
import QC = Categories;
export class Answer {
Text: string;
Value: number;
constructor(text: string, value: number) {
this.Text = text;
this.Value = value;
}
}
export class Question {
Category: QC.QuestionCategory;
Answers: Answer[];
Text: string;
ID: string;
constructor(text: string, id: string, category: QC.QuestionCategory, answers: Answer[]) {
this.Text = text;
this.ID = id;
this.Category = category;
this.Answers = answers;
}
Render(): HTMLElement {
var dContainer = document.createElement("div");
var dQuestion = document.createElement("h3")
dQuestion.innerHTML = this.Text;
dContainer.appendChild(dQuestion);
var dCategory = document.createElement("div")
dCategory.innerHTML = 'Category: ' + this.Category.Value;
dContainer.appendChild(dCategory);
dContainer.appendChild(document.createElement("br"));
var counter = 0;
this.Answers.forEach(a => {
var __id = this.ID + counter;
var dRadio = document.createElement("input");
dRadio.setAttribute('type', 'radio');
dRadio.setAttribute('id', __id);
dRadio.setAttribute('data-category', this.Category.Value + '');
dRadio.setAttribute('value', a.Value + '');
dRadio.setAttribute('name', this.ID);
var dLabel = document.createElement("label");
dLabel.innerHTML = a.Text
dLabel.setAttribute('For', __id)
dContainer.appendChild(dRadio);
dContainer.appendChild(dLabel);
counter++;
});
dContainer.appendChild(document.createElement("hr"));
return dContainer;
}
}
export class QuestionCollection {
Questions: Question[];
constructor(questions: Question[]) { this.Questions = questions; }
Render(): HTMLElement {
var div = document.createElement("div");
this.Questions.forEach(q => {
div.appendChild(q.Render());
});
return div;
}
}
export class QuestionArgument {
Name: string;
Collection: QuestionCollection;
constructor(name: string, collection: QuestionCollection) {
this.Collection = collection;
this.Name = name;
}
Render(): HTMLElement {
var div = document.createElement("div");
var h1Arg = document.createElement("h1");
h1Arg.innerHTML = this.Name;
div.appendChild(h1Arg);
div.appendChild(document.createElement("hr"));
div.appendChild(this.Collection.Render());
return div;
}
}
export class QuizManager {
Hook: HTMLElement;
Arguments: QuestionArgument[];
constructor(hook: HTMLElement, arguments: QuestionArgument[]) {
this.Arguments = arguments;
this.Hook = hook;
}
Render() {
this.Arguments.forEach(arg => {
this.Hook.appendChild(arg.Render());
});
var btn = <HTMLButtonElement> document.createElement('input');
btn.setAttribute('type', 'button');
btn.setAttribute('value', 'Done');
btn.onclick = (e) => { this.Compute(); }
this.Hook.appendChild(btn);
}
Compute() {
var cats = [], dxCat = [], dxCatTotValue = [];
this.Arguments.forEach(arg => {
arg.Collection.Questions.forEach(q => {
if (cats.length > 0) {
if (cats.indexOf(q.Category) === -1)
cats.push(q.Category);
}
else
cats.push(q.Category);
});
});
cats.forEach(c => {
var p = document.querySelectorAll('input[data-category =\'' + c.Value + '\']:checked');
var tv = 0;
for (var i = 0; i < p.length; i++)
{
if (parseInt(p[i]['value']) != NaN)
tv += parseInt(p[i]['value']);
}
dxCatTotValue.push({ "Cat": c.Value, "TVal": tv });
})
//this.Hook.appendChild(btn);
this.Hook.appendChild(document.createElement("hr"));
var summariH2 = document.createElement("h2");
summariH2.innerHTML = 'Summary';
dxCatTotValue.sort(this.Compare);
dxCatTotValue.forEach(catValue => {
var entryDiv = document.createElement("div");
entryDiv.innerHTML = 'Category ' + catValue['Cat'] + ': ' + catValue['TVal'];
this.Hook.appendChild(entryDiv);
});
this.Hook.appendChild(document.createElement("hr"));
}
Compare(a, b) {
if (a['TVal'] > b['TVal'])
return -1;
if (a['TVal'] < b['TVal'])
return 1;
return 0;
}
}
}
window.onload = () => {
var CCat = new Categories.CQuestionCategory();
var BCat = new Categories.BQuestionCategory();
var ACat = new Categories.AQuestionCategory();
var q1 = new Questions.Question('Do you eat Apples?', 'q1',
CCat,
[new Questions.Answer('All the time', 1), new Questions.Answer('Occasionally', 2), , new Questions.Answer('Never', 3)]);
var q2 = new Questions.Question('Do you like Pears?', 'q2',
BCat,
[new Questions.Answer('Yes', 1), new Questions.Answer('No', 2)]);
var fruitsquestions = new Questions.QuestionCollection([q1, q2]);
var fruitsArguments = new Questions.QuestionArgument('Fruits', fruitsquestions);
var q3 = new Questions.Question('Do you eat Onions?', 'q3',
ACat,
[new Questions.Answer('Yes', 1), new Questions.Answer('No', 2)]);
var q4 = new Questions.Question('Do you like Cucumbers?', 'q4',
CCat,
[new Questions.Answer('All the time', 1), new Questions.Answer('Occasionally', 2), , new Questions.Answer('Never', 3)]);
var vegetablesQuestions = new Questions.QuestionCollection([q3, q4]);
var vegetablesArguments = new Questions.QuestionArgument('Vegetables', vegetablesQuestions);
var quiz = new Questions.QuizManager(document.getElementById("content"), [fruitsArguments, vegetablesArguments]);
quiz.Render();
};
this quiz maker produces a very simple set of HTML and it's obvious where the total calculation is in order to change it.
You can simply add the numbers of questions relating to each answer, then compare to say which is largest and display the result. It gives you a choice of having radio buttons in a list for each question, or several on one line.
All the questions will display on a single page, rather than having to press Next each time which can be annoying for people doing the quiz. No CSS is needed and hardly any javascript.
Example code for a self-scoring quiz with 1 question of each type (drop-down box, short answer, multiple answers etc). The generator tool in the link above will create something similar, it's pure HTML and javascript with no external scripts to load, no jquery or dependencies.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional/EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../../dkj.css" type="text/css">
<title>Quiz: Sample "Think Again" Quiz</title>
<script type="text/javascript">
<!--
var stuff = new Array (51) // maximum number of questions
var answered = new Array (51) // processing inhibitor for guessers
for(var i = 0; i<=50; i++){stuff[i]=0; answered[i]=0} //initialize arrays// --> </script>
</head>
<body bgcolor ="#ffff88" text="#000000" link="#000088" vlink="purple" alink="#880000" >
<a name="top"></a>
<p align='right'><font size=-1>
Quiz created: 1999/1/31
</font></p>
<center>
<h2><font color="#ff3333">Sample "Think Again" Quiz</font></h2></center>
<noscript>
<p><font color="#880000">
I'm sorry. This page requires that your browser be capable of running JavaScript in order to use the self-correcting feature of the quiz.
In most browsers you can activate JavaScript using a dialog box somewhere under one of the menu bar options. If you are really using a (rare) non-JavaScript-capable browser, you will have to do without the self-grading features of this page.</font></p>
</noscript>
<p>
<b>Instructions: </b>
Answer the multiple choice questions, guessing if necessary,
then click on the "Process Questions" button to see your
score. The program will not reveal which questions you got wrong, only how
many points you have. Go back and change your answers until you get them all
right. (The message box will rejoice at that point and the page will change color in delight.)</p>
<p>
<b>Points to note: </b>
(1) Questions with only one possible answer are one point each.
(2) Questions with <i>one or more</i> possible answers (represented by check boxes)
give a point for each correct answer, but also subtract a point for each wrong answer!
(3) The program will not attempt to score your efforts at all if
you have not tried at least half of the questions.
(4) This practice quiz is for your own use only.
No record of your progress is kept or reported to anyone. </p>
<hr>
<form name="formzSampQuiz">
1. Fog is notorious in
<blockquote>
<input type=radio name=quest1 onClick="stuff[1]=0; answered[1]=1">New York
<input type=radio name=quest1 onClick="stuff[1]=0; answered[1]=1">Chicago
<input type=radio name=quest1 onClick="stuff[1]=1; answered[1]=1">London
<input type=radio name=quest1 onClick="stuff[1]=0; answered[1]=1">Los Angeles
<input type=radio name=quest1 checked onClick="stuff[1]=0; answered[1]=0">No Answer </blockquote>
2. Chicago is in
<blockquote>
<input type=radio name=quest2 onClick="stuff[2]=0; answered[2]=1">Montana
<input type=radio name=quest2 onClick="stuff[2]=0; answered[2]=1">Manitoba
<input type=radio name=quest2 onClick="stuff[2]=0; answered[2]=1">Missouri
<input type=radio name=quest2 onClick="stuff[2]=1; answered[2]=1">Illinois
<input type=radio name=quest2 checked onClick="stuff[2]=0; answered[2]=0">No Answer </blockquote>
3. The famous French Queen Marie Antoinette was married to
<blockquote>
<select name=quest3 size=1 onChange="figureout3()"><option selected>No Answer <option>St. Louis
<option>Louis XVI
<option>Louis DXLVIII
<option>Louis Rukeyser
<option>Louey, brother of Dewey and and Huey
<option>John L. Louis
</select>
<script type="text/javascript"><!-- //Pre-processor for question 3";
function figureout3() {
if (document.formzSampQuiz.quest3.options.selectedIndex == 0)
{stuff[3] = 0; answered[3]=0} // no answer
else if (document.formzSampQuiz.quest3.options.selectedIndex == 2)
{stuff[3] = 1; answered[3]=1} // right answer
else {stuff[3] = 0; answered[3]=1} // wrong answer
} // end function figureout3()
//--></script>
</blockquote>
4. Compared with Elizabeth II, Elizabeth I was
<blockquote>
<input type=radio name=quest4 onClick="stuff[4]=1; answered[4]=1">earlier
<input type=radio name=quest4 onClick="stuff[4]=0; answered[4]=1">later
<input type=radio name=quest4 checked onClick="stuff[4]=0; answered[4]=0">No Answer </blockquote>
5. Which of the Following are saints?
<blockquote>
<script type="text/javascript">
<!-- //Script to pre-process question 5
function figureout5() {
stuff[5]=0; answered[5]=0
if(document.formzSampQuiz.q5p2.checked==true){stuff[5]--; answered[5]=1}
if(document.formzSampQuiz.q5p3.checked==true){stuff[5]++; answered[5]=1}
if(document.formzSampQuiz.q5p4.checked==true){stuff[5]++; answered[5]=1}
if(document.formzSampQuiz.q5p5.checked==true){stuff[5]--; answered[5]=1}
if(document.formzSampQuiz.q5p6.checked==true){stuff[5]--; answered[5]=1}
} //end function figure5
// --></script>
<input type=checkbox name="q5p2" onClick="figureout5()">
Jack-the-Ripper
<input type=checkbox name="q5p3" onClick="figureout5()">
St. Augustine
<input type=checkbox name="q5p4" onClick="figureout5()">
St. Ursula
<input type=checkbox name="q5p5" onClick="figureout5()">
Adolf Hitler
<input type=checkbox name="q5p6" onClick="figureout5()">
Napoleon
</blockquote>
6. Which of the following is <i>not</i> one of the Seven Deadly Sins?
<blockquote>
<select name=quest6 size=1 onChange="figureout6()"><option selected>No Answer <option>pride
<option>lust
<option>envy
<option>stupidity
<option>anger
<option>covetousness
<option>gluttony
<option>sloth
</select>
<script type="text/javascript"><!-- //Pre-processor for question 6";
function figureout6() {
if (document.formzSampQuiz.quest6.options.selectedIndex == 0)
{stuff[6] = 0; answered[6]=0} // no answer
else if (document.formzSampQuiz.quest6.options.selectedIndex == 4)
{stuff[6] = 1; answered[6]=1} // right answer
else {stuff[6] = 0; answered[6]=1} // wrong answer
} // end function figureout6()
//--></script>
</blockquote>
<script type="text/javascript"><!--// Processor for questions 1-6>
function processqzSampQuiz() {
document.bgColor='#ffff88'
var goodguyszSampQuiz=0 // used to calculate score
var inhibitzSampQuiz=0 // used to prevent processing of partially completed forms
for (var i=1; i<=6; i++){
goodguyszSampQuiz=goodguyszSampQuiz + stuff[i]; inhibitzSampQuiz = inhibitzSampQuiz + answered[i];
} // end for
// Prevent display of score if too few questions completed
if (inhibitzSampQuiz < 3){
document.formzSampQuiz.grade.value="You must try at least 3!"
document.formzSampQuiz.score.value= "Secret!";
} // end if
else {
document.formzSampQuiz.score.value=goodguyszSampQuiz;
if (goodguyszSampQuiz==7){
document.formzSampQuiz.grade.value="Hooray!"
document.bgColor="#ff9999"
}else {document.formzSampQuiz.grade.value="Keep Trying!"}
} // end else
} // end function processqzSampQuiz()
function killall(){ //keep final scores from hanging around after reset clears form
goodguys=0; inhibitaa=0;
for (i=0; i<=50; i++){stuff[i]=0; answered[i]=0}
} // end functionl killall()
// --> </script>
<input type=button name=processor value="Process Questions" onClick=processqzSampQuiz()> <input type=reset value="Reset" onClick="killall(); document.bgColor='#ffff88'">
<input type=text name="grade" value="Nothing!" size=25 onFocus="blur()">
Points out of 7:
<input type=text name="score" value="Zip!" size=10 onFocus="blur()">
<br></form>
<p align='right'><font size=-1>
Return to top.</font></p>
<hr>
<!-- You can edit this acknowledgement out if you like. -->
<p align='right'><font size=-1>
This consummately cool, pedagogically compelling, self-correcting, <br>
multiple-choice quiz was produced automatically from <br>
a text file of questions using D.K. Jordan's<br>
<a href="http://anthro.ucsd.edu/~dkjordan/resources/quizzes/quizzes.html">
Think Again Quiz Maker</a> <br>
of October 31, 1998.<br>
</font></p>
</body></html>

Categories

Resources