Beniamino_Baggins Beniamino_Baggins - 4 months ago 9
jQuery Question

javascript module with JQuery causing module functions to be undefined

I'm trying to make a module called

ScrollToAnchor
that has a function called
goToTarget
that I will be able to call like
ScrollToAnchor.goToTarget(target);


However it says that


ScrollToAnchor.goToTarget is not a function


I think
ScrollToAnchor
is of type jQuery how I have it because of the
$
. Here is the code:

var ScrollToAnchor = $(function() {
var headerHeight = 70;

$('a[href*="#"]:not([href="#"])').click(function() {
if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
if (goToTarget(this.hash))
return false;
}
});

/*$('input[data-target]').click(function() {
if (gotoTarget($(this).data("target")))
return false;
})*/

var goToTarget = function(targetName) {
var target = $(targetName);
target = target.length ? target : $('[name="' + targetName.slice(1) + '"]');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top - headerHeight
}, 1000);

return true;
}
return false;
}

return {
goToTarget: goToTarget
}
});


What am I doing wrong? If i remove the
$
from
var ScrollToAnchor = $(function () {
then the jQuery inside
ScrollToAnchor
doesn't work.

But if I leave the
$
there then it thinks
ScrollToAnchor
is type jQuery and
ScrollToAnchor.goToTarget
is not a function.

Answer

The $(function() {...}) is a short hand of $( document ).ready( handler ).

So the result of $(function() {...}) is a jQuery result set containing the document as element.

You are looking for event delegation:

$(document).on('click', 'a[href*="#"]:not([href="#"])', function() {
  if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
    if (goToTarget(this.hash))
      return false;
  }
});

This will ensure that the click event will be use for all a element no matter when they have been added to the DOM and allows your to make your goToTarget available in the global scope in an easy way. Your final code will then look this way:

var ScrollToAnchor = (function() {
  var headerHeight = 70;

  // event handler with delegation
  $(document).on('click', 'a[href*="#"]:not([href="#"])', function() {
    if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
      if (goToTarget(this.hash))
        return false;
    }
  });

  function goToTarget(targetName) {
    var target = $(targetName);
    target = target.length ? target : $('[name="' + targetName.slice(1) + '"]');
    if (target.length) {
      $('html,body').animate({
        scrollTop: target.offset().top - headerHeight
      }, 1000);

      return true;
    }

    return false;
  }

  return {
    goToTarget: goToTarget
  }

}());

Using event delegation there is no need to wrap you whole code into a $(function() {...}) and your ScrollToAnchor is public available.

Comments