Trouble referencing object from within function - adobe animate canvas - javascript

I am having trouble getting a function to reference a movie clip on the stage (thatsRight). I can reference it outside of a function to initially set it visible = false and inside the this.Correct function to visible = true, but calling another function this.removeAndCheck can not reference the same movie clip on the stage. I get the error
"TypeError: undefined is not an object (evaluating
'this.thatsRight.visible = false')"
on the line in the this.removeAndCheck function. This doesn't make sense to me. One function can reference the movie clip but another can not. This code is on frame.
this.thatsRight.visible = false;
this.Correct = function() {
this.thatsRight.visible = true;
setTimeout(this.removeAndCheck, 3000)
}
this.removeAndCheck = function() {
this.thatsRight.visible = false;
this.CheckAllCorrect();
}
I am also have issue with this.CheckAllCorrect() being called. this.CheckAllCorrect() is also on from one but on another action layer.
This is part of a conversion of different as3 flash assets to html5 canvas assets using adobe animate CC. Any help with this would be greatly appreciated.

#Sammeer is correct, this is a scoping issue. Typically I get around this with a Function.bind
setTimeout(this.removeAndCheck.bind(this), 3000);
You might also see local variable binding like this:
var that = this;
setTimeout(function() { that.removeAndCheck(); }, 3000);
Here is some further reading.

This is a scoping issue with the value of the this variable, which is a common mistake in javascript. To avoid these issues completely, just use arrow functions instead:
this.thatsRight.visible = false;
this.removeAndCheck = () => {
this.thatsRight.visible = false;
this.CheckAllCorrect();
}
this.Correct = () => {
this.thatsRight.visible = true;
setTimeout(this.removeAndCheck, 3000)
}

Related

Javascript: run object method on DOM object selected through other property

I am very new to javascript.
Here I am failing to run an object method on a DOM element that I selected through another property of the same object. I suspect there is something wrong with my thinking!
Thanks in advance for any piece of help.
var Arrow = function() {
this.current = $('.arrow');
this.previous = null;
this.bend = function() {
// do bend
};
};
var arrow = new Arrow();
arrow.current.bend();
bend() is a method of Arrow, not current. Use arrow.bend() and it will also have access to current using this.current.
arrow.current.bend is not defined.
You have defined:
this.current as the Array of DOM elements.
this.bend as method with a function.
Hence, you can call:
arrow.current >> returns Array of DOMs
arrow.bend() >> executes function bend.
arrow.current.bend() does not exist.
Also, note that arrow.current is an array. You'd first need to get each of the elements:
for (element of arrow.current) { element.bend(); }
However, as said before, element does not have a bend element by default and you have not appended at any point. Only arrow has a bend property.
I hope this guides you on why this does not work.
However, if you want to open a question on what you are trying to achieve, maybe we can help to get it fixed.
You need to call bend() on arrow object. In bend() function, you do what you need to do.
var Arrow = function() {
this.current = $('.arrow');
this.previous = null;
this.bend = function() {
// do bend
current.style = 'bent';
};
};
var arrow = new Arrow();
arrow.bend();
So two things.
You called the right method on the wrong object
arrow.bend(); // not arrow.current.bend()
The second possible problem is with this.current = $('.arrow');. To get the an element from the DOM, you should make sure it's totally loaded. I'd suggest the following
var Arrow = function($arrow) {
this.current = $arrow;
this.previous = null;
};
// To avoid creating the `bend` in every instance of Arrow
Arrow.prototype.bend = function() {
console.log(this.current.attr('id'));
};
$(function () {
// Now it's certain that the DOM is completely loaded
var arrow = new Arrow($('.arrow').first());
arrow.bend();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="arrow" id="toto">arrow<div>

Javascript / Why mycode is not synchronous

I have discover that a custom code is not syncronous as I thought.
I have this pseudo code:
ObjectA = function ()
{
var pointer;
var value =[];
this.set_pointer = function (p) {pointer = p;}
this.return_value = function () {return value[pointer];}
}
ObjectB = function ()
{
var SCOPE = this;
var OBJ = new ObjectA();
....
this.reset = function ()
{ OBJ.set_pointer(0);}
this.draw = function (what)
{
SCOPE.update();
OBJ.set_pointer(from);
OBJ.get_value();
// do somethings with Three.js
// draw some lines and some little pointclouds.
// do some things
// update two text elements
}
}
Main = new ObjectB();
Main.draw(7);
Main.reset();
ObjectA is using arraybuffers, dataviews and typedarrays.
ObjectB is using Three.js to draw some very symple 3D things.
The problem is inside 'draw'.
OBJ.get_value(); is using the pointer value 0 (zero) instead 7.
Abnormally (as I think) main.draw(7) is not executed first and later Main.reset(); It seems that Main.reset() is inmediatelly executed, so I have 0 (zero)
I'm not going to wait any DOM synchronism.
What can be the reason of this bechaviour?. Maybe the Three,js use ? The OOP style I'm using ?
Is there any way to check why is this happen?
Any idea would be appreciated
NOTE: Sorry for use the Three.js tag.
SOLVED
I have found the reason (or I think ) of a NO synchonism
Sometimes 'this' could be pointing to 'window' instead of the self instance of your object.
Sometimes, a bad use of this (when it is 'window') can raise an error you have not taken into account. Then a next line of code can be executed, and sometimes you can have the impression of an incorrect (not syncronous) operation.
So.... review the bad use of 'this'....

Javascript object methods and binding functions

I'm looking for some help because I don't quite think I understand the Javascript scoping rules. What I'm trying to do in the below example is to push a button on a page that then starts listening for keyboard input. Once the keyboard input has started if there is a break in input for two seconds I want to stop capturing the input and pop an alert with the full contents of the input collected to that point. This is an example I made purely for this question.
What I see is that I click the button and start entering input. On each keypress I am alerted to the string collected to that point. After the two second, no-action timeout takes place I see an alert with the contents "undefined". The first alerts listed above come from startLog(). The second alert comes from stopLog(). What am I doing wrong when I call stopLog that it is telling me that this.message is undefined?
function Logger() {
this.message = '';
this.listenTimer;
this.startLog = function() {
this.message = '';
$(document).bind('keypress', {this_obj:this}, function(event) {
event.preventDefault();
var data = event.data;
clearTimeout(data.this_obj.listenTimer);
data.this_obj.message += String.fromCharCode(event.which);
alert(data.this_obj.message);
data.this_obj.listenTimer = setTimeout(data.this_obj.stopLog, 2000);
});
};
this.stopLog = function() {
$(document).unbind("keypress");
alert(this.message);
};
}
var k = new Logger();
$('.logging-button').click(function() {
k.startLog();
});
The issue is this. When you pass an object method as an event handler, it loses its object context; this will refer to the window object.
There are various ways to fix this, but the main issue is that you need to pass setTimeout a closure that will still refer to the correct context:
setTimeout(function() { data.this_obj.stopLog() }, 2000);
On a separate note, you can save yourself some unnecessary code by just using a closure to refer to the object, rather than binding it as event.data:
this.startLog = function() {
this.message = '';
var this_obj = this;
$(document).bind('keypress', function(event) {
event.preventDefault();
clearTimeout(this_obj.listenTimer);
// etc
});
};
var k = new Logger();
$('.logging-button').click(function() {
k.startLog.apply(this);
//Setting context of "this" so that it refers to element even in startLog()
});

Javascript Class Inheritance

Can anyone tell me why my 'showDiv_boo' is undefined inside the class´s method?
I also can´t access my class´s methods.
Here´s my class 'Blink' class with its properties and methods:
function Blink(div) {
this.div = div
}
Blink.prototype.counter = 0
Blink.prototype.showDiv_boo = true
Blink.prototype.showDiv = function() {
this.div.style.visibility = 'visible'
}
Blink.prototype.hideDiv = function() {
this.div.style.visibility = 'hidden'
}
Blink.prototype.startEngine = function() {
if (this.showDiv_boo) {
this.showDiv()
} else if (!this.showDiv_boo) {
this.hideDiv()
}
this.showDiv_boo = !this.showDiv_boo
this.counter++
}
Blink.prototype.startEffect = function() {
this.idEffect = setInterval(this.startEngine, 1000 / 45)
}
So, if I create:
_blink = new Blink(myDiv);
_blink.startEffect();
You can test... the variable 'showDiv_boo', is undefined inside the method.
Even, if I set the showDiv_boo inside the method to true, it won´t call my class´s methods showDiv or hideDiv.
Anyone?
Thanks :)
The reason why is that startEngine is called from setInterval. The way in which this callback is invoked causes startEngine to have a different value for this than startEffect. You need to save this in order to maintain it in the callback. For example.
Blink.prototype.startEffect = function () {
var self = this;
self.idEffect = setInterval(function () { self.startEngine(); }, 1000 / 45);
};
You need to:
use var self and call the method via self.startEngine()
use an anonymous function to wrap the call in [1] i.e. function(){ self.startEngine(); }
This is because when you just pass this.startEngine or self.startEngine you are just passing the function startEngine without specifying what this is, which in both cases is supplied by the global conext of DOMWindow.
To give an example...
function startEngine() {
...code omitted...
};
Blink.prototype.startEngine = startEngine;
Blink.prototype.start = function() {
setTimeout(startEngine, 0); // obviously wrong, what is this?
setTimeout(Blink.startEngine, 0); // actually the same as line above, although not as obvious
setTimeout(startEngine.bind(this), 0); // works correctly
}
works to add code to the prototype and if used in the anonymous function will work as expected, but if you just use Blink.startEngine as the callback it is exactly the same as using startEngine only the second is more obviously wrong because there's no object it is being called on so you'd expect this to be whatever is supplied by the context.
The other way you could do this without using the anonymous function would be
Blink.startEngine.bind(self)
Which returns a function that will call startEngine with the correct this same as explicitly creating the anonymous function and wrapping the call to self.startEngine()
Heres a link to a fiddle to play around with the differences: http://jsfiddle.net/bonza_labs/MdeTF/
If you do the following, you will find it is defined
var x = new Blink('hello');
x.showDiv_boo
Javascript uses prototypical inheritance. While showDiv_boo may not be explicitly defined within the instance of Blink that you now have, it does exist within the prototype that Blink inherits from. When you try referencing showDiv_boo from within the object, the Javascript engine realizes the object does not own a member by that name and then will check its prototype.
Along with setting a temporal variable to store this, you must call the startEngine() function with that variable:
Blink.prototype.startEffect = function(){
var self = this;
self.idEffect = setInterval(function(){ self.startEngine.call(self); }, 1000/45);
}
Note the .call(self), which basically calls the function with the variable self, so the variable this in startEngine will be the correct one.

Flash player control from javascript outside?

I am making flash player that suppose to be controlled from outside, from javascript.
I need those methods:
Play/Pause and Volume level
I am stuck with volume level... I tried to add this code:
flashMovie.volume = 10;
Where flashMovie is flash instance... And it's show NO ERROR but it's NOT WORKING
I try to make inner AddCall(); and then when it's called to call() from javascript to return sound level.
AS 3:
function setthisvolume()
{
var vlm = ExternalInterface.call('giveMeVolume()');
this.soundTransform.volume = vlm;
}
ExternalInterface.addCallback("setthisvolume", setthisvolume);
JS:
var soundlevel = 10;
function soundlevelset()
{
var flashMovie=getFlashMovieObject("objswf");
flashMovie.setthisvolume();
}
function giveMeVolume()
{
return parseInt(soundlevel);
}
But I am getting this error:
Error calling method on NPObject!
I even tried with setInterval():
AS 3:
function setthisvolume()
{
var vlm = ExternalInterface.call('giveMeVolume()');
this.soundTransform.volume = vlm;
}
setInterval(setthisvolume, 1000);
JS:
var soundlevel = 10;
function giveMeVolume()
{
return parseInt(soundlevel);
}
And it doesn't show any error, but it doesn't work neither...
Did someone work with stuffs like this?
Can someone help me what I am doing wrong here...
Thank you!
Thank you, #someone!
This second option worked okay!
Here is working code:
AS3:
function setthisvolume(vlm)
{
this.soundTransform = new SoundTransform(vlm);
}
ExternalInterface.addCallback("setthisvolume", setthisvolume);
JS:
function getFlashMovieObject(movieName)
{
if (window.document[movieName])
{
return window.document[movieName];
}
if (navigator.appName.indexOf("Microsoft Internet")==-1)
{
if (document.embeds && document.embeds[movieName])
return document.embeds[movieName];
}
else
{
return document.getElementById(movieName);
}
}
var soundlevel = 0.5; // it's 0-1 volume, not 0-100
function soundlevelset()
{
var flashMovie=getFlashMovieObject("objswf");
flashMovie.setthisvolume(parseFloat(soundlevel));
}
When you are using slider each time slider change you need to change soundlevel variable and call soundlevelset();
Hope I helped next one who is starting with this... :)
Thank you!
Try removing the parentheses when calling giveMeVolume, by changing this:
var vlm = ExternalInterface.call('giveMeVolume()');
to this:
var vlm = ExternalInterface.call('giveMeVolume');
If that doesn't work, try passing the volume directly as an argument/parameter, like this (this is probably a better way to do it):
AS3:
function setthisvolume(vlm)
{
this.soundTransform.volume = vlm;
}
ExternalInterface.addCallback("setthisvolume", setthisvolume);
JS:
var soundlevel = 10;
function soundlevelset()
{
var flashMovie=getFlashMovieObject("objswf");
flashMovie.setthisvolume(soundlevel);
}
Code looks reasonable.
Check if you allow Flash to communicate with script There is property when you create Flash object - AllowsScriptAccess - http://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e3d118a9b90204-7c9b.html .
Check if Falsh is coming from the same domain as HTML page.
For addCallback check if you are getting correct Flash object by Id (the way to create Flash is different in IE/FF, so you may be getting the wrong one).
Check if you have correct SWF file - browser may cache older version... I.e. add element on the Flash control that simply shows static number and make sure it matches to latest one.

Categories