javascript global variable in event handler - javascript

I'm trying to request a variable declared globally inside of the touchmove function but I'm getting a reference error. Does anybody know what's wrong?
function drawer(pulltab,drawer){
$('#pulltab').on('touchstart',function(e){
notworking=e.originalEvent.touches[0].pageX;
})
$(drawer).on('touchmove',function(loc){
var fingerloc=loc.originalEvent.touches[0].pageX;
var dist=fingerloc-notworking;
console.log(dist);
if (dist<0){
$(this).css('margin-left',dist);
}
})
$(drawer).on('touchend',function(){
$(this).css('transition','margin-left .1s');
$(this).css('margin-left',0);
})
}
drawer('#pulltab','#navigation-drawer');

I'm trying to request a variable declared globally inside of the touchmove function
There are no global variable declarations in your quoted code.
Assuming you haven't declared it, then you are creating (but not declaring) a global variable in the touchstart handler on #pulltab:
notworking=e.originalEvent.touches[0].pageX;
That uses The Horror of Implicit Globals* to create a global. But the global won't exist until that code runs.
Clearly, your touchmove handler on drawer is firing before your touchstart handler on #pulltab. Since there is no existing global called notworking, you can't read its value, and you get a ReferenceError. If the touchstart on #pulltab had executed first, you wouldn't.
Don't rely on the horror of implicit globals. Declare your variables. If you want it to be global, put
var notworking;
...outside all functions. (Although global variables are a Bad Thing™ best avoided; if you only use notworking within the drawer function and you don't need it shared between calls to drawer, just declare it within drawer.) You might also want to check, when using it, whether it has a useful value.
* (that's a post on my anemic little blog)

Related

In this context, what exactly does $('id').on('click', this.method.bind(this)) do?

Here is the app I'm referring to:
I am trying to fundamentally understand the bind method in Javascript.
My understanding when I play around with it in the console is that bind returns a copy of the function, with "this" bound to whatever you pass into bind.
function logThis(){
console.log(this)
}
logThis.bind({today: 'Tuesday'})
//Will return a copy of the logThis function, with 'this' set to the
{today:'Tuesday'} object. The code does not run right away though.
var explicitlyLogThis = logThis.bind({today: 'Tuesday'});
explicitlyLogThis(); //This will run the code and display the {today: 'Tuesday'} object to the console.
This is my understanding so far. I understand that to actually run this new function that has 'this' explicitly bound using the bind method, you need to set it to a variable and then run it.
I see a contradiction when I look at the app in the above link. If you look at the bindEvents method on line 56, we have .on('keyup', this.create.bind(this)). I understand that we have to set 'this' to App when we run the create method because jQuery defaults to setting 'this' to the jQuery object itself. So this line is actually the same as: $('#new-todo').on('keyup', App.create.bind(App)).
That isn't where my confusion is. My question is:
How exactly are these copies of the functions with 'this' set to App actually being called? The app does not set them to a variable and then call that variable the way I had to when I was working in the console.
It just invokes the bound functions directly as soon as an event occurs on one of the jQuery elements. But I thought writing it this way would just return a copy of the function, and not run the function itself, if I am basing my assumptions on what I have figured out in the code I wrote above. I thought in order to invoke the function immediately, you would need to use call or apply.
I also realize that the app runs the bindEvents method when it starts (see line 46). So I understand that when you start the app, copies of the various functions are created with the correct 'this' bound to the functions. But...when/how do they actually get invoked without assigning them to variables? How are these copies accessed?
I think I have a flawed understanding of the bind method, so I would love some help. Thanks!
It sounds like you understand bind well enough. Perhaps there is some confusion with passing anonymous functions. As you know calling bind returns a new function and this can optionally be stored as a variable or passed as a function argument.
In the example below btn1 accepts a bound function as you've seen. This could also be written in a more long hand fashion with btn2. They're identical. btn3 doesn't receive a bound function, when its clicked its context is the button element, this looses all visibility of MagicalApp fucntions.
<button id="example1">button one bound</button>
<button id="example2">button one bound</button>
<button id="example3">button two unbound</button>
<script>
class MagicalApp {
add() {
console.log('this could do addition');
}
}
const app = new MagicalApp();
function contextOfEvent(event) {
console.log('contextSensitive', this.add)
}
const btn1 = document.querySelector("#example1");
btn1.addEventListener('click', contextOfEvent.bind(app));
const btn2 = document.querySelector("#example2");
const btn2ClickHandler = contextOfEvent.bind(app)
btn2.addEventListener('click', btn2ClickHandler);
const btn3 = document.querySelector("#example3");
btn3.addEventListener('click', contextOfEvent);
</script>

ReferenceError: is not defined : localStorage

So i am really confused right now, not sure if I'm being stupid or not but.. when my page loads I want to bind some localStorage to a variable called JsonData.
$(document).ready(function() {
var JsonData = localStorage.getItem(0);
.....
Here is a screen shot of my console to prove localStorage.getItem(0) has a item on page load.
Any ideas?
Because the variable JsonData is defined in a dom ready callback, making it local to that method - you are trying to access the variable from the console where the variable does not exists.
If you really want to access the variable across multiple independent scopes then declare it as a global variable, but I would recommend against it(simple doesn't like to pollute the global scope with my variables)
var JsonData = localStorage.getItem(0);
$(document).ready(function () {
});
since the data has nothing to do with the dom structure you can move out of the dom ready handler
Unless the code is paused by a breakpoint in the same scope JsonData resides, console.log operates on the global scope. JsonData lives inside the ready callback and is not accessible from the global scope, thus the error.
I suggest placing a breakpoint somewhere inside the ready handler. Then you can use console.log. In Chrome, you can pop-out the console from anywhere in dev tools by pressing ESC.

Why are scopes not destroyed even after $destroy is triggered?

I have made a directive that, when clicked, creates a dialog that is appended to the body using jQuery. The problem is that when the dialog is closed, the scopes are never properly cleaned up. As shown in the picture below 167 ChildScopes are preserved. Which matches the amount of items in the dialog which includes the ng-repeat directive.
I attempted to create an extremely simple version of the scenario on Plnkr. To my surprise the scopes ARE in fact being removed on each close in the Plnkr. So something, somewhere in production is causing the scopes to stay alive even after $destroy has been called.
link: ($scope, $element, $attr) ->
$element.on 'click', () ->
$scope.$apply () ->
child = $scope.$new()
template = """<span ng-controller="ListCtrl">...List dialog things...</span>"""
compiledTemplate = $compile(template)(child)
container = containers.createDialogContainer($element)
container.append(compiledTemplate)
#cleanup
$scope.closeWidget = () ->
container.trigger("container_close")
return
container.on "container_close", ()->
child.$apply () ->
child.$destroy()
return
So here is my question:
What can cause a scope to stay alive even after $destroy has been called, triggered and garbage collection performed?
For obvious reasons I cannot show you our production code. However the directive in the Plnkr matches the one im debugging sufficiently.
In general, a scope (or any other JS object) can not be cleaned up by the GC if it is still accessible by another JS object.
In practice, in an Angular project that also uses JQuery, this is most likely caused by:
an Angular service, controller, scope or some other object still having a reference to your scope object
a reference to your object still exists through a DOM element, probably through an event listener. The DOM element might not be GC-able itself because it is still in the cache of JQuery
Your example, for instance, creates a memory leak.
From your code:
$scope.removeDialog = () ->
console.log "closing"
child.$destroy()
$('.listshell').remove()
return
You do not set child to null so $scope.removeDialog still has access to the scope object referenced by the child variable. Therefore, this object can not be GC'ed.
NB: It seems to me that it would be more appropriate to put removeDialog on the child scope. Now your example only works because the child scope is not isolated.
Closure functions can cause a functions Activation object to stay alive even after the scope has been "destroyed". For instance you might have inner functions still referencing variable objects in the functions whose scope you are trying to destroy.
nullifying the reference variables would be the best option as opposed to delete
The only thing I can think of is that if you somewhere have a global function or function outside of the controller or directive that references a method inside of the scope for the directive it will infact keep that scope alive for the duration of the application.

How does browser read the JavaScripts, which should come first (set on the top):event? function? or sub function

A simple question.
I have a web project includes multi JavaScripts.
JS:
// (1) Event
$('.input').keyup(function()
{
keyUpFunction();
});
// (2) Function
function keyUpFunction(){ ... }
(1),(2) which should come first in one javascript file? If the browser read the function first, does it store the function in memory and invoke it when scan the event.
In some case, the same function is defined in multi javascript . e.g.
prm.add_endRequest(function() {
fn1();
fn2();
});
$(document).ready(.......)
Should I duplicate the function name and define each component in each js file.
or keep the function declare in one file and invoke sub-function composite the function?
Functions defined in the following manner:
function fooBar(){}
Are 'hoisted' to the top of the current scope. This means they will always be available, in the current scope, even if they are defined at the end of the file.
This does not hold true if you defined you functions like this:
var fooBar = function(){};
These functions are not hoisted, and must be defined before they can be used.
It should be noted that in your specific example, keyUpFunction will only be called once a keyup event has fired. This also means that all javascript on your page will already be evaluated, so the keyUpFunction will be defined (parsed) already regardless.
EDIT: To be more explicit, this first example is okay:
doSomething('hello world');
function doSomething(str){
console.log(str);
}
However, this will cause you problems:
doSomething('hello world');
var doSomething = function(str){
console.log(str);
}
#Matt's answer covers the function hoisting stuff nicely.
To avoid function name clashes within multiple files, wrap your content in an immediately invoked function expression, e.g.:
(function() {
// put your variables functions here
...
// register event handlers
})();
Any variables or functions declared therein will be constrained to that scope.

What Do You Call The Approach Being Used In This JavaScript Code?

At my current place of work we have a set way of going about JavaScript and was wondering if someone can help shed any light on the below approach to storing variables and cached jQuery objects.
(function($) {
var APP = {};
$(function() {
APP.header = $("#header");
APP.footer = $("#footer");
});
})(jQuery);
Firstly, what is the point of setting what appears to be a global variable and then appending jQuery objects to the variable? Does it keep things cleaner, does it make your app perform any faster or is it an easier way to set variables without having to go:
var header = $("#header");
var footer = $("#footer");
I understand everything else going on, but always wondered why this was common place in all our project JS files? I presume there is a name for what is going on here and I'd like to understand it a little better, especially if there are caveats that I should bring up with my manager about doing this.
The name of these constructs are closure and namespace. A closure is a function that maintains references to variables outside of its scope.
Note that you can now access the APP variable later and it will be correctly updated:
(function($) {
var APP = {};
$(function() {
APP.header = $("#header");
APP.footer = $("#footer");
});
// "APP.header" and "APP.footer" are defined later in the code
})(jQuery);
If you used local variables, you could not get his effect:
(function($) {
$(function() {
var header = $("#header");
var footer = $("#footer");
});
    // "header" and "footer" are long gone local variables
})(jQuery);
Note that you could use global variables (technically properties of window) here:
(function($) {
$(function() {
header = $("#header");
footer = $("#footer");
});
    // "header" and "footer" are accessible global variables
})(jQuery);
But that's bad practice for a number of reasons (notably, possible collisions and unexpectedly defined variables). So you set up what's called a namespace -- a variable like APP to hold your data that needs to be "global-like".
As to the specific utility of this closure in your case, note that it's surrounded by $(). This is a jQuery way of saying "run this functoin when the DOM has finished loading". The DOM has to be finished loading before trying to access $('#header') and $('#footer') to make sure these items actually exist in the DOM. But since this is a callback, it will be execute later, that's why it's need a closure to maintain a reference to APP when it does eventually get called.
It's called namespacing.
This is so that you can keep the DOM clean, and other plugins/scripts won't interfere. If you were to create a global var called header or footer, another plugin may want to use that global var, and thus breaking your code.
APP appears to be the namespace your company uses to have an applicationwide consistent notation without cluttering the global namespace.
Also using variables to store the access to Dom-Elements is faster then accessing them each time needed via the jQuery Construct $("...")
Other than my comment, some "caveats" to "Global Vars"
Local variables are freed from memory whereas global vars sit with the lifetime of the app open
If code is inside a function or in another scope and references that variable, the engine has to slow down to step back until it reaches your global scope, thus causing "lag"
Little known factoid, global scope is shared with the window object!!! This means it takes even LONGER for the engine to find them, thus another negative slow down point

Categories

Resources