Decoupling your CSS from your JavaScript, a “well no duh” moment

This weekend I had one of those “oh DUH” moments which I have been struggling with for quite some time. How can I better structure my jQuery selectors and make the code more maintainable? I came across this excellent article – Decoupling your HTML CSS and JavaScript and it all came into focus.

The problem

Using JavaScript selectors (dojo or jQuery) in XPages can be a problem because of the id naming scheme used by the JSP generator “id=”view:_id1:_id2:link5” and how this falls over in a selector. So an alternate to not having to mess with is attributes is to use class selectors $(‘.class’) which is actually much simpler and less troubling to get your head around.

When you are using class selectors for a DOM element which already has a class then awesome I don’t have to add any more classes. Using this bootstrap example there are multiple classes I can get a hold of to manipulate the dialog contents.

 <div class="modal fade myModal" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
			<button type="button" class="close modal-maxmin" aria-hidden="true">
				<i class="icon-external-link"> </i>
			</button>
			<button type="button" data-dismiss="modal" class="close" aria-hidden="true">
				<i class="icon-remove"> </i>
			</button>
          <h4 class="modal-title">modal-title</h4>
        </div>
        <div class="modal-body">
         modal-body : HERE GOES THE MESSAGE
        </div>
        <div class="modal-footer">
	        <div class="btn-group">
	          <button type="button" class="btn btn-default modal-cancel" data-dismiss="modal">CANCEL</button>
	          <button type="button" class="btn btn-primary modal-ok">OK</button>
	        </div>
        </div>
      </div><!-- /.modal-content -->
    </div><!-- /.modal-dialog -->
  </div><!-- /.modal -->

To add something to the body of the dialog I would do something like this

  $(".modal-body").html('Hi Marky')

The other problem

This example is very “coupled” code whereby my JavaScript selector is coupled to the real class file used by the HTML code. In reality what it means is that if I have to change the classname for some reason (hmm an example – oh I don’t know – going from Bootstrap2 to Bootstrap3 for example) then my JavaScript breaks down. While tightly coupled code is easy to follow, easy to create initially, it can be an absolute nightmare in the long run.

The epiphany moment

As I am reading Philip Walton’s article  I am struck by the “oh well no duh” moment when he talks about using js-* as a naming convention for classes which only exist for JavaScript selection.

  • My personal recommendation is to use a prefix for all JavaScript hooks. I use js-*. That way, when a developer sees such a class in the HTML source, she’ll know exactly where to look to discover its purpose.

Well no duh – brilliant idea!

In all senses this makes perfect sense:

  • The developer does not have to search through CSS files looking to see if you used the class as a selector as a real CSS marker
    • (well ok they changed something and the CSS broke, then they started to look for it)
  • It is immediately apparent from looking at the HTML that there is some dojo or jQuery selection/manipulation going to go on in this area because of the js-* class naming scheme
  • Within eclipse you can do a quick search and find out what is trying to manipulate this area before you go and ruin it

The new code

A very simple change to the modal-body but this then decouples my code form the bootstrap code – allowing me to make changes to the bootstrap classes int he future without breaking my JavaScript

 <div class="modal fade myModal" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
			<button type="button" class="close modal-maxmin" aria-hidden="true">
				<i class="icon-external-link"> </i>
			</button>
			<button type="button" data-dismiss="modal" class="close" aria-hidden="true">
				<i class="icon-remove"> </i>
			</button>
          <h4 class="modal-title">modal-title</h4>
        </div>
        <div class="modal-body js-modal-body"> <!-- js-modal-body change here -->
         modal-body : HERE GOES THE MESSAGE
        </div>
        <div class="modal-footer">
	        <div class="btn-group">
	          <button type="button" class="btn btn-default modal-cancel" data-dismiss="modal">CANCEL</button>
	          <button type="button" class="btn btn-primary modal-ok">OK</button>
	        </div>
        </div>
      </div><!-- /.modal-content -->
    </div><!-- /.modal-dialog -->
  </div><!-- /.modal -->

To add something to the body of the dialog I would now select the js-* class not the modal-body itself

  $(".js-modal-body").html('Hi Marky')

Comment

One of the things I love about my career is that it is an “always learning” experience for me. There are times like this where you think to yourself that is an awesome idea and you are very happy to learn it – and at the same time feel so stupid that you didn’t think of it yourself before🙂

10 thoughts on “Decoupling your CSS from your JavaScript, a “well no duh” moment

  1. Thanks for sharing that. I figured out another way to select xPage elements. Add a property to your element and then specify the property in the jQuery selector. For example:

    Then in your JS code:
    var selector = ‘button[isSubmitButton=”yes”]’;
    $(selector).{do something}
    or
    $(‘button[isSubmitButton=”yes”]’).{do something} should work as well.

    I’ve not tried a div e.g. $(‘div[isSubmitButton=”yes”]’).{do something} but it could work as well.

    • mmm, the first part of my example isn’t showing in my comment, perhaps it was removed because it was seen to be html. Will try again. The first part was (without enclosing symbols):
      xp:button value=”Submit” id=”button1″ styleClass=”btn”
      xp:this.attrs
      xp:attr name=”isSubmitButton” value=”yes” /xp:attr
      /xp:this.attrs
      /xp:button

    • Murray – thanks for commenting, I like where you are going with this, but….

      Some of the XPage controls also put out a name attribute as well as the is attribute which would make this a little confusing. If you add this to the data-* attribute concept that Mark Barton is talking about (comment further down) this definitely has potential.

      thanks again🙂

    • Interesting topic to debate Mark and I do not think there is a right answer. Needs beer for sure.

      On the one hand I agree and I use jQuery.data() a lot with attributes to store data especially in a repeat control where I want to pass additional field values to the surface in an easy to manage way.

      But on the other hand I don’t agree that using a class selector is a hack and adding styleClass to your XPages control is much easier than adding and then the data-whatever every time. Having to add “attributes” to XPage controls in the manner we have to is definitely on my list of annoyances with DDE.
      🙂

      • Haha your right needs beer.

        I guess if your using a CSS class name for something which isn’t CSS related…..

        I suppose the problem is in my mind I don’t think of these things from an XPages point of view – I am currently using AngularJS against a Domino REST API and I have to say its pretty damn powerful.

        Just Javascript, HTML, CSS and Webstorm IDE.

        I have a feeling I am preaching to the Choir😉

  2. Marky, this is awesome! It’s better than trying to use the id after using your x$, which I have used. I love how it is apparent what is happening when using inspect element/firebug. It is totally a “why didn’t I think of this sooner” moment. Thanks for sharing!

  3. When you are using class selectors for a DOM element which already has a class then awesome I don’t have to add any more classes. Using this bootstrap example there are multiple classes I can get a hold of to manipulate the dialog contents.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s