how to use the javascript module pattern in a real example?
Asked Answered
T

5

14

I am trying to understand the JavaScript Module Pattern. I've seen examples of what it should look like, but I don't understand how to use it.

For example, a few things are happening here:

$('input#share').on("click", function() {

    $('.loading').html('<img class="remove_loading" src="/graphics/loading.gif" />');

    var message = $(".wallmessage").val();

    if (message == ""){
        $("#messageempty").jmNotify();
        $('.remove_loading').remove();
    } else {
        addMessage(message);
    }

    return false;
});


function addMessage(message)
{
    $.ajax({
        url: '/test',
        type: 'POST',
        dataType: "json",
        data: {'message' : message},
        success: function(data) {
                ...
        },
        error: function() {
            ...
        }
    });
}

How can I use the above example with:

var myTest = function() {
    var selectId;
    function addMessage () {
        // ...
    }
    return { // public interface
        publicMethod1: function () {
            // all private members are accesible here
        }
    };
};
var start = myTest();

Where do I add the click event, declare my vars, add the addMessage function with the ajax call. and call the addMessage function? Do i have to wrap everything in $(document).ready(function()?

Can anyone shed some light on this for me?

Thanks

Tester answered 20/8, 2012 at 17:31 Comment(0)
P
23

This is quite an opinionated subject, but I'd do it (without entirely knowing your full app and what it does), somewhat like so:

var myApp = (function() {

  var someElement = $("#foo"); //some element I know I'll use lots

  var addMessage = function(message) {
    $.ajax({
      url: '/test',
      type: 'POST',
      dataType: "json",
      data: {'message' : message},
      success: function(data) {
              ...
      },
      error: function() {
          ...
      }
    });
  };

  var inputClick = function(event) {
    event.preventDefault();
    //depending on if you'll reuse these selectors throughout the app I might have these as variables
    $('.loading').html('<img class="remove_loading" src="/graphics/loading.gif" />');

    var message = $(".wallmessage").val();

    if (message == ""){
      $("#messageempty").jmNotify();
      $('.remove_loading').remove();
    } else {
      addMessage(message);
    }
  };

  var bindFunctions = function() {
    $("input#share").on("click", inputClick)
  };

  var init = function() {
    bindFunctions();
  };

  return {
    // EDIT: 27/12/16 - need to return init for 'usage' example to work
    init: init,
    addMessage: addMessage
    //anything else you want available
    //through myApp.function()
    //or expose variables here too
  };


})();

//usage

myApp.init();

Your original code for the pattern is wrong, the function has to have () at the very end, to make it a function that is immediately invoked, and then executes, exposing anything through the return statement.

You may wish to differ slightly from what I've done, it's only a basic idea but I hope it might get you started.

Someone a while back asked a question relating to this pattern and I answered it explaining why we use (function() {})(); and how the return statement works in that context, if you're slightly confused by it that might be worth reading too.

Painkiller answered 20/8, 2012 at 17:47 Comment(7)
what if i have more addMessage and inputClick methods, do i have to create more bindFunctions like methods and add them all in the main "class" and to the return?Tester
If you have more methods that occur on an event, I would bind them all within the bindFunctions method, similar to how I've done it with the one event method above. Please don't take this as gospel - if you'd rather use slightly different function names or lay it out slightly differently, go ahead :)Painkiller
in my case, i have a few click events and each one calls a ajax method, it's some king of a chat situation. But im wondering why i call myApp.init(); when i return addMessage, What if i have more returns, like addMessage: addMessage, addMessage1: addMessage1, etc, how do i make sure that each click calls the right method and returns the right return? :)Tester
or probably u meant myApp.addMessage();Tester
You don't have to return addMessage, that was just an example to show you how you can return methods. Just return what you might need to access externally.Painkiller
thanks, i think i understand it better now, ill jump on practicing.Tester
3 years late but just clarifying, in your example code, you can't actually use myApp.init(); since you have not returned the init() function, right? thanks for the explanation again.Concepcionconcept
B
13

The revealing module pattern is used like this:

var moduleName = (function () {
    var privateVariable = 'private';

    var privateMethod = function () {
        alert('this is private');
    };

    // this is the "revealed" part of the module
    return { 
        publicVariable: 'public',
        publicMethod: function () {
            alert('this is public');
        }
    };
}());

You can also define the public variables/methods as privates and then expose a reference to them, making them public. This is a matter of preference.

In your example, if you wanted addMessage to be part of the module, you would do it like this:

var moduleName = (function () {
    // this becomes public due to the reference exposure in the return below
    var addMessage = function () {
        // do whatever
    };

    // this is the "revealed" part of the module
    return { 
        addMessage: addMessage
    };
}());

moduleName.addMessage();
Blairblaire answered 20/8, 2012 at 17:42 Comment(2)
i was thinking why not create a method with the click event and another one with the ajax call, then another one that binds those 2 together then return that one... what do you think?Tester
@Tester yes, you can create them both as private methods and then the public method would call them both. it's good to have as little code as possible exposed as public.Blairblaire
W
2

Unlike JAVA, Javascript does not have the concept of private and public on properties or on methods. Let’s create an object called person which has 2 properties firstName and lastName, and also create 2 functions which will be getters for our properties. In Javascript we can create functions as properties of objects & those functions are accessible like any other property anywhere.

var person={
  "firstName":"Anoop",
  "lastName":"Rai",
  "getFirstName":function(){
    return this.firstName;
  },
  "getLastName":function(){
    return this.lastName;
  }
};
console.log(person.getFirstName());
console.log(person.firstName);

As expected above codes 11 prints Anoop and Anoop. Hmmm, that’s not good for object oriented programming. Well, we successfully implemented getters and so we should also have setters that should be of public scope and properties should be marked as private scope (what??? these private and public concept belongs to JAVA, C++ like languages). Our intentions are good, lets apply concepts specific to Javascript. We don’t want to do person.firstName, we want the prevent the access of the property directly. In languages like JAVA because of private and public we achieved the controlled acccess of properties, but in Javascript everything is public.

Javascript uses concept of closures to implement things like private & public. This pattern is called Module Pattern. That is, hiding variables from public access. In order to implement scopes, wrap your codes in a function (remember, scopes are implemented via functions in Javascript).

function createPerson(){
  var returnObj={
    "firstName":"Anoop",
    "lastName":"Rai",
    "getFirstName":function(){
      return this.firstName;
    },
    "getLastName":function(){
      return this.lastName;
    }
  };
  return returnObj;
}
var person=createPerson();
console.log(person.getFirstName());
console.log(person.firstName);

Now also above lines prints Anoop and Anoop. Still no success. As long as properties are tied to the object it will be accessed directly. Let’s untie it. Instead of properties we make variables of function scope (closure variables).

function createPerson(){
  var firstName="Anoop";
  var lastName="Rai";
  var returnObj={
    "getFirstName":function(){
      return firstName;
    },
    "getLastName":function(){
      return lastName;
    }
  };
  return returnObj;
}
var person=createPerson();
console.log(person.getFirstName());
console.log(person.firstName);

Now above lines prints Anoop and undefined. How does this happen? Because of closures, when the functions getFirstName and getLastName was created the functions had the whole scope chain or say pointers to the relevant variables i.e. firstName and lastName. The object returnObj does not remember the variabes but the function objects remembers, because of closures. Looks like we achieved what we wanted to, but one thing is left and that is setters for the controlled access of firstName and lastName. Let’s implement setters.

function createPerson(){
  var firstName="Anoop";
  var lastName="Rai";
  var returnObj={
    "getFirstName":function(){
      return firstName;
    },
    "getLastName":function(){
      return lastName;
    },
    "setFirstName":function(name){
      return firstName=name;
    },
    "setLastName":function(name){
      return lastName=name;
    }
  };
  return returnObj;
}
var person=createPerson();
console.log(person.getFirstName());
person.setFirstName("Kumar");
console.log(person.getFirstName());

We successfully modified firstName but in a controlled manner.

http://jkoder.com/the-module-pattern-javascript-way-of-hiding-data-in-objects-from-public-access/

Whity answered 1/9, 2016 at 11:35 Comment(0)
R
1

The idea is to cut down the visibility from outside world and better code management by dividing your code into segments/modules.Check this out if you want to see a really good usage of modular design pattern and some way of how we can get benefit from it.
http://learn.jquery.com/code-organization/concepts/

Retrograde answered 17/10, 2013 at 2:29 Comment(0)
D
0

I've got some experience with Mootools, but I'm a jQuery novice. I've read through the docs, and it looks like the smartest way to organize code is the Module Pattern, so I'm trying that out. However, one thing that seems to be missing from that style is any notion of "self", since each variable within the IIFE is a self-contained object (no pun intended).

So...maybe this defeats the whole purpose, but could you do something like this, and still have it be "valid" in all the ways that the module pattern style is valid?

var feature = ( function () {

    var self = {

        config: {
            option1: 'thing 1',
            option2: 'thing 2'
        },


        init: function (options) {

            // allow overriding the default config
            jQuery.extend( self.config, options );

            self.doSomething();

        },

        doSomething: function () {

        },

    };

    return {
        init: self.init
    }

})();

What I like about this is that I can internally reference all of the methods and properties using "self". I'm still able to expose the methods that I want using the "return" object, so (I guess) that's okay. But I'm such a novice, and this seems so simple and (at first glance) elegant, that I must be missing a major gotcha. It shares the coding style with the Object Literal format, which is what I'm familiar with from Mootools. So maybe I'm trying to fit a round peg into a square hole. Maybe the internal object literal isn't necessary, because rather than "self.doSomething()", I can just say "doSomething"? Is that the case?

Partially I like this because I can set the "context" argument of $.ajax to be "self", which seems like a win.

Diffract answered 8/8, 2013 at 20:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.