Javascript object method is not a function - javascript

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.

Related

addEventListener has no effect when button clicked. (JavaScript)

May I ask for help why my addEventListener is not getting work out and does not click the button? Yet, whenever I pressed the keyboard buttons on my keyboard it works.
I am practicing the projects from the Web Development Bootcamp Course I took by Angela Yu. Hoping for an answer!
Here is the code:
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Piano Kit</title>
<!-- CSS Stylesheet -->
<link rel="stylesheet" href="style.css">
<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="images/">
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Merriweather:wght#400;700&family=Montserrat:wght#400;700&display=swap" rel="stylesheet">
</head>
<body>
<div class="flex-container">
<img class="grandPiano" src="images/grandPianoIcon.png" alt="grandPiano.png">
</div>
<div class="grid-container">
<button class="a key">do</button>
<button class="s key">re</button>
<button class="d key">mi</button>
<button class="f key">fa</button>
<button class="h key">sol</button>
<button class="j key">la</button>
<button class="k key">ti</button>
<button class="l key">do</button>
</div>
<!-- jQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<!-- JavaScript -->
<script src="index.js"></script>
</body>
</html>
JS
// Detecting Button Press
var numberOfPianoKeyButtons = document.querySelectorAll(".key").length;
for (var i = 0; i < numberOfPianoKeyButtons; i++) {
document.querySelectorAll(".key")[i].addEventListener("click", function () {
var buttonInnerHTML = this.innerHTML
// audio
makeSound (buttonInnerHTML);
// animation
buttonAnimation (buttonInnerHTML);
});
}
// Detecting Keyboard Press
document.addEventListener("keydown", function(event) {
// alert("Key was pressed!");
// console.log(event);
// audio
makeSound(event.key);
buttonAnimation(event.key);
});
// Detecting Sound Audio
function makeSound(key) {
// audio
// switch (buttonInnerHTML)
switch (key) {
case "a":
var piano1 = new Audio('sounds/piano1.mp3');
piano1.play();
break;
case "s":
var piano2 = new Audio('sounds/piano2.mp3');
piano2.play();
break;
case "d":
var piano3 = new Audio('sounds/piano3.mp3');
piano3.play();
break;
case "f":
var piano4 = new Audio('sounds/piano4.mp3');
piano4.play();
break;
case "h":
var piano5 = new Audio('sounds/piano5.mp3');
piano5.play();
break;
case "j":
var piano6 = new Audio('sounds/piano6.mp3');
piano6.play();
break;
case "k":
var piano7 = new Audio('sounds/piano7.mp3');
piano7.play();
break;
case "l":
var piano8 = new Audio('sounds/piano8.mp3');
piano8.play();
break;
default: console.log(buttonInnerHTML);
}
}
// Button Animation
function buttonAnimation(currentKey) {
var activeButton = document.querySelector("." + currentKey)
activeButton.classList.add("pressed");
// timeout function
// setTimeout(function, milliseconds, param1, param2, ...)
setTimeout(function() {
activeButton.classList.remove('pressed');
}, 100);
}
There are a few issues with your code, you need to define the key through which the value will be sent (data-key).
<button data-key="a" class="a key">do</button>
<button data-key="s" class="s key">re</button>
<button data-key="d" class="d key">mi</button>
<button data-key="f" class="f key">fa</button>
<button data-key="h" class="h key">sol</button>
<button data-key="j" class="j key">la</button>
<button data-key="k" class="k key">ti</button>
<button data-key="l" class="l key">do</button>
For the click delay, you need to find out the key value for this element:
var pianoKeyButtons = document.querySelectorAll(".key");
pianoKeyButtons.forEach(function (button) {
button.addEventListener("click", function () {
var key = this.getAttribute('data-key');
// audio
makeSound (key);
// animation
buttonAnimation (key);
});
})

Popup content will not appear in the UI - CartoDB Web Mapping Application

I am trying to add content to my popup in my web mapping application, but no content will appear in the popup when it is clicked. Perhaps something wrong with my JSAny help would be fantastic!
Here is my code:
<!DOCTYPE html>
<html>
<head>
<title>Pop-ups | CARTO</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
<link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700' rel='stylesheet' type='text/css'>
<!-- Include Leaflet -->
<script src="https://unpkg.com/leaflet#1.3.1/dist/leaflet.js"></script>
<link href="https://unpkg.com/leaflet#1.3.1/dist/leaflet.css" rel="stylesheet">
<!-- Include CARTO.js -->
<script src="https://libs.cartocdn.com/carto.js/v4.1.11/carto.min.js"></script>
<link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
</head>
<body>
<div id="map"></div>
<aside class="toolbox">
<div class="box">
<header>
<h1>Pop-Ups</h1>
<button class="github-logo js-source-link"></button>
</header>
<section>
<p class="description open-sans">Create pop-up information windows and interact with your map.</p>
</section>
<footer class="js-footer"></footer>
</div>
</aside>
<script>
const map = L.map('map').setView([30, 0], 3);
map.scrollWheelZoom.disable();
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
maxZoom: 18
}).addTo(map);
const client = new carto.Client({
apiKey: 'default_public',
username: 'cartojs-test'
});
const populatedPlacesSource = new carto.source.Dataset(`
ne_10m_populated_places_simple
`);
const populatedPlacesStyle = new carto.style.CartoCSS(`
#layer {
marker-width: 7;
marker-fill: #EE4D5A;
marker-line-color: #FFFFFF;
}
`);
const populatedPlacesLayer = new carto.layer.Layer(populatedPlacesSource, populatedPlacesStyle, {
featureOverColumns: ['name', 'pop_max', 'pop_min']
});
client.addLayer(populatedPlacesLayer);
client.getLeafletLayer().addTo(map);
const popup = L.popup({ closeButton: false });
function openPopup(featureEvent) {
const data = featureEvent.data;
let content = '<div class="widget">';
// My popup up content
content += `<h3> ${data.name} </h3>`;
content += `<p>Between ${data.pop_min} and ${data.pop_max} inhabitants </p>`;
content += `</div>`;
popup.setLatLng(featureEvent.latLng);
if (!popup.isOpen()) {
popup.openOn(map);
}
}
function closePopup(featureEvent) {
popup.removeFrom(map);
}
populatedPlacesLayer.on('featureClicked', openPopup);
</script>
</body>
</html>
And here are the results in the Web Viewer. Note that I am not getting any errors thrown in the Console (image attached to this ticket)
I was expecting the content associated the dataset to appear in the popup ui
enter image description here
You are missing one line of code. The line that set the actual popupContent. After popup.setLatLng(featureEvent.latLng);
include: popup.setContent(content);
<!DOCTYPE html>
<html>
<head>
<title>Pop-ups | CARTO</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
<link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700' rel='stylesheet' type='text/css'>
<!-- Include Leaflet -->
<script src="https://unpkg.com/leaflet#1.3.1/dist/leaflet.js"></script>
<link href="https://unpkg.com/leaflet#1.3.1/dist/leaflet.css" rel="stylesheet">
<!-- Include CARTO.js -->
<script src="https://libs.cartocdn.com/carto.js/v4.1.11/carto.min.js"></script>
<link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
</head>
<body>
<div id="map"></div>
<aside class="toolbox">
<div class="box">
<header>
<h1>Pop-Ups</h1>
<button class="github-logo js-source-link"></button>
</header>
<section>
<p class="description open-sans">Create pop-up information windows and interact with your map.</p>
</section>
<footer class="js-footer"></footer>
</div>
</aside>
<script>
const map = L.map('map').setView([30, 0], 3);
map.scrollWheelZoom.disable();
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
maxZoom: 18
}).addTo(map);
const client = new carto.Client({
apiKey: 'default_public',
username: 'cartojs-test'
});
const populatedPlacesSource = new carto.source.Dataset(`
ne_10m_populated_places_simple
`);
const populatedPlacesStyle = new carto.style.CartoCSS(`
#layer {
marker-width: 7;
marker-fill: #EE4D5A;
marker-line-color: #FFFFFF;
}
`);
const populatedPlacesLayer = new carto.layer.Layer(populatedPlacesSource, populatedPlacesStyle, {
featureOverColumns: ['name', 'pop_max', 'pop_min']
});
client.addLayer(populatedPlacesLayer);
client.getLeafletLayer().addTo(map);
const popup = L.popup({
closeButton: false
});
function openPopup(featureEvent) {
const data = featureEvent.data;
let content = '<div class="widget">';
// My popup up content
content += `<h3> ${data.name} </h3>`;
content += `<p>Between ${data.pop_min} and ${data.pop_max} inhabitants </p>`;
content += `</div>`;
popup.setLatLng(featureEvent.latLng);
popup.setContent(content);
if (!popup.isOpen()) {
popup.openOn(map);
}
}
function closePopup(featureEvent) {
popup.removeFrom(map);
}
populatedPlacesLayer.on('featureClicked', openPopup);
</script>
</body>
</html>

Value is not returning form function

I am a beginner and I am learning JavaScript. I am trying to return a value from a function but I am not getting the value. When I am doing console.log(randomNuber) it is showing undefined. Also, it is not showing anything for the last line of the JavaScript code.
var randomNumberDisplayEl = document.getElementById("random-number-display");
var generateBtnEl = document.getElementById("generate-btn");
function randomDigit() {
var randomEl = parseInt(Math.random() * 10000);
randomNumberDisplayEl.value = randomEl;
return randomEl;
}
var randomNumber = generateBtnEl.addEventListener("click", randomDigit);
console.log("Random Number is:", randomNumber);
console.log(randomNumberDisplayEl.value);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pin Generator</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<!-- <link rel="stylesheet" href="style.css"> -->
<link rel="stylesheet" href="https://res.cloudinary.com/djz3p8sux/raw/upload/v1628938996/StackOverflow/style_til9dq.css">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6">
<div class="pin-generator half-width">
<input class="form-control" id="random-number-display" type="text">
<button class="generate-btn" id="generate-btn">Generate Pin</button>
</div>
</div>
</div>
<div class="notify-section pb-3" id="notify-section">
<p class="notify" id="notify-wrong">❌ Pin Didn't Match, Please try again</p>
<p class="notify" id="notify-right">✅ Pin Matched... Secret door is opening for you</p>
</div>
</div>
<script src="./main.js"></script>
</body>
</html>
Why I am getting the value of randomNumber? Also not getting anything for the last line randomNumberDisplayEl.value.
Actually, I need the randomNumber as a global variable so that I can use it anywhere in the program.
How can I get the value of randomNumber outside of function randomDigit?
Help me please. Thank you.
There seems to be a bit of confusion between what is an element and what is an 'ordinary' variable value, like a number in this case.
In this code:
var randomNumberDisplayEl = document.getElementById("random-number-display");
var generateBtnEl = document.getElementById("generate-btn");
function randomDigit() {
var randomEl = parseInt(Math.random() * 10000);
randomNumberDisplayEl.value = randomEl;
return randomEl;
}
var randomNumber = generateBtnEl.addEventListener("click", randomDigit);
console.log("Random Number is:", randomNumber);
console.log(randomNumberDisplayEl.value);
randomNumberDIsplayEl and generateBtnEl both correctly are elements (hence the El at the end).
However randomEl is set to be a random number. I suggest this be renamed, say to what it is: randomNumber.
Then in the above code, randomNumber is assigned from something (an addEventListener) that doesn't return anything. What we need to do is add the event listener and then in the function called when the user clicks (randomDigit) that is when the random number can be looked at.
The function is named as if it were getting a digit, so I've renamed it to what it is doing, getRandomNumber to try to make the sequence of events clearer.
So the above code becomes:
var randomNumber; //make it global
var randomNumberDisplayEl = document.getElementById("random-number-display");
var generateBtnEl = document.getElementById("generate-btn");
function getRandomNumber() {
randomNumber = parseInt(Math.random() * 10000);
randomNumberDisplayEl.value = randomNumber;
console.log("Random Number is:", randomNumber);
console.log(randomNumberDisplayEl.value);
return randomEl;
}
generateBtnEl.addEventListener("click", getRandomNumber);
Try this
var notifyWrongEl = document.getElementById("notify-wrong");
var notifyRightEl = document.getElementById("notify-right");
var randomNumberDisplayEl = document.getElementById("random-number-display");
var generateBtnEl = document.getElementById("generate-btn");
// Notifications Hide
notifyWrongEl.style.display = "none";
notifyRightEl.style.display = "none";
function randomDigit() {
var randomEl = parseInt(Math.random() * 10000);
randomNumberDisplayEl.value = randomEl;
return randomEl;
}
let randomNumber = 0;
generateBtnEl.addEventListener("click", function(){
randomNumber = randomDigit()
console.log("Random Number is:", randomNumber);
console.log(randomNumberDisplayEl.value);
});
You can declare randomNumber before the randomDigit() function, and set its value to the random number, generated by the function.
Note: randomNumber will be undefined before the first button click. You can initialize it with some default value, if you want to.
var randomNumberDisplayEl = document.getElementById("random-number-display");
var generateBtnEl = document.getElementById("generate-btn");
var randomNumber;
function randomDigit() {
var randomEl = parseInt(Math.random() * 10000);
randomNumberDisplayEl.value = randomEl;
randomNumber = randomEl;
}
generateBtnEl.addEventListener("click", () => {
randomDigit();
/* For Logging purposes*/
console.log("Random Number is:", randomNumber);
console.log(randomNumberDisplayEl.value);
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pin Generator</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<!-- <link rel="stylesheet" href="style.css"> -->
<link rel="stylesheet" href="https://res.cloudinary.com/djz3p8sux/raw/upload/v1628938996/StackOverflow/style_til9dq.css">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6">
<div class="pin-generator half-width">
<input class="form-control" id="random-number-display" type="text">
<button class="generate-btn" id="generate-btn">Generate Pin</button>
</div>
</div>
</div>
<div class="notify-section pb-3" id="notify-section">
<p class="notify" id="notify-wrong">❌ Pin Didn't Match, Please try again</p>
<p class="notify" id="notify-right">✅ Pin Matched... Secret door is opening for you</p>
</div>
</div>
<script src="./main.js"></script>
</body>
</html>
It seems you had the JS code in the CSS section, I put it in the JS section and removed the useless code in the end (addEventListener doesn’t return what the fuction does, the randomNumber should be stored from the function.) and it works. In order to generate 4-digit codes, it needs to generate numbers greater or equal to 1000 or to add leading zeroes.
var randomNumberDisplayEl = document.getElementById("random-number-display");
var generateBtnEl = document.getElementById("generate-btn");
var randomNumber;
function randomDigit() {
randomNumber = parseInt(Math.random() * 9000 + 1000);
randomNumberDisplayEl.value = randomNumber;
}
generateBtnEl.addEventListener("click", randomDigit);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pin Generator</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<!-- <link rel="stylesheet" href="style.css"> -->
<link rel="stylesheet" href="https://res.cloudinary.com/djz3p8sux/raw/upload/v1628938996/StackOverflow/style_til9dq.css">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6">
<div class="pin-generator half-width">
<input class="form-control" id="random-number-display" type="text">
<button class="generate-btn" id="generate-btn">Generate Pin</button>
</div>
</div>
</div>
<div class="notify-section pb-3" id="notify-section">
<p class="notify" id="notify-wrong">❌ Pin Didn't Match, Please try again</p>
<p class="notify" id="notify-right">✅ Pin Matched... Secret door is opening for you</p>
</div>
</div>
<script src="./main.js"></script>
</body>
</html>

Closures with dynamically generated content

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>

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