2

I have to admit that I have always been a little confused on "proper" unobtrusive javascript. I get that you want to move the script out of your markup, and don't have the markup reference your script (other than the original script reference of course!) But I can't see how this works in practice.

I get how to make your markup not reference the code, but I feel dirty hard coding in DOM IDs in the script. Here is an example:

<script src="....awesome.js"></script>

<button id="primaryAction">Click me for something awesome!</button>
<labal id="resultText"></label>

//in awesome.js
awesome = function(){

    init = function(){
        //pretend we are doing something incredible here
        //and then we hook the button up

        $('#primaryAction').click(function(){
            $('#resultText').val(result());
        });    
    };

    result = function(){
        //here something awesome happens and we return the result
        return "Joe";
    };

    return {
        init: init
    }

}();

That should be something pretty representative of what could be, right? So my confusion comes in two places.

  1. Where should I call awesome.init() from?
  2. I feels wrong to reference the control IDs from javascript, but it also feels wrong to have classes specified in the script and require the markup to use them for it to work. How should it be done? Both feel obtrusive to me. Should the init() function take something like {button:'#primaryAction', result:'#resultText'} But then again it comes to #1..Where should Init be called from?

If I am doing this fundamentally wrong, please guide me to the path.

  • Where are all your variables declared? – elclanrs Aug 18 '12 at 06:28
  • 1
    Don't get so stressed about using element ids in your JS code, there's nothing wrong with that _up to a point_. Regarding where to call `awesome.init()`, since it references a DOM element you'd need to call it _after_ the element has been parsed, so either call it from a document ready handler or from a script block that appears after the element - it's standard practice (well, one of several competing standard practices) to put your script block at the end of the body. – nnnnnn Aug 18 '12 at 06:30
  • @nnnnnn would I call awesome.init directly from the markup, or should that be put at the bottom on the script itself in a $(function(){awesome.init();}); –  Aug 18 '12 at 19:03
  • If it's in a script at the bottom you don't also need a document.ready, so just `awesome.init();` would do it. If you already have a document.ready handler somewhere else on the page you could add it there though, to keep all the onready stuff together. – nnnnnn Aug 19 '12 at 04:37
  • @nnnnnn you should concert all that to an answer –  Aug 19 '12 at 05:25

2 Answers2

0

Backbone Js is an MVC approach for this problem.

Warning: It may be overkill for your current example.

See also: what-is-backbone-js

Community
  • 1
  • 1
davidmontoyago
  • 1,834
  • 14
  • 18
0

JQuery

Placing id (or class) attributes on your elements and referencing those same elements in your script is indeed the correct JQuery way to do it, but there are ways to reduce the hardcoding, and you should use them.

You can get at the elements you want using jQuery traversal. This will dramatically reduce the number of ids you will need (ideally down to just one per unit of functionality) http://learn.jquery.com/using-jquery-core/traversing/

eg.

<form class="edit">
  <button>Hello</button>
  <label>Hi there</label>
</form>

$(function() {
  var $form = $('form.edit');
  var $button = $form.find('button');
  var $label = $form.find('label');
  // your code here
});

As for where to put your init function, if you place a call to init at the bottom of your HTML that should just work. Alternately, if you pass it to $ it will be run onDomReady, i.e. when the DOM is ready to render, like so:

$(function() {
  init();
  // anything else you need to do
});

or just:

$(init)

JQuery Plugin

A JQuery Plugin is a function which has been added to the jQuery prototype. You should be writing most of your functionality as generic jQuery plugins. Use traversal to eliminate hard-coded ids as much as possible from your plugins.

You then just wire them together in a tiny bit of app specific wiring code.

http://learn.jquery.com/plugins/basic-plugin-creation/

//plugin
(function($) {
  $.fn.editForm = function() {
    $form = this;
    var $button = $form.find('button');
    var $label = $form.find('label');
  }
})(jQuery)

// app code
$(function() {
  $('form.edit').editForm()
});

Framework solutions

You might also adopt a different approach and consider using a framework.

Angular is getting massive attention right now. Angular treats your HTML as code, and actually compiles it to produce the final page. You get extremely tight coupling between your code and template, it's a completely opposite way of thinking about it, but one with significant advantages.

superluminary
  • 47,086
  • 25
  • 151
  • 148