0

I use dependency injection in PHP ( tagged b.c. used as a comparison ) as this seems to be best practice. PHP has more constructs for OO programming but it seems as doable to use DI in JavaScript as well to have de-coupled code.

In my instance it is a bit complicated b.c. my object contains object properties( function objects) that each have their own dependencies.

Here is the code in question that has 3 dependencies that I created inside the top level object but am considering injecting.

Where exactly would I inject them as they are used in different function objects with in the single object MC.MATweet?

The 3 objects are SText, SMessage, and SUniversals.

/**
 **  MATweet - Text, Universal, Message - Inject?
 */

MC.MATweet = { 
    init: function() {
        var tweet_button = document.getElementById( 'po_but' ),
            tweet_input = document.getElementById( 'po_in' );
        tweet_button.addEventListener( "click", function() {
            MC.Controller( MC.o_p( 'MATweet' ) ); 
        }, false ); 
        tweet_input.addEventListener( "keypress", function( event ) {
            if( event.keyCode === 13 ) {
                MC.Controller( MC.o_p( 'MATweet' ) );  
                event.preventDefault();
            }
        }, false );
        sStyle( [ "po_in","po_lab" ] );
    },
    pre : function( o_p ) {
        var form_elements = document.getElementById( 'fo_po' ).elements,
            text_object = new SText( form_elements ),
            universal_object = new SUniversals();
        if( universal_object.get('load') === '1' )
        {
            if( !text_object.checkEmpty() ) {
                return MC.MATweet.message( 'empty', o_p );
            }
            if( !text_object.checkPattern( 'tweet' ) ) {
                return MC.MATweet.message( 'tweet', o_p );
            }
        }
        o_p.args.hash = localStorage.hash;
        o_p.page = text_object.getArray();
        return o_p;
    },
    post : function( o_p ) {
       if( o_p.server.result === 'true' ) {
            MC.C.resetView( 'po_in' ); 
            vTPane( o_p.server.tweets ); 
        }
    },
    message: function( type, o_p )
    {
        var response_element = document.getElementById( 'i_box_rr' ),
            pane_element = document.getElementById( 'i_box_r_post' ),
            message_object = new SMessage( response_element ),
            cover_element = document.getElementById( 'po_but_cov' );

        o_p.result = 'complete';
        message_object.display( type );
        cover_element.style.display = 'inline';
        MC.MATweet.movePane( pane_element, 30, 'down' );
        return o_p;
    },
    movePane: function( pane_element, pos, dir ) {
        if( ( dir === 'down' ) && ( pos < 70 ) ) {
            pos += 1;
            pane_element.style.top = ( pos ) + 'px';
            setTimeout( function( ){ MC.MATweet.movePane( pane_element, pos, dir ); }, 1 );
        }
        else if( ( dir === 'down' ) && pos === 70 ) { 
            dir = 'up';
            setTimeout( function( ){ MC.MATweet.movePane( pane_element, pos, dir ); }, 2000 );
        }
        else if( ( dir === 'up' ) && ( pos > 30 ) ) {
            pos -= 1;
            pane_element.style.top = ( pos ) + 'px';
            setTimeout( function( ){ MC.MATweet.movePane( pane_element, pos, dir ); }, 1 );
        }
        else if( ( dir === 'up' ) && ( pos === 30 ) ) {
            document.getElementById( 'po_but_cov' ).style.display='none';
        }
    },
};

2 Answers2

2

You are correct, the example code is brittle and depends on many other parts of the system.

But this class won’t be simpler by adding dependency injection - it will only be harder to read and modify. The problem is not that it names the external features that it calls, but that it is calling so many external pieces of code in the first place.

Right now this code handles all the coding for, and interaction between, the user inputing tweets, tweets getting sent to the server, and tweets being displayed. It’s no wonder that it’s a hairball. Break these out into separate classes, each responsible for only one thing, and communicating by events not by calling each other.

So your tweet input view class becomes only responsible for emitting “new_tweet” messages containing a single string with the tweet text.

Your tweet display pane class listens for changes to the list of tweets and redraws itself.

Your controller code that creates the tweet input view, also attaches a listener for “new_tweet” events to it and then sends those new tweets off to get posted to the server.

In this way your code becomes minimally intertwined, leading to understanding, reusability, and beauty.

Daniel Von Fange
  • 857
  • 9
  • 10
1

We have found dependency injection, in the classical sense, to be useful in JavaScript. Here are some previous answers of mine on that topic, with some nice sample code in each:

Community
  • 1
  • 1
Domenic
  • 110,262
  • 41
  • 219
  • 271
  • No libraries involved really, even RequireJS was just in the context of a module system, you could write bare modules that way. – Domenic Aug 02 '12 at 18:36