1

I'm trying to find a better way to write a piece of jQuery but I couldn't figure it out on my own.

$('.ajaxButton').click(function(event) {

    event.preventDefault();

    var button = $(this).data('button');
    var action = $(this).data('buttonaction');
    var target = $(this).data('buttontarget');

    // The following code needs a rewrite
    if (action === 'fadeIn') {
        $(target).fadeIn();
    } else if (action === 'slideDown') {
        $(target).slideDown();      
    } else if (action === 'fadeToggle') {
        $(target).fadeToggle();     
    } else if (action === 'slideToggle') {
        $(target).slideToggle();        
    } else {
        console.log('Action not found for ' + button + ' button.');
    }


});

In order to avoid having to write the same code over and over again, I wrote the above JS for buttons I create in my web application. The above code works with the following anchor:

<a href="#" 
    class="button ajaxButton" 
    data-button="showForm"
    data-buttonaction="slideToggle"
    data-buttontarget=".showForm" >...</a>

What I have been trying to figure out is if there is a better way to write the following piece of code:

if (action === 'fadeIn') {
    $(target).fadeIn();
} else if (action === 'slideDown') {
    $(target).slideDown();      
} else if (action === 'fadeToggle') {
    $(target).fadeToggle();     
} else if (action === 'slideToggle') {
    $(target).slideToggle();        
} else {
    console.log('Action not found for ' + button + ' button.');
}

I would like to avoid the use of if: else statements. My first instinct was to have some sort of array that contains all possible actions. From there, I conduct a simple if action is in array do....

var actionArray = new Array('fadeIn', 'slideDown'...);

if ($.inArray(action, actionArray)) {
    $(target).action();
}

But I have no idea how to create the function. Can I call functions based on array values? Or can I convert strings to functions? I think the closest I could find was to use the eval() function.

Is there a better way to do this? Or will I have to use if else statements?

Uzair Hayat
  • 518
  • 1
  • 8
  • 21
  • Possible duplicate of [jQuery call function from a string](https://stackoverflow.com/questions/3326078/jquery-call-function-from-a-string) – Okan Kocyigit May 07 '19 at 12:37
  • 1
    `if ( target[ action ] ) target[ action ]();` could work. But no idea how to convert it to jquery. The point is, as long as the action is the same spelling as the method name you are calling, you can use the action string to call the function in bracket notation instead of dot notation. Never use `eval()` unless you can exactly explain why you are using it. You could also use a switch() statement same way as inside reducers. PS: if you use an actual button instead of a hyperlink you do not have to `preventDefault()`. – Shilly May 07 '19 at 12:37
  • 2
    @Shilly, it is simply `$(target)[action]()` – Okan Kocyigit May 07 '19 at 12:43

3 Answers3

1

You can target a property within an object using bracket notation (obj['prop']) instead of dot notation (obj.prop). So you can do something like this:

const validActions = ['fadeIn', 'slideDown'];

function doSomethingWithTarget(target, something) {
  if (validActions.includes(something)) {
    target[something]();
  }
}

doSomethingWithTarget($('#element'), 'slideDown'); // $('#element').slideDown();

More info: Working with objects @MDN, Property accessors @MDN

Luuuud
  • 4,206
  • 2
  • 25
  • 34
  • Hi, Thank you this worked well for me. However, I wasn't able to find anything on the jQuery API website regarding the Bracket Notations or why I do not need the `.` to call the functions. I would love to learn a little more about this. – Uzair Hayat May 07 '19 at 12:50
  • 1
    @UzairHayat It doesn't necessarily have anything to do with jQuery, but rather with JS objects in general. A jQuery object is just a JS object with a bunch of methods/properties defined in it (like `fadeIn`, `slideDown` etc.). I've added links to MDN pages with extra info to the answer. – Luuuud May 07 '19 at 12:53
0

Here's my attempt :

$('.ajaxButton').click(event => {
  event.preventDefault();

  let $this = $(this),
    button = $this.data('button'),
    action = $this.data('buttonaction'),
    $target = $($this.data('buttontarget'));

  try {
    $target[action]();
  } catch (error) {
    console.log('Action not found for ' + button + ' button.');
  }
});

target.fadeIn can also be written target["fadeIn"]. If it is a function, you can then call it the same way : target.fadeIn() or target["fadeIn"](). Then the argument can be dynamic (variable) : target[action]()

Jeremy Thille
  • 26,047
  • 12
  • 43
  • 63
0

What you can do is check of the function excist for the target, and if so execute it.

$('.ajaxButton').click(function(event) {

  event.preventDefault();

  var button = $(this).data('button');
  var action = $(this).data('buttonaction');
  var target = $(this).data('buttontarget');

  //check if the function excist for target object
  if (typeof $(target)[action] === 'function') {
    //if so execute it.
    $(target)[action]();
  } else {
    console.log('function: ' + action + ' not found for target: ' + target);
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<a href="#" class="button ajaxButton" data-button="showForm" data-buttonaction="slideToggle" data-buttontarget=".showForm">testbutton</a>

<div class="showForm">test toggle div</div>
Mark Baijens
  • 13,028
  • 11
  • 47
  • 73