Closures with dynamically generated content - javascript

I'm trying to generate an event listener for every element created dynamically. The problem is in the createDisplay function. I'm constantly receiving some errors. I read that the solutions are the closures, but I'm don't understand at this moment. Can anyone help me to learn how to solve this situation?
$(document).ready(function() {
var counter1 = 0;
var counter2 = 0;
// Our Cats
catsArr = [{
name: "Michelangelo",
picture: "img/cat-picture.jpg",
counter: "counter1",
clicks: 0,
listenerClass: "cat-picture-1"
},
{
name: "Ivanka",
picture: "img/cat-picture-2.jpg",
counter: "counter2",
clicks: 0,
listenerClass: "cat-picture-2"
}
];
// Our main function to print the cats
function createDisplay(catsArr) {
for (i = 0; i < catsArr.length; i++) {
$('.cats-place').append(`
<div class=" cat-img col s6 m6 l6 xl5 offset-xl1 center-align">
<p class="cat-1-name flow-text">${catsArr[i].name}</p>
<img class="responsive-img ${catsArr[i].listenerClass}" src="${catsArr[i].picture}" alt="cat picture">
<div class="col s12 m6 offset-m3 center-align">
<p class="flow-text">Counter = <span class="${catsArr[i].counter}">0</span></p>
</div>
</div>`)
$(`.${catsArr[i].listenerClass}`).click(function() {
var counter = 0;
counter = counter + 1;
$(`.${catsArr[i].counter}`).html(counter);
})
}
};
// Executing the function
createDisplay(catsArr)
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Cat Clicker</title>
<link rel="stylesheet" href="css\style.css">
<!-- Compiled and minified CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css">
<!-- Compiled and minified JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/js/materialize.min.js"></script>
</head>
<body>
<div class="container">
<div class="row cats-place">
</div>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha256-3edrmyuQ0w65f8gfBsqowzjJe2iM6n0nKciPUp8y+7E=" crossorigin="anonymous"></script>
<script src="js\app.js"></script>
</body>
</html>

The issue is that you are trying to reference the i inside the click handler, which has already been iterated to be equal to the length of the array, so it is out of scope. You need to use a closure, or store this variable in another variable, so it is unchanged and preserved for your click handlers.
This modified version uses the forEach method to iterate over the array. An advantage of this is it uses a callback and passes in the element and the index, which for the scope of each call to the callback do not change.
$(document).ready(function() {
var counter1 = 0;
var counter2 = 0;
// Our Cats
catsArr = [{
name: "Michelangelo",
picture: "img/cat-picture.jpg",
counter: "counter1",
clicks: 0,
listenerClass: "cat-picture-1"
},
{
name: "Ivanka",
picture: "img/cat-picture-2.jpg",
counter: "counter2",
clicks: 0,
listenerClass: "cat-picture-2"
}
];
// Our main function to print the cats
function createDisplay(catsArr) {
catsArr.forEach(function(cat) {
$('.cats-place').append(`
<div class=" cat-img col s6 m6 l6 xl5 offset-xl1 center-align">
<p class="cat-1-name flow-text">${cat.name}</p>
<img class="responsive-img ${cat.listenerClass}" src="${cat.picture}" alt="cat picture">
<div class="col s12 m6 offset-m3 center-align">
<p class="flow-text">Counter = <span class="${cat.counter}">0</span></p>
</div>
</div>`)
var counter = 0;
$(`.${cat.listenerClass}`).click(function() {
$(`.${cat.counter}`).html(++counter);
})
});
};
// Executing the function
createDisplay(catsArr)
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Cat Clicker</title>
<link rel="stylesheet" href="css\style.css">
<!-- Compiled and minified CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css">
<!-- Compiled and minified JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/js/materialize.min.js"></script>
</head>
<body>
<div class="container">
<div class="row cats-place">
</div>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha256-3edrmyuQ0w65f8gfBsqowzjJe2iM6n0nKciPUp8y+7E=" crossorigin="anonymous"></script>
<script src="js\app.js"></script>
</body>
</html>

Related

Why is my global variable object (window.[variable]) working locally but not live in the browser?

Junior dev here:
Goal: I would like to define my global variable [array of objects] in one JS file (globalVariables.js) and dynamically access that global variable's key values from different JS (index.js, products.js) and HTML (index.html, products.html, etc.) pages. I will include all of these pages at the bottom.
Essentially, on both index.html and products.html, I am listing my client's products, and the global variable is supposed to fill in all that information dynamically.
According to W3schools section on Global Variables, I should be able to declare the variable like so:
var carName = "Volvo";
and access it like so:
console.log(window.carName)
Unexpected Result: Instead, nothing shows up in the browser and, looking at the console, I read:
jQuery.Deferred exception: Cannot read property '0' of undefined TypeError: Cannot read property '0' of undefined
at HTMLDocument.<anonymous> (https://tiegrrr.com/testing/js/index.js:19:54)
at e (https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js:2:30005)
at t (https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js:2:30307) undefined
Furthermore, if I try defining the global variable like I've seen recommend on some websites...
var window.allProducts = [object, object, object, etc.]
...I get a different error in VS Code:
',' expected.ts(1005)
What am I missing? And why would it work locally but not online, given the directory structure is the same?
==================================================
ALL THE FILES
globalVariables.js
var allProducts = [
{
name: 'TieGrrr Strap',
img: 'tiegrrr-strap.jpg',
desc: "TieGrrr Straps are the safest alternative to stretch and bungee cords. They quickly and securely hold cargo of almost any shape or size. Works great with ladder racks, pipe, lumber, kayaks, rafts, etc.",
popularity:1,
lengths: [3,6,9,12],
colors: ["red","blue","orange","green"],
breakStrengths: ["1,200 lbs"],
cost: 5,
tag:"tiegrrr",
page: "tiegrrr-strap.html"
},
{
name: 'Ratchet Strap',
img: 'Ratchet-S-Hook.jpg',
desc: '',
popularity:2,
lengths: [6,10,12,16],
colors: ["red","blue","orange","green"],
breakStrengths: ['1,500 lb.'],
cost: 8,
tag:"ratchet",
page: "ratchet-strap.html"
},
{
name: 'Heavy Duty Ratchet',
img: 'heavy-duty-strap.jpg',
desc: '',
popularity:3,
lengths: [6,10,12,16],
colors: ["red","blue","orange","green"],
breakStrengths: ['1,500 lb.','3,000 lb.'],
cost: 10,
tag:"heavy",
page: "heavy-duty-ratchet.html"
},
{
name: 'Load Hugger',
img: 'load-hugger.jpg',
desc: '',
popularity:4,
lengths: [6,10,12,16],
colors: ["red","blue","orange","green"],
breakStrengths: ['1,500 lb.'],
cost: 15,
tag:"hugger",
page: "load-hugger.html"
},
{
name: 'Super Duty Ratchet',
img: 'SD Ratchet-F-Hook.jpg',
desc: '',
popularity:0,
lengths: [6,10,12,16],
colors: ["red","blue","orange","green"],
breakStrengths: ['1,500 lb.'],
cost: 12,
tag:"super",
page: "super-duty-ratchet.html"
},
{
name: 'Winch Strap',
img: 'winch-green.jpg',
desc: '',
popularity:0,
lengths: [6,10,12,16],
colors: ["red","blue","orange","green"],
breakStrengths: ['1,500 lb.'],
cost: 9,
tag:"winch",
page: "winch-strap.html"
},
{
name: 'Universal Cam Strap',
img: 'universal-strap1.jpg',
desc: '',
popularity:0,
lengths: [6,10,12,16],
colors: ["red","blue","orange","green"],
breakStrengths: ['1,500 lb.'],
cost: 6,
tag:"uni",
page: "universal-cam-strap.html"
},
{
name: 'Endless Ratchet',
img: 'endless-ratchet-strap.jpg',
desc: '',
popularity:0,
lengths: [6,10,12,16],
colors: ["red","blue","orange","green"],
breakStrengths: ['1,500 lb.'],
cost: 8,
tag:"endless",
page: "endless-ratchet-strap.html"
}
];
indes.js
$(() => {
let $container = $('#item-container')
// TODO: make it so LOOP automatically filters for 1-4
for (i=0;i<4;i++) { // LOOPS through first 4
$newITEM_div = $('<div>') // PARENT div for ITEM + IMG
$newITEM_div.addClass("item")
$newITEM_NAME_div = $('<div>') // div for ITEM NAME
$newITEM_NAME_div.text(window.allProducts[i].name)
$newITEM_NAME_div.addClass("item-name")
$newITEM_IMG = $('<img>')
$newITEM_IMG.css("background-image", `url('../testing/images/${window.allProducts[i].img}')`);
$newITEM_div.append($newITEM_NAME_div)
$newITEM_div.append($newITEM_IMG)
$newITEM_div.attr('onclick',`location.href='./products/${window.allProducts[i].page}'`);
$container.append($newITEM_div)
}
})
console.log(window.allProducts)
products.js
$(() => {
let $container = $('#item-container')
// splits string at every "/" then POPS last array element
var currentPage = $(location).attr('href').split("/").pop();
// TODO: make it so LOOP automatically filters for 1-4 popularity
// on PRODUCTS page, this code loops through ALL PRODUCTS for category imgs
if (currentPage.match("products.html")) {
for (i=0;i<window.allProducts.length;i++) {
$newITEM_div = $('<div>') // PARENT div for ITEM + IMG
$newITEM_div.addClass("product-item")
$newITEM_NAME_div = $('<div>') // div for ITEM NAME
$newITEM_NAME_div.text(window.allProducts[i].name)
$newITEM_NAME_div.addClass("product-item-name")
$newITEM_IMG = $('<img>')
if (currentPage.match("products.html")) {
$newITEM_IMG.css("background-image", `url('../testing/images/${window.allProducts[i].img}')`);
} else {
$newITEM_IMG.css("background-image", `url('../images/${window.allProducts[i].img}')`);
}
$newITEM_div.append($newITEM_NAME_div)
$newITEM_div.append($newITEM_IMG)
$newITEM_div.attr('onclick',`location.href='./products/${window.allProducts[i].page}'`);
$container.append($newITEM_div)
$container.removeAttr('id');
$container.addClass("all-products-container")
}
} else {
for (i=0;i<window.allProducts.length;i++) {
if (currentPage.includes(window.allProducts[i].tag)) {
let currentProduct = window.allProducts[i]
let $productImg = currentProduct.img;
let $productTitle = currentProduct.name;
let $productDesc = currentProduct.desc;
let $productCost = currentProduct.cost;
$("#product-image").attr("src",`../images/`+$productImg);
$('h1').text($productTitle);
$('#description').text($productDesc);
for (i=0;i<currentProduct.lengths.length;i++) { // LOOPS through first 4
$newLength = currentProduct.lengths[i]
$newLength_div = $('<div>')
$newLength_div.text($newLength)
$newLength_div.addClass("length")
$('.lengths').append($newLength_div)
}
for (i=0;i<currentProduct.colors.length;i++) { // LOOPS through first 4
$newColor = currentProduct.colors[i]
$newColor_div = $('<div>')
$newColor_div.addClass("color")
$newColor_div.css("background-color",`${$newColor}`)
$('.colors').append($newColor_div)
}
for (i=0;i<currentProduct.breakStrengths.length;i++) { // LOOPS through first 4
$newBreak = currentProduct.breakStrengths[i];
if (i>0) {
$('#breaks').append(`, `+$newBreak);
} else {
$('#breaks').text($newBreak);
}
}
$('#cost').text(`$`+$productCost+`.00`);
break;
} else {
continue;
}
}
}
})
index.html (head and body, StackOverflow didn't like the full doc for some reason)
<head>
<title>TieGrrr Straps, Inc.</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="author" content="TieGrrr Straps, Inc.">
<meta name="description" content="Manufacturers of high quality tie-down systems at competitive prices.">
<meta name="keywords" content="tie downs, tie-downs, tie down straps, ratchet straps, straps, tie downs, tie down systems, tie down manufacturers">
<!-- BOOTSTRAP CSS -->
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
<!-- TieGrrr Strap CSS -->
<link rel="stylesheet" type="text/css" href="css/styles.css">
<!-- add GOOGLE FONTS here-->
<link href="" rel="stylesheet"> <!-- ADD Google Font when ready-->
<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- BOOTSTRAP JS -->
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<!-- SLICK carousel -->
<link rel="stylesheet" type="text/css" href="js/slick-1.8.1/slick/slick.css"/>
<!-- Add the new slick-theme.css if you want the default styling -->
<link rel="stylesheet" type="text/css" href="js/slick-1.8.1/slick/slick-theme.css"/>
<!-- JS for INDEX PAGE -->
<script src="js/globalVariables.js"></script>
<script src="js/index.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div id="top-thin-bar" class="col">800.810.8881 | sales#tiegrrr.com</div>
</div>
</div>
<nav class="navbar sticky-top">
<div id="main-logo" onclick="location.href='https\://tiegrrr.com'"></div>
<div id="nav-info-content">
<div id="main-logo-mobile" onclick="location.href='https\://tiegrrr.com'"></div>
<div id="company-title">TieGrrr Straps, Inc.</div>
<div id="subtitle">Manufacturers of Quality Tie-Down Systems</div>
<div id="buttons">
<div class="active" onclick="location.href='./index.html'">HOME</div>
<div onclick="location.href='./products.html'">PRODUCTS</div>
<div onclick="location.href='./about-us.html'">ABOUT US</div>
<div onclick="location.href='./contact-us.html'">CONTACT</div>
</div>
</div>
<div id="buttons-mobile"> <!-- starts out HIDDEN -->
<div onclick="location.href='./index.html'">HOME</div>
<div onclick="location.href='./products.html'">PRODUCTS</div>
<div onclick="location.href='./about-us.html'">ABOUT US</div>
<div onclick="location.href='./contact-us.html'">CONTACT</div>
</div>
</nav>
<div class="container-fluid">
<div class="row" id="landing-carousel">
<div id="carousel-container" class="col">
<div id="carousel-inner">
<!-- CHANGE which PICS in STYLES.CSS -- look for #on-sale-item- -->
<div id="on-sale-item-1"></div>
<div id="on-sale-item-2"></div>
<div id="on-sale-item-3"></div>
<div id="on-sale-item-1"></div>
<div id="on-sale-item-2"></div>
<div id="on-sale-item-3"></div>
<div id="on-sale-item-1"></div>
<div id="on-sale-item-2"></div>
<div id="on-sale-item-3"></div>
<div id="on-sale-item-1"></div>
<div id="on-sale-item-2"></div>
<div id="on-sale-item-3"></div>
<div id="on-sale-item-1"></div>
<div id="on-sale-item-2"></div>
<div id="on-sale-item-3"></div>
<div id="on-sale-item-1"></div>
<div id="on-sale-item-2"></div>
<div id="on-sale-item-3"></div>
<div id="on-sale-item-1"></div>
<div id="on-sale-item-2"></div>
<div id="on-sale-item-3"></div>
<div id="on-sale-item-1"></div>
<div id="on-sale-item-2"></div>
<div id="on-sale-item-3"></div>
<div id="on-sale-item-1"></div>
<div id="on-sale-item-2"></div>
<div id="on-sale-item-3"></div>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col text-center" id="page-content">
<div id="item-container"> <!-- use JAVASCRIPT to LOOP through -->
<!-- index.js fills in with TOP 4 POPULAR ITEMS -->
</div>
View ALL PRODUCTS
<p style="color:white; font-size:x-large; font-style:italic; font-weight:800;">GET A GRIP</p>
<p style="color:white; font-size:1.2em; font-weight:600;">We are a family-owned manufacturing company that aims to provide tie-down systems both superior in quality and price to that of any similar products carried by "big-box" stores.</p>
<p style="color:white; font-size:1em;margin-bottom:3vh;">All of our products meet or exceed both D.O.T. and Web &Sling Assoc. standards for safety. Before we will sell any product, it must pass our field and/or lab test for "normal" abuse. Our products may cost as much as other disposable tie-downs, but they will outlast even the most expensive straps.</p>
<p style="color:red; font-size:large; font-style:italic; font-weight:800;">AMERICAN OWNED</p>
<img id="USAflag" src="./images/USA.jpg">
</div>
</div>
</div>
<div class="container-fluid">
<div class="row">
<div class="col" id="footer">
Copyright © 2007 Tiegrrr Straps, Inc.
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script type="text/javascript" src="js/slick-1.8.1/slick/slick.min.js"></script>
<!-- SLICK carousel inline script -->
<script type="text/javascript">
$('#carousel-inner').slick({
slidesToShow: 1,
slidesToScroll: 1,
autoplay: true,
autoplaySpeed: 8000,
});
</script>
</body>
products.html
<head>
<title>TieGrrr Straps, Inc. - Products</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="author" content="TieGrrr Straps, Inc.">
<meta name="description" content="Manufacturers of high quality tie-down systems at competitive prices.">
<meta name="keywords" content="tie downs, tie-downs, tie down straps, ratchet straps, straps, tie downs, tie down systems, tie down manufacturers">
<!-- BOOTSTRAP CSS -->
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
<!-- TieGrrr Strap CSS -->
<link rel="stylesheet" type="text/css" href="css/styles.css">
<!-- add GOOGLE FONTS here-->
<link href="" rel="stylesheet"> <!-- ADD Google Font when ready-->
<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- BOOTSTRAP JS -->
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<!-- JS for PRODUCTS PAGE -->
<script src="js/globalVariables.js"></script>
<script src="js/products.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div id="top-thin-bar" class="col">800.810.8881 | sales#tiegrrr.com</div>
</div>
</div>
<nav class="navbar sticky-top">
<div id="main-logo" onclick="location.href='https\://tiegrrr.com'"></div>
<div id="nav-info-content">
<div id="main-logo-mobile" onclick="location.href='https\://tiegrrr.com'"></div>
<div id="company-title">TieGrrr Straps, Inc.</div>
<div id="subtitle">Manufacturers of Quality Tie-Down Systems</div>
<div id="buttons">
<div onclick="location.href='./index.html'">HOME</div>
<div class="active" onclick="location.href='./products.html'">PRODUCTS</div>
<div onclick="location.href='./about-us.html'">ABOUT US</div>
<div onclick="location.href='./contact-us.html'">CONTACT</div>
</div>
</div>
<div id="buttons-mobile"> <!-- starts out HIDDEN -->
<div onclick="location.href='./index.html'">HOME</div>
<div onclick="location.href='./products.html'">PRODUCTS</div>
<div onclick="location.href='./about-us.html'">ABOUT US</div>
<div onclick="location.href='./contact-us.html'">CONTACT</div>
</div>
</nav>
<div class="container-fluid">
<!-- TODO: remove FLEX STYLES from ROW -->
<div class="row">
<div id="carousel-container" class="col">
<div id="item-container">
<!-- PRODUCTS JS fills in -->
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col text-center" id="page-content">
<div style="margin-top: 2.5vh;">
<p style="color:white; font-size:x-large; font-style:italic; font-weight:800;">GET A GRIP</p>
<p style="color:white; font-size:1.2em; font-weight:600;">We are a family-owned manufacturing company that aims to provide tie-down systems both superior in quality and price to that of any similar products carried by "big-box" stores.</p>
<p style="color:white; font-size:1em;margin-bottom:3vh;">All of our products meet or exceed both D.O.T. and Web &Sling Assoc. standards for safety. Before we will sell any product, it must pass our field and/or lab test for "normal" abuse. Our products may cost as much as other disposable tie-downs, but they will outlast even the most expensive straps.</p>
<p style="color:red; font-size:large; font-style:italic; font-weight:800;">AMERICAN OWNED</p>
<img id="USAflag" src="./images/USA.jpg">
</div>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row">
<div class="col" id="footer">
Copyright © 2007 Tiegrrr Straps, Inc.
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
</body>
UPDATE: I incorrectly called allProducts an object when I first posted, but it's actually an array of objects, if that matters.
When you're adding something to the window it's usually best to do it explicitly.
So your second solution was probably right but your syntax was wrong, try this:
window.allProducts = {objectValues, objectValues, etc.}
Without the var. You only need to use var when creating the variable, since window already exists it'll error if you try and create it.

Javascript object method is not a function

I have been searching here and haven't found something that quite matches, of course correct me if I'm wrong. This seems simple but I cannot see the reason.
function Dice() {
if (!(this instanceof Dice)) {
return new Dice();
};
this.sides = 6
};
Dice.prototype.setUpDieForHTML = function(roll) {
const die = [
'C:\\projects\\apoc\\img\\perspective-dice-six-faces-one.svg',
'C:\\projects\\apoc\\img\\perspective-dice-six-faces-two.svg',
'C:\\projects\\apoc\\img\\perspective-dice-six-faces-three.svg',
'C:\\projects\\apoc\\img\\perspective-dice-six-faces-four.svg',
'C:\\projects\\apoc\\img\\perspective-dice-six-faces-five.svg',
'C:\\projects\\apoc\\img\\perspective-dice-six-faces-six.svg'
];
const img = document.createElement('img');
const dice = $('.dice');
img.classList.add('dice-size');
img.setAttribute('src', die[roll]);
dice.append(img);
}
Dice.prototype.dieRoll = function() {
let result = 1 + Math.floor(Math.random() * 6);
switch (result) {
case 1:
this.setUpDieForHTML(result);
break
case 2:
this.setUpDieForHTML(result);
break
case 3:
this.setUpDieForHTML(result);
break
case 4:
this.setUpDieForHTML(result);
break
case 5:
this.setUpDieForHTML(result);
break
default:
this.setUpDieForHTML(result);
break
}
}
module.exports = {
Dice
};
When I instantiate the object and call dieRoll() I get setUpDieForHTML is not a function. I have moved the code around, changed to a class, run directly in Node REPL it seems to recognize the functions. Also in the dev tools of chrome the instance object has the functions until called.
index.js
'use strict'
const die = require('./js/gamePieces/dice')
const newDie = new die.Dice()
$(() => {
debugger
$('.die-start-icon').on('click', newDie.dieRoll)
})
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title>Fallout Meeples</title>
<!-- <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script> -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Do not add `link` tags-->
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
<!-- Do not add `script` tags-->
<script src="public/vendor.js" type="text/javascript" charset="utf-8" defer></script>
<script src="public/application.js" type="text/javascript" charset="utf-8" defer></script>
</head>
<body>
<main id="apoc" class="game-area">
<section class="player-start-area border yellow">
<h2>Player One</h2>
<section id="playerOne-dice">
<div class="dice">
<img class="die-start-icon dice-size" src="./assets/img/perspective-dice-six-faces-random.svg">
<!--C:\\projects\\apoc\\assets\\img\\perspective-dice-six-faces-random.svg-->
</div>
</section>
</section>
<section class="player-start-area border blue">
<h2>Player Two</h2>
<section id="playerTwo-dice">
<div class="dice"></div>
</section>
</section>
<div class="dice"></div>
</main>
<!-- <script src="./assets/scripts/js/gamePieces/dice.js" type="text/javascript"></script> -->
</body>
</html>
I know there are some other issues in my code but this one thing I couldn't figure out.

Javascript Filereader sort by name

i'm trying to list my image preuploader sort by name but got some issues.i have dozen image with name img001 - img100 but when i input that the result show the files sort by image size. here is my code
<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">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<title>generate nama ikan</title>
</head>
<body>
<div class="flex-center position-ref full-height">
<div class="container">
<div class="row">
<div class="col-md-12">
<h1>Nama Ikan</h1>
<input id="ingambar" type="file" multiple />
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="content">
<br />
<table class="table">
<thead>
<th>gambar</th><th>nama</th>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script>
$('#ingambar').change(function () {
for (var i=0, len = this.files.length; i < len; i++) {
(function (j, self) {
var reader = new FileReader()
reader.onload = function (e) {
$('tbody').append('<tr><td><img width="100px" src="' + e.target.result + '"></td><input class="form-control" type="text" value="' + self.files[j].name.slice(0, -4) + '" name="namaikan[]" disabled/></td></tr>')
}
reader.readAsDataURL(self.files[j])
})(i, this);
}
});
</script>
</html>
can someone show me how to get it done ?
To achieve this you can sort() the table rows after you append a new one, based on the value of the input contained within the row. Try this:
$('#ingambar').change(function() {
for (var i = 0, len = this.files.length; i < len; i++) {
(function(j, self) {
var reader = new FileReader()
reader.onload = function(e) {
$('tbody').append('<tr><td><img width="100px" src="' + e.target.result + '"></td><td><input class="form-control" type="text" value="' + self.files[j].name.slice(0, -4) + '" name="namaikan[]" disabled/></td></tr>');
sortFiles();
}
reader.readAsDataURL(self.files[j])
})(i, this);
}
});
function sortFiles() {
$('.table tbody tr').sort(function(a, b) {
var $a = $(a).find('input'),
$b = $(b).find('input');
return $a.val().localeCompare($b.val());
}).appendTo('.table tbody');
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<div class="flex-center position-ref full-height">
<div class="container">
<div class="row">
<div class="col-md-12">
<h1>Nama Ikan</h1>
<input id="ingambar" type="file" multiple />
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="content">
<br />
<table class="table">
<thead>
<th>gambar</th>
<th>nama</th>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
</div>
</div>
Instead of displaying the images as you read them, you could instead put them all i an array with the same for loop. Then sort the new array with a sort function. And then you just run through the array and display them. Works for me!
You can sort using javascripts Array build in function using a custom sort function with localeCompare. Inserting the following right before the for-loop should do what you want.
this.files.sort((fileA, fileB) => fileA.name.localeCompare(fileB.name));
Providing that this.files is an array of files having a name attribute.

Cannot read property '0' of undefined

I get "Cannot read property '0' of undefined" error. I couldn't find the issue. I think javascript file has a problem but I couldn't see. I wrote the script twice but still js file has a problem.
HTML File
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta charset="UTF-8">
<title>FreeCodeCamp - Local Weather</title>
<script src="https://code.jquery.com/jquery-3.0.0.js"></script>
<script type="text/javascript" src="app.js"></script>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
<div id="main" class="text-center container">
<h1>FreeCodeCamp - Weather App</h1>
<div class="row" id="fade">
<div style="margin-top: 200px;">
<span id="city"></span>
<span id="country"></span>
<div id="weather"><img id="w-icon"><span id="temp"></span></div>
<span id="description"></span>
</div>
</div>
<div id="author">
<span> Created by Kaan Karaca</span><br>
<span>#GitHub </span><br>
<span>#FreeCodeCamp </span>
</div>
</div>
</body>
</html>
JavaScript File
$(document).ready(function () {
var cityId;
var city;
var unitsFormat = "metric";
var getWeatherInfo = function () {
$.getJSON("http://api.sypexgeo.net/json")
.done(function (locationData) {
cityId = locationData.city.id;
cityName = locationData.country.iso;
$.getJSON("http://api.openweathermap.org/data/2.5/weather?", {
id: cityId,
units: unitsFormat,
APPID: '610ae7b6406da76bb34ad4bb95cc3673'
})
.done(function (weatherDate) {
$("#w-icon").attr("src", "http://openweathermap.org/img/w/" + weatherDate.weather[0].icon + ".png");
$("#temp").text(Math.round(weatherDate.main.temp) + "°C");
$("#city").text(weatherDate.name + ",");
$("#country").text(cityName);
$("#description").text(weatherDate.weather[0].description);
});
});
}
getWeatherInfo();
});
Your code is too trusting that all these calls will work.
In my case, the json from http://api.sypexgeo.net/json correctly locates me, but http://api.openweathermap.org/data/2.5/weather?" has no clue about that city id. Therefore it passes back a json such as:
{
"cod": "404",
"message": "Error: Not found city"
}
This obviously lacks the array weather, so js throws an undefined.
The solution would be to get the specs from the weather api (and location, while you're at it) and check that the response code is good. (I guessed "200" is good. I never got the success case).
$(document).ready(function() {
var cityId;
var city;
var unitsFormat = "metric";
var getWeatherInfo = function() {
$.getJSON("http://api.sypexgeo.net/json")
.done(function(locationData) {
cityId = locationData.city.id;
cityName = locationData.country.iso;
$.getJSON("http://api.openweathermap.org/data/2.5/weather?", {
id: cityId,
units: unitsFormat,
APPID: '610ae7b6406da76bb34ad4bb95cc3673'
})
.done(function(weatherDate) {
if (weatherDate.cod != "200") {
console.log(weatherDate);
console.log("Couldn't find the weather!!!");
return;
}
$("#w-icon").attr("src", "http://openweathermap.org/img/w/" + weatherDate.weather[0].icon + ".png");
$("#temp").text(Math.round(weatherDate.main.temp) + "°C");
$("#city").text(weatherDate.name + ",");
$("#country").text(cityName);
$("#description").text(weatherDate.weather[0].description);
});
});
}
getWeatherInfo();
});
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta charset="UTF-8">
<title>FreeCodeCamp - Local Weather</title>
<script src="//code.jquery.com/jquery-3.0.0.js"></script>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div id="main" class="text-center container">
<h1>FreeCodeCamp - Weather App</h1>
<div class="row" id="fade">
<div style="margin-top: 200px;">
<span id="city"></span>
<span id="country"></span>
<div id="weather">
<img id="w-icon"><span id="temp"></span>
</div>
<span id="description"></span>
</div>
</div>
<div id="author">
<span> Created by Kaan Karaca</span>
<br>
<span>#GitHub </span>
<br>
<span>#FreeCodeCamp </span>
</div>
</div>
</body>
</html>

Angularjs fails to dynamic change image src

Hello i'm building an application where i want to dynamically change the source of an image in order to force reload it . The problem is that in order of this i only get a broken image on the browser. Instead , if a run the function manually by a button it runs perfect .
HTML document
<!DOCTYPE html>
<html lang="en" ng-app='cameraApp'>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Node JS Camera</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<script src='https://code.angularjs.org/1.4.4/angular-sanitize.min.js'></script>
<script src="cameraApp.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="jumbotron">
<h1>Welcome to NodeJS Camera v1</h1>
</div>
<div ng-controller="HomeController">
<div class="cameraControl col-md-5">
<p>Here is the camera control</p>
<button class="btn btn-default" ng-click="getSnapshot()">Snapshot</button>
<button class="btn btn-info" ng-click="intervalFunction()">Start Feed</button>
</div>
<div class="lifeFeed col-md-7">
<p>Here is the live feed</p>
<p><button class="btn btn-default" ng-click="readSnapshot()">Snapshot Read</button></p>
<img width='600' height='600' ng-src="{{snapshot}}" alt="SnapShot taken">
</div>
</div>
</div>
</body>
</html>
cameraApp.js
var cameraApp = angular.module('cameraApp',[]);
cameraApp.controller('HomeController', function($scope,$http,$timeout) {
function updateImage() {
var img = 'snapshots/camera.jpg'+ '?decache=' + Math.random();
console.log('Snapshot Loaded');
$scope.snapshot = img;
};
$scope.readSnapshot = updateImage;
$scope.getSnapshot = function() {
$http.get('/api/getSnapshot')
.then(function(response) {
// this callback will be called asynchronously
// when the response is available
console.log('Snapshot captured');
$scope.readSnapshot();
}, function(response) {
console.log('Error in capturing...');
});
}
$scope.intervalFunction = function() {
$timeout(function() {
$scope.getSnapshot();
$scope.intervalFunction();
}, 2000);
};
// Kick off the interval
$scope.intervalFunction();
});
There are two solutions I've used for this in the past.
1) Use an ng-if/ng-show on your img tag. This will prevent the broken image from displaying.
<img ng-if='snapshot'>
2) Set a default image that will load and then be replaced once the other images load.
$scope.snapshot = 'snapshots/default.png';

Categories

Resources