user1869935
user1869935

Reputation: 759

Javascript functions within self-executed block not accesible. Why?

I have a simple index.html file with some dragable images. My JS file looks like this:

    function drop(ev){
      ev.preventDefault();
      var data = ev.dataTransfer.getData('text');
      ev.target.appendChild(document.getElementById(data));
    }

    function drag(ev){
      ev.dataTransfer.setData('text',ev.target.id);
    }

That works perfectly fine. But, as I learned, it's good practice to write your code within a self-executed block.

So, I moved my two functions:

    (function(){

      function drop(ev){
        ev.preventDefault();
        var data = ev.dataTransfer.getData('text');
        ev.target.appendChild(document.getElementById(data));
      }

      function drag(ev){
        ev.dataTransfer.setData('text',ev.target.id);
      }

    })();

And now, when dragging the images around, the functions appear to be 'undefined'. They're probably newbie questions but:

Upvotes: 0

Views: 42

Answers (3)

brk
brk

Reputation: 50326

The inner function wont be executed. Here comes the beauty of closure make js objects private & public . This code may serve your purpose

var demoFunction =(function(){
    function _drop(ev){
        alert("Helo");
          _drag();
      }
    function _drag(ev){
       alert("Hello1");
      }
    _drop();

   return{
         drop :_drop,
         drag:_drag    
    }
})();

You can also call this drop and drag from other functions by demoFunction.drop & so on.Hope this is helpful for you

jsfiddle

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1074989

The answer is scope. The variables and functions defined within a function are only accessible within that function. In your first example, you're defining them globally; in your second example, they're inside a function.

Can I keep my functions in the block scope and still use them on the HTML like <div id="div0" ondrop="drop(event)">...</div>?

To use functions from old-fashioned onxyz attribute handlers, they have to be globals. You can make your functions globals by assigning them to properties on the global object, which you can access as window on browsers:

(function() {

    function drop(ev) {
        ev.preventDefault();
        var data = ev.dataTransfer.getData('text');
        ev.target.appendChild(document.getElementById(data));
    }

    function drag(ev) {
        ev.dataTransfer.setData('text', ev.target.id);
    }

    window.drop = drop;
    window.drag = drag;

})();

...but ideally, it's better not to create globals; the global namespace is incredibly crowded, adding to it just asks for conflicts. Instead, use modern event handling (addEventListener, attachEvent) instead of onxyz attributes.

Upvotes: 1

Amadan
Amadan

Reputation: 198436

The whole point of enclosing stuff into IIFEs is to isolate them and not pollute the global environment with unnecessaries. For example,

var counter = (function() {
  var current = 0;
  function getCurrentAndIncrement() {
    return current++;
  };
  return getCurrentAndIncrement;
})();

counter()
// 0
counter()
// 1
current
// ReferenceError: current is not defined

We hide what should be private, and expose what should be public.

You hid everything - then the fact that it is inaccessible should not be a surprise.

Finally, <div id="div0" ondrop="drop(event)">...</div> is a bad practice. Binding event listeners from JavaScript is much better, if a bit more complicated. Do just this:

<div id="div0">...</div>

then in JavaScript,

var div0 = document.getElementById('div0');
div0.addEventListener('drop', myHandler);

and this can, indeed, be stuffed into an IIFE. Whatever you refer to from HTML (as in your drop function) needs to be in global scope, or the browser will not be able to find it.

Upvotes: 2

Related Questions