0

Disclaimer: I am sure that someone somewhere asked these question, but I couldn't think of the accurate google key words to locate similar questions. So please bear with me.

Question: I am constantly suffering from the necessity to re-write entire bulks of JQuery code because of the following pattern:

<div class = 'foo'></div>

<script>
    $('.foo').on('click', function(){
       // Do something
    });
</script>

The problem with this code is that it's too fragile. If I decide to rename my class to change the structure of the DOM, entire bulks of JS related to binding handlers to DOM elemenets are subject to editing.

What is the best-practice to make JQuery code less prone to such kind of risk or ideally eliminate it at all?

Crazy Frog
  • 495
  • 8
  • 17
  • 1
    IMO the key is to avoid global selectors as much as possible. `const $parent = $('.parent-class'); const $child = $parent.find('.child-class')` – john_omalley Jan 19 '17 at 20:33
  • @john_omalley, seems like you're telling something important that I can't understand. Can you clarify a bit ? – Crazy Frog Jan 19 '17 at 20:36
  • When you select an element in the DOM using the '$' function, you're searching through the whole DOM. Depending on how you've structured your code, sometimes that's your only option. But jquery allows you to limit your scope by parent element using .find(). This can be important for decoupling. It doesn't address the exact concern you mention above (hence the comment instead of an answer), but it helps make your code less error-prone. – john_omalley Jan 19 '17 at 20:42

4 Answers4

4

I find it easier to add a class to bind to based upon the event that is occurring instead of a class that is defining structure or component.

For example:

<button class="foo js-add-user">Add User</button>

<script>
  $('.js-add-user').on('click', function() {
    //..
  });
</script>

That way if you want to change .foo, you don't need to mess with the handler.

chazsolo
  • 7,873
  • 1
  • 20
  • 44
  • feeling much like accepting your asnwer. But can you comment on MarceloMita's asnwer? This is possibly a bit off-topic, but what's the advantage - if any - of using separately bound (in js file) event handler compared to using `onclick` ? – Crazy Frog Jan 19 '17 at 20:40
  • The answer to that is mostly subjective, but I find that the separation of concerns and abstracting your JavaScript from your HTML is a better (and widely accepted) practice - easier to read, think through, and debug. Namespacing your event-based classes with 'js-' makes it easy to find and know what is being listened to. – chazsolo Jan 19 '17 at 20:46
  • 1
    For a better answer on this subject you can [read this question here](http://stackoverflow.com/questions/5871640/why-is-using-onclick-in-html-a-bad-practice) – chazsolo Jan 19 '17 at 20:48
1

You could cache your elements and just reference the variables:

var foo = $('.foo');
foo.on('click', function(){
   // Do something
});

Then if you need to change the class name, you only need to change it in one place. This also has the added benefit of not having to re-query the DOM for your elements whenever you use them.

SimpleJ
  • 13,812
  • 13
  • 53
  • 93
  • Nice. One more question. First, what about the case of dynamic elements ? – Crazy Frog Jan 19 '17 at 20:29
  • 1
    In the case of dynamic elements, you could use a variable to store the class name and include it in your query string: `var fooClassname = '.foo'; var foo = $('.' + fooClassname)`; – SimpleJ Jan 19 '17 at 20:30
  • 1
    This approach has the drawback that if you change the logic of your DOM structure, then the variable string `fooClassname` can become obsolete in terms of its semantical meaning. Whereas @chazsolo approach doesn't have this downside. Agree ? – Crazy Frog Jan 19 '17 at 20:34
  • Isn't this similarly fragile? If the name `foo` that was just a class name is now also a variable name, and you change the class name, aren't you going to most likely need to change the variable name as well to match the new understanding / description? Otherwise you've got variable name `foo` (or `fooClassname`) which are now just tracking variables for `.liveReload`. The divergence seems anti-clarity and error-prone. – Jonathan Eunice Jan 19 '17 at 20:36
0

I don't know if it a good practice to do this way, but I usually use the following structure to call some function onclick:

<div onclick='myFunction();'></div>

<script>
  function myFunction() {
    alert('Hey!');
  }
</script>
  • MarceloMita, I am not sure, but AFAIK, `onclick` doesn't work for dynamic elements – Crazy Frog Jan 19 '17 at 20:41
  • I don't know if I understand what you mean by dynamic elements. But I've done a test that dinamically adds divs equal to the first one when clicking in any of these divs and it worked fine. Like it always adds a new div whatever div that I clicked. [jsfiddle snipet](https://jsfiddle.net/tf5moyha/10/) – MarceloMita Jan 19 '17 at 21:09
  • On [this example](https://jsfiddle.net/tf5moyha/21/) you see that you can pass the element as an arg of the function in order to modify the element as well – MarceloMita Jan 19 '17 at 21:18
0

You could create an alias function with your custom parameters, allowing it to store them for you later. You can also add function to set on id too, or to remove the click event.. things like this:

function setClickOnClass(className, func){
    var className = className;
    $(className).click(function(){
        func();
        //...
    });
}

then you make just one call, and you edit the class at that moment. If you want tou do it from multiple place and moments, you could create a "class"

function ClickOnClass(className, func){
    var className = className;

    this.setClick = function(optionalClassName){
        var classN = (optionalClassName) ? optionalClassName : className;
        $(classN).click(function(){
            func();
            //...
        });
    };

    return this;
}

//initialization
var clickHandler = new ClickOnClass('.foo', func);

//later in code
clickHandler.setClick();
Kaddath
  • 5,933
  • 1
  • 9
  • 23