Keeping it DRY with Function.call and jQuery toggle

Update: There is now a simpler example of the principles detailed here in the form of JQuery trigger and JS Function Call revisited.

In this case we have a text that will get toggled back and forth between a text area containing said text and the raw text itself. Each time we toggle back from text area to simply showing the text itself it gets saved to disc.

The thing is; we might have other instances of a text that needs to be edited in place and a lot of these instances might share a lot of common ground. We need to stop code repetition, and below is one way of doing it.

var me      = $(this).parent().find(".body-edit");
var txt_sel = "edit-body";
editSaveToggle(me, txt_sel,
  function(){
    var body = me.parent().find(".body");
    body.html( txtArea(txt_sel, body.html()) );
  },
  function(){
    plExec("ListItem", "updateAttr!", {id: getId( me.parent() ), attr: "body", value: $("#"+txt_sel).val()} );
  }
);

Above we have a DIV with the class of body-edit which is the button that will toggle editing in place of text contained in a sibling DIV with the class body. When the edit button is pressed the first time the text is replaced with a text area with the id edit-body which will contain the text itself, ready to be edited.

When the button is pressed again we save the text by way of Ajax. Note how we both pass txt_sel (id of text area) and me (jQuery DOM object of the button) to editSaveToggle and use them in the function arguments. The reason for that is that they need to be available to the function literals (editFunc and saveFunc) when they are defined, ie. in the function call. However they are also needed within editSaveToggle, hence we pass them along too.

function editSaveToggle(me, txt_sel, editFunc, saveFunc){
  me.toggle(
    function(){
      me.removeAttr("class").addClass("item-save");
      editFunc.call();
    },
    function(){
      me.removeAttr("class").addClass("body-edit");
      var txt  = $("#"+txt_sel);
      saveFunc.call();
      txt.parent().html( txt.val() );
    }
  );
}

So, currently not a lot of common code but that might change so it’s still a good thing to set this up right away.

1.) When the button is first pressed it will change its appearance and call the editFunc function. Which, as you can see above, takes care of transforming the text into a text area.

2.) When we’re done editing we press the new item-save button and the button will change back to its original state (we’re basically just switching background image at the moment). We execute saveFunc (nothing more than an Ajax call) and then change the text area back into plain text.

As you can see the unique code contained in editFunc and saveFunc will create the text area and handle the particulars of the Ajax call. If editing in place in our application always involved text areas then we could’ve put this logic inside editFunc instead but it might involve text fields too so we don’t. Sure we could’ve provided yet one more wrapping layer to keep that stuff DRY too, and that might very well happen in the future if the application gets more complex.


Related Posts

Tags: , ,