Global variable used in object property not updating inside the object - javascript - javascript

I have an object set up like so:
let xVal = 0;
const myObj = {
infoText: "The value of x is: " + xVal
}
This infoText is referenced later to display somewhat of a tooltip when hovering over an element.
function showTooltip(obj) {
targetEl = document.getElementById('targetId');
targetEl.innerHTML = obj.infoText;
}
The value of xVal can change. The issue I'm running into is that despite whether or not that value has changed, when I hover over my element, it will always display the initial value of xVal. I assume this is because myObj.infoText is established when it's initiated and pulls the initial value of xVal. How can I get myObj.infoText to show the current xVal and keep up with the changes?
EDIT - Here is a better example of my code, I realize I offered a poor sample originally.
let count = 0;
let clickVal = 1;
const myObj = {
cost: 10,
infoText: `This displays the current value of your click <br />
Current click = ` + clickVal
};
function cardContent(obj) {
targetEl = document.getElementById('targetId');
targetEl.innerHTML = obj.infoText;
}
cardContent(myObj); // initialize card content
function handleClick() {
count += clickVal;
}
function upgradeClick() {
count -= myObj.cost;
clickVal += 1;
cardContent(myObj) // attempting to update the text to reflect new value
}
There is a button that invokes handleClick and one that invokes upgradeClick. Using CSS, the following div is hidden and shows when hovering over the upgradeClick button.
<div id='targetId'></div> This is where the infoText shows.

You can use something like a getter
let xVal = 0;
const myObj = {
get infoText() {return "The value of x is: " + xVal;}
}
function showTooltip(obj) {
console.log(obj.infoText);
}
showTooltip(myObj);
xVal = 29;
showTooltip(myObj);
xVal = 794;
showTooltip(myObj);

Creating the object everytime inside of the showTooltip should work
let xVal = 0;
function showTooltip() {
const myObj = {
infoText: "The value of x is: " + xVal
}
console.log(myObj.infoText);
}
showTooltip();
xVal = 50;
showTooltip();

Related

Add variable property new value to previous value (javascript)

Good afternoon. Is it possible to add a new object property value to its previous value?
I have tried the following code but browser returns "Maximum call stack size exceeded". The property translate will be used to drag a chart horizontally. It will shift the data range of an array that will be painted on the canvas chart. Kind regards.
function drawChart() {
.
.
.
tickerData = [..., ..., ...];
dataLength = tickerData.length;
barSpace = Number(localStorage.getItem("barspace"));
barWidth = (0.7 * barSpace).toFixed(1);
rightSpan = 3 * barSpace;
barStrokeWidth = 1;
if(!(dataLength - dragCanvas.translate() > dataLength)) {
dataLength = dataLength - dragCanvas.translate();
}
else {
dataLength = dataLength;
}
.
.
.
}
var dragCanvas = {
isTrue : false,
drag : [0, 0],
translate : function() {
return this.translate() + Math.ceil((this.drag[1] - this.drag[0])/barSpace);
}
};
function updateChartPaint(e) {
var pointerX = e.clientX;
var pointerY = e.clientY;
if(!dragCanvas.isTrue) {
dragCanvas.drag[0] = pointerX;
dragCanvas.drag[1] = pointerX;
}
else {
dragCanvas.drag[1] = pointerX;
$("#chartCanvas").empty();
drawChart();
}
}
document.addEventListener("mousemove", updateChartPaint, false);
document.getElementById("chartCanvas").onmousedown = function() {
dragCanvas.isTrue = true;
};
document.getElementById("chartCanvas").onmouseup = function() {
dragCanvas.isTrue = false;
};
You are calling this.translate() inside of the translate function so it goes into an infinite loop calling itself until eventually the call stack is exceeded.
From the way translate is called it looks like the function should be defined like this instead:
translate : function() {
const newTranslate = this.oldTranslate + Math.ceil((this.drag[1] - this.drag[0])/barSpace);
this.oldTranslate = newTranslate;
return newTranslate;
}
oldTranslate: 0
I assume that barSpace is declared outside of the function and will be a valid value. It seems to be set from localStorage but if it does not exist, then Number(localStorage.getItem("barspace")) will be zero and the return value from translate will be Infinity. Is that intended?
Also updateChartPaint sets a variable called pointerY but never uses it. Is it correct that dragging in the Y-axis is ignored and only changes in the X-axis matters?

How to Set the value of an angular variable to another variable dynamically

I have a slideshow on my website with left and right buttons.
Like this (http://i.prntscr.com/863ad10cfd4e4f1ea9b90721cc6582e8.png).
I am using angular to change the image on left and right.
As you can see in the function I increase the value
/*SlideShow Pictures*/
$scope.picture_1 = "./images/photos/watch.jpg";
$scope.picture_2 = "./images/photos/watch.jpg";
$scope.picture_3 = "./images/photos/watch.jpg";
$scope.picture_4 = "./images/photos/watch.jpg";
$scope.picture = $scope.picture_1;
$scope.picture_value = 1;
$scope.image_change_right = function () {
if ($scope.picture_value < 4)
{
$scope.picture_value = $scope.picture_value + 1;
$scope.picture = ('$scope.picture_' + $scope.picture_value);
console.log($scope.picture_value);
}
else{
$scope.picture_value = 1;
$scope.picture = ('$scope.picture_' + $scope.picture_value);
console.log($scope.picture_value);
}
}
Above is the function called for button right press.
The function increases the variable by 1 and adds it to the string to call the new variable. In the console log it looks great! However I think it is only showing as a string --- it is not actually setting the value of scope.picture to the variable.
How can I set this to not be a string but as a valid variable?
Thanks everyone!
A better way would be like this:
The Controller:
// The array of picture links.
$scope.pictures = [
"./images/photos/watch.jpg",
"./images/photos/watch.jpg",
"./images/photos/watch.jpg",
"./images/photos/watch.jpg"
];
$scope.current = 0; // Initialize the current pictures place in the array.
$scope.picture = $scope.pictures[$scope.current]; // Set the current picture.
// The direction is either 1 or -1;
$scope.changePicture = function (direction) {
$scope.current += direction; // add or remove one depending on direction.
$scope.current %= $scope.pictures.length; // Normalize the number based on the length of the pictures array.
console.log($scope.picture);
}
The Html:
<img src="{{picture}}">
<button ng-click="changePicture(1)">Next</button>
<button ng-click="changePicture(-1)">Previous</button>
Why don't you use an array with image links like this?
/*SlideShow Pictures*/
$scope.pictures = ["./images/photos/watch.jpg", "./images/photos/watch.jpg", "./images/photos/watch.jpg", "./images/photos/watch.jpg"];
$scope.picture = $scope.pictures[0];
$scope.picture_value = 0;
$scope.image_change_right = function () {
if ($scope.picture_value < 4)
{
$scope.picture_value = $scope.picture_value + 1;
$scope.picture = $scope.pictures[$scope.picture_value];
console.log($scope.picture_value);
}
else{
$scope.picture_value = 0;
$scope.picture = $scope.pictures[$scope.picture_value];
console.log($scope.picture_value);
}
}

Change properties of a class from time to time

I have two functions. In the first one I increase a variable by adding 100 to it and I put a setInterval so the funcion repeats itself after some time. The other function is a class, a contrusctor to create an object. I want this.x_origen to get increased by adding aumento to it after some time and repeat it. However what I'm getting here is that the first function increases aument and then it finishes and then the second function starts. How can I solve this?
var aument = 0;
function aumento(){
aument = aument + 100;
return aument;
}
setInterval(function () {aumento()}, 1000/50);
function create_class_brick (x_origen_in, y_origen_in, x_final_in, y_final_in, mi_estado, mi_velocidad, mi_id){
this.x_origen = x_origen_in + aumento();
this.y_origen = y_origen_in;
this.x_final = x_final_in + aumento();
this.y_final = y_final_in;
this.estado = mi_estado;
this.velocidad = mi_velocidad;
this.id_elemento = mi_id;
this.DESPLAZAR_LADRILLO = desplazar_ladrillo;
this.F0 = f0;
this.F2 = f2;
this.crear_ladrillo = crear_ladrillo;
this.obtener_x_origen_ladrillo = obtener_x_origen_ladrillo;
this.obtener_y_origen_ladrillo = obtener_y_origen_ladrillo;
this.obtener_x_final_ladrillo = obtener_x_final_ladrillo;
this.obtener_y_final_ladrillo = obtener_y_final_ladrillo;
}
An example on how to wait for the initial call:
function brick (x_origen_in){
this.x_origen = x_origen_in;
}
function aumento(brick){
console.log(brick.x_origen);
brick.x_origen += 100;
setTimeout(aumento.bind(this, brick), 500);
}
var brick = new brick(100);
aumento(brick);
http://jsfiddle.net/x6c08u39/
You can use Object.defineProperty to dynamically generate the value whenever it is accessed.
First, lets simplify the auto-incrementing of aument:
var aument = 0;
function aumento(){
aument += 100;
}
// The first argument for setInterval is the function to execute
// No need to figure out the interval value at runtime as there are no dynamic values
setInterval(aumento, 20); // 1000/50 === 20
Now lets make an object that will have a the correct value:
function create_class_brick (x_origen_in, y_origen_in, x_final_in, y_final_in, mi_estado, mi_velocidad, mi_id){
Object.defineProperty(this, 'x_origen', {
get: function () { return x_origen_in + aument; }
});
// Other stuff
// ...
}
A quick test:
> aument
34100
> var obj = new create_class_brick(23);
undefined
> obj.x_origen
161523
> obj.x_origen
167223
> obj.x_origen
172423

undefined style

I have homework from university, classic 15 puzzle. I have problem with those two styles. Here is the code that i have problem
function siirra_pala(pala) {
var palaRivi = parseInt(pala.style.top) / palanKoko;
var palaSarake = parseInt(pala.style.left) / palanKoko;
}
Error code is "Uncaught TypeError: Cannot read property 'top' of undefined" and "Uncaught TypeError: Cannot read property 'left' of undefined".
If it helps:
siirra_pala(pala) is move_tile(tile)
palaRivi is tileRow and palaSarake is tileColumn
palanKoko is tileSize.
I have palanKoko set to 100. And style is defined in:
function muodosta_palat(pelialue) {
for (var y = 0; y < 4; y++) {
for (var x = 0; x < 4; x++) {
if (!(x === tyhja_paikka.x && y === tyhja_paikka.y)) {
var pala = document.createElement('div');
pala.id = 'pala' + x + y;
pala.textContent = 4 * y + x + 1;
pala.style.left = x * palanKoko + 'px';
pala.style.top = y * palanKoko + 'px';
pala.className = 'pala';
pelialue.appendChild(pala);
}
}
}
If you need more code, please tell which one. Thank You
#Bergi:
window.onload = function () {
muodosta_palat(document.getElementById('pelialue'));
var palat = document.querySelectorAll(".pala");
document.getElementById('sekoitusnappi').onclick = sekoita;
for (var i = 0; i < palat.length; i++) {
palat[i].addEventListener("click", siirra_pala);
palat[i].addEventListener("mouseover", mouseOver);
palat[i].addEventListener("mouseout", mouseOut);
}
};
From your error it would seem pala is undefined (not set, doesn't exist), at least not in the scope of that function.
Variable pala is created within a function, and it's only known in this function. What you want to do is capture the click event, and pass what was clicked to the function.
If you change call to the function..
palat[i].addEventListener("click", function () { siirra_pala(this) });
the reference should be ok.
Here:
palat[i].addEventListener("click", siirra_pala);
the parameter passed to siirra_pala is the click event, not the clicked element. You should modify your function to either select the clicked element property from the event object or simply use this.
See this:
document.getElementById('x').addEventListener("click", handler);
function handler(e) {
console.log(e); // full event object
console.log(this); // clicked element
this.style.background = "#aaa";
}
#x {
width: 50px;
height: 50px;
background: #eee;
}
<div id="x"></div>
So the fix for your function would be something like this:
function siirra_pala(pala) {
var palaRivi = parseInt(this.style.top) / palanKoko;
var palaSarake = parseInt(this.style.left) / palanKoko;
}
(bear in mind that this function is not very useful)

webGL story sphere popups

I am trying to adapt the really cool looking WebGL Story Sphere, source code and css here. There's one big problem: once you click on a news article, the text of the article in the popup is always the same. I want to modify the code so that when you click on an article, the right text appears in the popup.
I'm working from a set of article texts that I specify in the code, e.g. var captions = ["good","better","best"]. Though the article titles and images populate correctly in the popup, I can't get the text to do so. Can you help me?? Here's what I've got:
// function code
var passvar = null; // failed attempt to store texts for later
function initialize() {
math = tdl.math;
fast = tdl.fast;
canvas = document.getElementById("canvas");
g_fpsTimer = new tdl.fps.FPSTimer();
hack();
canvas.addEventListener("mousedown", handleMouseDown, false);
canvas.addEventListener("mousemove", handleMouseMove, false);
canvas.addEventListener("mouseup", handleMouseUp, false);
// Create a canvas 2d for making textures with text.
g_canvas2d = document.createElement('canvas');
window.two2w = window.two2h = g_tilesize;
g_canvas2d.width = two2w;
g_canvas2d.height = two2h;
g_ctx2d = g_canvas2d.getContext("2d");
window.gl = wu.create3DContext(canvas);
if (g_debug) {
gl = wd.makeDebugContext(gl, undefined, LogGLCall);
}
//gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, gl.TRUE);
// Here is where I specify article titles, images, captions
// Titles and images populate the popup correctly, captions don't...
var titles = ["a","b","c"];
var captions = ["good","better","best"];
var images = ['imagesphere/assets/1.jpg',
'imagesphere/assets/bp/2.png',
'imagesphere/assets/bp/3.png'
];
var headlines = titles.concat( titles);
var blurbs = captions.concat( captions);
var tmpImages = [];
var tmpHeadlines = [];
var tmpCaptions = [];
// make a bunch of textures.
for (var ii = 0; ii < g_imagesDownGrid; ++ii) {
var textures = [];
for (var jj = 0; jj < g_imagesAcrossGrid; ++jj) {
var imgTexture = new ImgTexture();
textures.push(imgTexture);
if (tmpImages.length == 0) {
tmpImages = images.slice();
}
if (tmpHeadlines.length == 0) {
tmpHeadlines = headlines.slice();
}
if (tmpCaptions.length == 0) {
tmpCaptions = blurbs.slice();
}
var rando = math.randomInt(tmpImages.length);
var img = tmpImages.splice(rando, 1)[0];
var headline = tmpHeadlines.splice(rando, 1)[0];
var caption = tmpCaptions.splice(rando, 1)[0];
passvar = caption;
if (img.indexOf('videoplay.jpg') > -1){
window.vidtexture = imgTexture;
images = images.slice(1); // dont use that thumb again.
headlines = 'WebGL Brings Video To the Party as Well'
}
imgTexture.load(img, /* "[" + jj + "/" + ii + "]" + */ headline);
}
g_textures.push(textures);
}
// And here's where I try to put this in a popup, finally
// But passvar, the stored article text, never refreshes!!!
<div id="story" class="prettybox" style="display:none">
<img class="close" src="imagesphere/assets/close.png">
<div id="storyinner">
<input id = "mytext">
<script>document.getElementById("mytext").value = passvar;</script>
</div>
</div>
And here is my click handler code:
function sphereClick(e){
window.console && console.log('click!', e, e.timeStamp);
var selected = g_textures[sel.y][sel.x];
window.selected = selected;
animateGL('eyeRadius', glProp('eyeRadius'), 4, 500);
var wwidth = $(window).width(),
wheight = $(window).height(),
story = $('#story').width( ~~(wwidth / 7 * 4) ).height( ~~(wheight / 6 * 5) ),
width = story.width(),
height = story.height(),
miniwidth = 30;
story.detach()
.find('#storyinner').find('h3,img,caption').remove().end().end()
.show();
story.css({
left : e.pageX,
top : e.pageY,
marginLeft : - width / 2,
marginTop : - height / 2
}).appendTo($body); // we remove and put back on the DOM to reset it to the correct position.
$('style.anim.story').remove();
$('<style class="anim story">')
.text( '.storyopen #story { left : ' + (wwidth / 3 * 2) + 'px !important; top : ' + wheight / 2 + 'px !important; }' )
.appendTo($body);
$(selected.img).prependTo('#storyinner').parent();
$('<h3>').text(selected.msg.replace(/\(.*/,'')).prependTo('#storyinner');
$body.addClass('storyopen');
} // eo sphereClick()
There's a lot wrong here, but here's a start. It won't solve your problem, but it will help you avoid issues like this.
var passvar = null; is a global variable.
Your loop for (var ii = 0; ... sets that global variable to a new value on every iteration.
Later, you click something and the global variable passvar is never changed.
If you want to use this pattern, you need to set passvar from your click handler so it has the value that was clicked. Since you didn't actually post your click handlers, it's hard to advise more.
But this is also a bad pattern, functions take arguments for a good reason. Since you have to find your clicked item in the click handler anyway, why not pass it directly which does involve a shared global variable at all?
var handleMouseUp = function(event) {
var story = findClickedThing(event);
if (obj) {
showPopup(story.texture, story.caption);
}
}
Which brings me to this:
var titles = ["a","b","c"];
var captions = ["good","better","best"];
var images = ['imagesphere/assets/1.jpg',
'imagesphere/assets/bp/2.png',
'imagesphere/assets/bp/3.png'
];
When you have 3 arrays, all of the same length, each array describing a different property of an object, you are doing it wrong. What you want, is one array of objects instead.
var stories = [
{
title: "a",
caption: "good",
image: "imagesphere/assets/1.jpg"
}, {
title: "b",
caption: "better",
image: "imagesphere/assets/bp/2.jpg"
}, {
title: "c",
caption: "best",
image: "imagesphere/assets/bp/3.jpg"
},
];
console.log(stories[1].caption); // "better"
Now once you find the clicked object, you can just ask it what it's caption is. And you can pass the whole object to the popup maker. And no field is handled differently or passed around in a different manner, because you are not passing around the fields. You are passsing the entire object.

Categories

Resources