Sacrificial Lambda

read 9 comments

Dynamically binding event handlers to content that has been ajaxed in with $.load without repeating yourself can be tricky. Lambda functions help you to not repeat yourself as much. jQuery uses lamdba functions everywhere, so if you're familiar with jQuery, you should be familiar with the syntax of lambda functions.

In this example, the ajaxed-in content contains the elements that trigger a $.load over themselves.

JavaScript:
  1. prepare_links = function() {  
  2.   var month = $('.calendar-info .month').html();  
  3.   var year = $('.calendar-info .year').html();    
  4.   $('.previous-month').click(function() {
  5.      $('#calendar').load(this.href, prepare_links);
  6.      return false;
  7.   });
  8.   $('.next-month').click(function() {
  9.      $('#calendar').load(this.href, prepare_links);
  10.      return false;
  11.   });
  12. };
  13. $(document).ready(function() {
  14.    prepare_links();
  15. });

Make sure you're not calling the function in the callback by accidentally using prepare_links():

JavaScript:
  1. $('.next-month').click(function() {
  2.    $('#calendar').load(this.href, prepare_links()); /* Don't do this */
  3.    return false;
  4. });

This would set the callback to whatever the return value of the function is, not to the function itself.

comment feed

9 comments

  1. Hey Dan,
    So, a "lambda function" is the same thing as an anonymous function, right?

  2. Thanks, I finally stumbled across this technique when I got sick of wrapping all the functions I wanted to run in $('document').ready() with function(){} wrappers. This way is much cleaner, it's nice to see that I'm on the right track with that.

    The recursion in prepare_links is also something new to me; I didn't realize that you could self-refer to a function definition in this way. Neat. Confusing, but neat.

    PS this blog is a great idea!

  3. You could take this one step further and make it as DRY (Do not Repeat Yourself) as possible:

    CODE:
    1. do_load = function() {
    2.    $('#calendar').load(this.href, prepare_links);
    3.    return false;
    4. }
    5. prepare_links = function() {
    6.   $('.previous-month, .next-month').click(do_load);
    7. }
    8. $(document).ready(function() {
    9.    prepare_links();
    10. });

    I hope that code is readable...

  4. Oops, it can be written even DRYer:

    do_load = function() {
    $(’#calendar’).load(this.href, prepare_links);
    return false;
    }
    prepare_links = function() {
    $(’.previous-month, .next-month’).click(do_load);
    }
    $(prepare_links);

    Heh.

  5. Marat

    You have forgoten next moment. To set the whole construction callback to null. Your example overflows browser buffer.

    prepare_links = function() {
    prepare_links = false; ///!forgoten

    So, what do you thing about it?

  6. Sientz
    
    prepare_links = function() {
    prepare_links = false; ///!forgotten
    
    

    Do I need to use that =false somewhere in my script? I have created a div_switch function that hides all my functions at the bottom, where would I insert the div_switch = false; if needed??

    
    $(document).ready(function(){
      //THIS HIDES ALL LISTED DIVS ON LOADING OF PAGE
      $('div.blackbook').hide();
      $('div.canvas').hide();
      $('div.pencil').hide();
      $('div.murals').hide();
      $('div.shows').hide();
      $('div.tattoos').hide();
      $('div.miscellaneous').hide();
      $('a#blackbook').click(function() {
        //HIDE DIVS
        hide_divs();
        //SHOW LISTED DIV
        $('.blackbook').show('fast');
        return false;
      });
      $('a#canvas').click(function() {
        //HIDE DIVS
        hide_divs();
        //SHOW LISTED DIV
        $('.canvas').show('fast');
        return false;
      });
      $('a#pencil').click(function() {
        //HIDE DIVS
        hide_divs();
        //SHOW LISTED DIV
        $('.pencil').show('fast');
        return false;
      });
      $('a#murals').click(function() {
        //HIDE DIVS
        hide_divs();
        //SHOW LISTED DIV
        $('.murals').show('fast');
        return false;
      });
      $('a#shows').click(function() {
        //HIDE DIVS
        hide_divs();
        //SHOW LISTED DIV
        $('.shows').show('fast');
        return false;
      });
      $('a#tattoos').click(function() {
        //HIDE DIVS
        hide_divs();
        //SHOW LISTED DIV
        $('.tattoos').show('fast');
        return false;
      });
      $('a#miscellaneous').click(function() {
        //HIDE DIVS
        hide_divs();
        //SHOW LISTED DIV
        $('.miscellaneous').show('fast');
        return false;
      });
    });
    //HIDES ANY VISIBLE DIVS
    hide_divs = function() {
        //HIDE ANY VISIBLE DIVS BEFORE CONTINUING
        if ($('div.main').is(':visible')) {
        $('div.main').hide('fast');
        }
        if ($('div.blackbook').is(':visible')) {
        $('div.blackbook').hide('fast');
        }
        if ($('div.canvas').is(':visible')) {
        $('div.canvas').hide('fast');
        }
        if ($('div.pencil').is(':visible')) {
        $('div.pencil').hide('fast');
        }
        if ($('div.murals').is(':visible')) {
        $('div.murals').hide('fast');
        }
        if ($('div.shows').is(':visible')) {
        $('div.shows').hide('fast');
        }
        if ($('div.tattoos').is(':visible')) {
        $('div.tattoos').hide('fast');
        }
        if ($('div.miscellaneous').is(':visible')) {
        $('div.miscellaneous').hide('fast');
        }
    }
    
    

    If there is an easier way to do this, please feel free to educate me, I am a rookie at this scripting stuff.

    • Jonas

      Sientz :
      You could set an id to a div wrapping the "containers" and simplify the hide_function and even integrate the hide and show_function by sending the object the you want to display in the funcion_calling.

      
      hide_show_divs = function(d) {
        //HIDE ANY VISIBLE DIVS BEFORE CONTINUING
        $("#all_contents div").each(function(){
          if ($(this).is(':visible')) {
            $(this).hide('fast');
          }
        }
        $(d).show('fast');
        return false;
      }
      

      I'm sure this can be optimized

    • Valerij Primachenko

      i assume all your navigation links can be selected at once via class or something
      than you can use this snippet

      
      $(function(){
        //THIS HIDES ALL LISTED DIVS ON LOADING OF PAGE
        function hide_divs() {
          $('div.blackbook,div.canvas,div.pencil,div.murals,div.shows,div.tattoos,div.miscellaneous').filter(':visible').hide();
        }();
        $('a.link').click(function() {
          hide_divs();
          //SHOW DIV WITH CLASS CORRESPONDING TO ID OF THE LINK
          $('div.'+$(this).attr('id')).show('fast');
          return false;
        });
      });
      

      Its quite unusual that the content divs has classes instead of ids, and links with class instead of hrefs - think of usability for clients without js support
      Its better to use

      
      <a href="main">Main&lt:/a>
      <a href="blackbook">blackbook&lt:/a>
      ...
      <div id="main">....</div>
      <div id="blackbook">....</div>
      

      and

      $(function(){
        //THIS HIDES ALL LISTED DIVS ON LOADING OF PAGE
        function hide_divs() {
          $('#blackbook,#canvas,#pencil,#murals,#shows,#tattoos,#miscellaneous').filter(':visible').hide();
        }();
        $('a.link').click(function() {
          hide_divs();
          //SHOW LISTED DIV
          $('#'+$(this).attr('href')).show('fast');
          return false;
        });
      });
      

      cheers VP

      • Valerij Primachenko

        sad typo - forgot to use actual anchors

        
        <a href="#main">Main&lt:/a>
        <a href="#blackbook">blackbook&lt:/a>
        ...
        <div id="main">....</div>
        <div id="blackbook">....</div>
        

        and

        $(function(){
          function hide_divs() {
            $('#blackbook,#canvas,#pencil,#murals,#shows,#tattoos,#miscellaneous').filter(':visible').hide();
          }();
          $('a.link').click(function() {
            hide_divs();
            $($(this).attr('href')).show('fast');
            return false;
          });
        });
        

Sorry, but comments for this entry are now closed.