Search code examples
javascriptdombackbone.jsunobtrusive-javascript

Feedback on client-side unobstrusive JavaScript hack


I'm developing a SPA application where Backbone.js is the main piece of the architecture.

We also have some Twitter Bootstrap flavor among which we have Button groups[1]. So the html has these buttons acting as checkboxes or radios.

In order to transparently bind Backbone models to Backbone views containing these buttons over the use of Backbone.ModelBinder[2] I hacked out the following piece of code:

# Twitter Bootstrap compatibility
addButtonGroupModelBindingSupport = ->
    $(@el).one 'mousedown keydown', '.btn-group[data-toggle="buttons-radio"] button', ->
        $(@).closest('.btn-group').find('button').prop 'type', 'radio'

installTwitterBootstrapModelBindingSupport = ->
    backboneView = Backbone.View
    ButtonGroupModelBinderSupportView = Backbone.View.extend
        constructor: ->
            backboneView.apply @, arguments
            addButtonGroupModelBindingSupport.call @
            return

    Backbone.View = ButtonGroupModelBinderSupportView

installTwitterBootstrapModelBindingSupport()

This code is internal to the module that exports the ModelBinder so it's executed only once. I mixin the behavior I need in Backbone.View so the specious JavaScript is injected in an unobstrusive way.

So I'm telling those buttons that they are not buttons anymore. As far as I could tell Chrome Firefox and IE are ok with that.

Fooled, ModelBinder properly handles that buttons as checkboxes or radios and everything works as needed.

It would be great to hear from more experienced front-end developers if this hack seems too much tricky.

[1] http://twitter.github.com/bootstrap/components.html#buttonGroups

[2] https://github.com/theironcook/Backbone.ModelBinder


Solution

  • I can't say it's wrong that way if it works for you in all of your target browsers/platforms, but it is certainly unusual. I see a few downsides in this approach:

    • it's not standard html. Valid types for button are submit, reset and button. See specification here
    • since it's not common, it might be misleading for other developers in your team (assuming you're not working alone).
    • even if it works for this particular case, next time you need to use a different plugin/component you might not be so lucky to find a hack that works like this does.
    • it might not be an issue in your case, but selectors like $('input').something() won't find your hacked button

    AFAIK, the usual way of handling this kind of scenario (where you need the input element but want to have a prettier UI element in the view) is to have both elements synchronized in the page - the pretty styled div and the actual input (invisible). Here are some examples of that: Select2, Fancy Checkboxes and Radio Buttons. Since it's more common, this might be a better approach for your problem, even if it requires a little more js to be written.