So I'm Trying to make a "soft auto scrolling" function for and elements scroll-bar, basically its meant to be called then scroll an element for you. However as you can see in the code below I've encapsulated the function in a self-invoking function which holds the element in "element". However when it first reads the variable from the returned function in the line else if (pos>element.scrollHeight) element is returned as null
'use strict';
window.onload=(function()
{
window.scrollTo=(function()
{
var element=document.getElementById('more_info'),
ease=function(pos)
{
var diff=(pos-element.scrollTop).
increment=(diff / Math.abs(diff));
if (Math.abs(diff)<1)
{
element.scrollTop=pos;
return;
}
else if (Math.abs(diff)<30)
{
element.scrollTop+=1-(increment / diff);
}
else
{
element.scrollTop+=increment*10;
}
window.setTimeout(ease,1000 / 10);
};
return function(pos)
{
if (pos<0) {pos=0;}
else if (pos>element.scrollHeight) {pos=element.scrollHeight;}
ease(pos);
};
}());
}());
I Updated the code so that its called after the document loads, however my debugger seems to show that var element is still called before window.onload is
You're executing the onload function immediately.
window.onload = (function () {
...
}());
That makes the function execute then assign the returned value as the onload handler. This means it's executing before the DOM's ready. Change it to remove the self-execution.
window.onload = function () {
...
};
Related
I am trying to understand how this code works. I finally figured out it is a loop. It is not a "while" or "for" loop, but it is a loop nonetheless by virtue of calling itself I think (please correct me if I am wrong).
I understand it's main function: to pass JQuery when it is loaded to my 'foo' function, when ever jQuery has loaded. To do that it checks for jQuery in Window and if not there it resets the timer(). That is the loop. I get that.
Let me explain what I do not understand:
the call: CheckDependency.Deferred.execute(foo);
why the "Deferred" keyword?
execute baffles me: I expect that if I call CheckDependency.Deferred.execute that it would only execute that method. Why does it obviously run the timer function. why could it not simply have that code after the timer() since it keeps looping there and then return jquery?
Speaking of return. Why is there a method in there? CheckDependency.Deferred.execute(foo); is as crazy to me as CheckDependency.Deferred.RETURN.execute(foo); (or some similar crazy statement)
I am fairly new to JavaScript (from PHP). Here the code:
function foo(){ console.log('jQuery found!');
}
var CheckDependency = CheckDependency || { };
CheckDependency.Deferred = function ()
{
var functions = [];
var timer = function() {
if (window.jQuery) {/* && window.jQuery.ui*/
while (functions.length) {
functions.shift()(window.jQuery);
}
} else {
window.setTimeout(timer, 250);
}
};
timer();
return {
execute: function(onJQueryReady)
{
if (window.jQuery) { // && window.jQuery.ui
onJQueryReady(window.jQuery);
} else {
functions.push(onJQueryReady);
}
}
};
}();
CheckDependency.Deferred.execute(foo);
Let me start by saying I'm not a javascript expert, but I dabble :) I'll take a stab at describing what is going on here.
First, This creates a new object called "CheckDependency".
var CheckDependency = CheckDependency || { };
Next, it runs an anonymous function, and stores the result in CheckDependency.Deferred.
CheckDependency.Deferred = function ()
{
.
.
.
.
}()
The anonymous function runs the following code:
var functions = [];
var timer = function() {
if (window.jQuery) {/* && window.jQuery.ui*/
while (functions.length) {
functions.shift()(window.jQuery);
}
} else {
window.setTimeout(timer, 250);
}
};
timer();
The last part of the function code returns a new function execute, which gives CheckDependency.Deferred a function execute.
return {
execute: function(onJQueryReady)
{
if (window.jQuery) { // && window.jQuery.ui
onJQueryReady(window.jQuery);
} else {
functions.push(onJQueryReady);
}
}
};
Finally, this new function is called
CheckDependency.Deferred.execute(foo);
The final result of this is that the code starts a background timer that calls itself until window.jQuery is true - which means jQuery is loaded. Then, the function passed to execute is passed into this loop and so will once jQuery is available, the original function passed to "execute" will be called with the instance of window.jQuery.
I hope I did this justice, and I hope my answer helps! Please let me know if you have any question.
I have an angular animation on an ng-repeat (using jQuery's animate function), and want to update a "Visible" property on the model when each animation completes. The purpose is to orchestrate multiple animations. I am finding this works fine in the enter function, but does not work in the leave function. Here is the code:
app.animation('.step-animation',
function () {
return {
enter: function (element, done) {
var scope = angular.element(element).scope();
jQuery(element).css({ opacity: 0 });
jQuery(element).animate({
opacity: 1
}, 2000, done);
return function (cancelled) {
if (cancelled) {
jQuery(element).stop();
} else {
scope.$apply(function () {
scope.step.Visible = true;
});
}
}
},
leave: function(element, done) {
var scope = angular.element(element).scope();
jQuery(element).animate({
opacity: 0
}, 1000, done);
return function (cancelled) {
if (cancelled) {
jQuery(element).stop();
} else {
scope.$apply(function () {
scope.step.Visible = false;
});
}
}
}
}
});
The Visible property on my step object is being successfully set to true after the enter animation completes, but it is not updated on the leave animation. Also - I notice that the $parent property is null on the scope in the leave function, but populated on the scope in the enter function. It seems like leave is isolated, and enter is not. How can I update the scope from the leave function?
UPDATE
I have discovered that the return function is getting called twice in the leave function - once with cancelled = true. No idea what is causing this, or how to troubleshoot.
For each element in the iterated collection a DOM template will be rendered and a new scope will be created and associated with it.
The leave function in your code is called when one of these templates is removed from the DOM (for example due to filter). When the template is removed its associated scope is destroyed.
This means that when the following function executes the associated scope will already have been destroyed:
return function (cancelled) {
if (cancelled) {
jQuery(element).stop();
} else {
scope.$apply(function () {
scope.step.Visible = false;
});
}
};
You can verify this by adding the following inside it:
console.log(scope.$$destroyed);
When a scope is destroyed one of the things that happens it that its $apply function is set to an empty function:
function noop() {}
This means that the anonymous function (the one that sets Visible to false) that you pass to scope.$apply will never be executed, since $apply is just an empty function and doesn't do anything with its passed arguments.
To solve this you can inject $rootScope and use that instead:
return function(cancelled) {
if (cancelled) {
jQuery(element).stop();
} else {
$rootScope.$apply(function() {
scope.step.Visible = false;
});
}
};
Demo: http://plnkr.co/edit/jdNtcOSzq9BC9vxjmmLy?p=preview
Also note that the element will already be a jqLite element (or jQuery element if jQuery is loaded before AngularJS) so you can replace the following:
var scope = angular.element(element).scope();
With:
var scope = element.scope();
And all occurences of:
jQuery(element)
With just:
element
Preety straight forward question, though I can't find the answer anywhere
I tried these two ways:
setInterval(function(){object/*or this*/.method()},500)
and
setInterval('object/*or this*/.method()',500)
setInterval in fact expects a method as the first argument, though there is an alternative syntax where the first argument can be a string of code (not recommended by most)
If you're having issues with that code, it may have to do with the scope of 'this'
setInterval(function(){this.method()},500)
In the above code, 'this' will refer to the closure itself, and wouldn't be the same as 'this.method' occurring outside of that closure. For example, the following would work:
function MyClass() {
this.thingy = 'yep this is a thingy'
}
var myClass = new MyClass()
// Will log 'MyClass yep this is a thingy'
setInterval(function() { console.log('MyClass', myClass.thingy) }, 1000)
Whereas the following will not work (presuming instantiating the object and calling foo()):
function MyOtherClass() {
this.thingy = 'also a thingy'
}
// Will log 'MyOtherClass undefined'
MyOtherClass.prototype.foo = function() {
setInterval(function() { console.log('MyOtherClass', this.thingy) }, 1000)
}
The second example will work if we get around using 'this' within the closure (presuming instantiating the object and calling bar()):
MyOtherClass.prototype.bar = function() {
var that = this
setInterval(function() { console.log('MyOtherClass', that.thingy) }, 1000)
}
Also be sure that setInterval is being passed the name of a function:
setInterval(someFunction, 500)
rather than executing a function as an argument
setInterval(someFunction(), 500)
This last line of code is usually a mistake, unless someFunction() returns a function itself ;)
The difference between your 2 ways for passing a function to setInterval is whether you want to pass your function as refrence of just copy of it. Allow me to explain it by example:
-1 Referring(demo):
var obj = {
testMethod: function () {
console.log('function (testMethod): intial output');
}
}
setInterval(function () {
obj.testMethod()
}, 1000);
obj.testMethod = function () {
console.log('function (testMethod): changed output');
}
when you run this code, the result 'll be execution of the modified version of testMethod. Because here you dont copy the function! Instead, you refer to it. So whenever function implementation is changed, the last modified version is executed.
-2 Copying(demo):
var obj = {
testMethod: function () {
console.log('function (testMethod): intial output');
}
}
setInterval(obj.testMethod, 1000);
obj.testMethod = function () {
console.log('function (testMethod): changed output');
}
Here all you do is you are passing a copy of the last defined version of the function testMethod to setInterval. So whatever changes you do to testMethod, the result of setInterval will not be changed.
I have a variable created with setInterval called cycle1. It is created with setInterval inside of a prototyped function to an object called eGi, which is the same as $_. After creating it, it still fires, but is inaccessible to the rest of the script and the console. When I try to clear this interval from another prototyped function, nothing happens.
eGi.prototype.startGame = function() {
//other code...
if (somethingOrOther) {
var somethingElse = confirm("start interval?");
if (somethingElse) {
this.cycle1 = setInterval($_.cycle,toMS(INTERVAL_SECONDS));
}
} else {
this.cycle1 = setInterval($_.cycle,toMS(INTERVAL_SECONDS));
}
};
then when i try and stop it in another function
eGi.prototype.gameOver = function() {
clearInterval(this.cycle1);
//other code...
if (restart) {
$_.startGame();
} else {
$_.mainMenu();
}
};
It never gets cleared, and seems to be created again in the calling of $_.startGame. I can't even access it from the Chrome console using $_.cycle1 or the eGi instance variable, egi.cycle1. The strange thing is, this works for accessing any other variable that belongs to my eGi object:
var eGi = function(console,cDom,ctxt,game,devMode) {
$_ = this;
this.game = game;
this.cDom = cDom; //specifically, these objects control the canvas' DOM
this.ctxt = ctxt; //and the CanvasRenderingContext2D
}
eGi.prototype.mainMenu = function() {
this.ctxt.fillText("Hello",250,250); //this works just fine
//etc
};
Why isn't it being cleared?
Full code/game here.
It's a nice game...
The problem is you are referring to "this" inside gameover which doesn't contain reference to cycle1 (undefined).
Instead you have to store "cycle1" as part of an object which can be referenced from your other function (in this case gameover)
Making variables as global is not a good thing. Instead you can store the "cycle1" as part of eGi or any such namespace or object.
Refer here (working code): JSFiddle implementation
Javascript code (start and stop are input buttons)
var eGi = {};
$('#start').click(function start() {
var somethingElse = confirm("start interval?");
if (somethingElse) {
eGi.cycle1 = setInterval(function(){
console.log('Running...');
},1000);
}
});
$('#stop').click(function stop(){
clearInterval(eGi.cycle1);
});
I have a function that listens for a click on the screen and fires a callback. It is part of a Helper object (which is why is preceded by the term Helper in my sample code. That is irrelevant however.
var Helper = {
bodyClickListener: function(fn) {
var window = document.getElementsByTagName('body')[0];
window.click();
CORE.dom.on(window, 'click', function(event) {
CORE.dom.off(window, 'click');
fn(event);
});
}
}
I need to be able to pass a function into this function with a parameter that has been previously set.
function someFunction() {
var popup = document.getElementById('tagResultsPopup');
Helper.bodyClickListener(function(popup) {
return function(event) {
event.stopPropagation();
removePopup(popup);
};
}(document.getElementById('tagResultsPopup')));
function removePopup(element) {
if(element) {
element.parentNode.removeChild(element);
}
};
}
The code above works, but you'll notice that I have to set the popup variable inside of the callback function. It has already been set above. How do I pass a reference to the earlier variable into the callback function.
If I understand your question correctly, you don't need to do much. You can just use the popup variable defined outside.
var popup = document.getElementById('tagResultsPopup');
Helper.bodyClickListener(function(event) {
event.stopPropagation();
//Don't set it
//var popup = document.getElementById('tagResultsPopup');
removePopup(popup);//popup will refer to the correct variable
});
The function that you are passing to bodyClickListener is a closure. You can simply reference 'popup' inside that function without any problem. You don't have to create a new variable.
The answer was to use closure in this way:
Helper.bodyClickListener(function(popup) {
return function(event) {
event.stopPropagation();
removePopup(popup);
};
}(document.getElementById('tagResultsPopup')));
That way the callback function has access to the variable I pass into the parameter function. So here, the return is actually the function I am passing as the callback.