0
\$\begingroup\$

On click on a div, a form replace this div. When the user clicks outside the form, the form is hidden and the div is re-show. For this, I implemented this process and I want your feedback, please.

function showForm(){
   hide the div 
   show the form, and set value of a form textarea
    textarea.focus();
}


function hideForm(id_form) {
    hide the form
    show the div
}


$(document).ready(function() {
    $("form[name=theform] :submit").mousedown(function() {
         myprocess with ajax (not important)
    });
});

$(document).ready(function() {
    $("form[name=theform] textarea").focusout(function(e){
        When a form textarea loses the focus, the form is hide with this function :  
        hideForm($(this).closest("form").attr('id'));
    });
}); 


// The process beginning
$(document).ready(function(){
    $('div[name=thediv]').click(showForm);
});

I have used the function blur() at the beginning, but it was difficult with the submit button, so I chose this process containing mousedown and focusout.

Can these 2 functions (mousedown and focusout) provoke problems? What do you think about this process?

\$\endgroup\$
  • \$\begingroup\$ It looks wrong to me that hideForm takes an ID as argument, but showForm does not.This says to me that showForm has the specific form selector hard-coded into it, whereas hideForm does not. I think these functions should be made consistent and either both should accept the selector argument or both should not. \$\endgroup\$ – 76484 Oct 19 '15 at 2:18
1
\$\begingroup\$

I would move all of the functionality into a single document ready handler. I will use the short-hand notation.

$(function () {
    /* All code goes in here. */
});

I will use less verbose selectors for creating my jQuery objects and I will cache them by assigning them to variables.

var $div = $('#TheDiv');
var $form = $('#TheForm');
var $window = $(window);

I think that hiding the form on the textarea's focusout event is a bad idea because this event could be triggered by the user tabbing out of the textarea. Hiding the form at this point would prevent the user from submitting the form.

I think a better approach is to take our direction directly from your requirements and hide the form when the user clicks outside of it. We can do this by attaching a click handler to the $window. In this handler we will call hideForm only if the clicked target was neither the form element nor an element within the form.

$window.on('click.TheForm', function (e) {
    if ($(e.target).is($form)) { return; }
    if ($.contains($form.get(0), e.target)) { return; }
    hideForm();
});

Notice above that the click event has been namespaced with '.TheForm'. Namespacing will allow us to easily remove the event handler without removing any other click events that may have been attached to the window. I will wrap the $window click handler code from above into a function so that we can re-attach this handler as we please. I will also create a function for removing the handler.

var attachWindowClick = function () {
    $window.on('click.TheForm', function (e) {
        if ($(e.target).is($form)) { return; }
        if ($.contains($form.get(0), e.target)) { return; }
        hideForm();
    });
};

var removeWindowClick = function () {
    $window.off('click.TheForm');  
};

If we want to hide the form when it is submitted, it will be better to listen for the submit event on the form rather than the mousedown event on the submit button, because the user can submit the form without the mouse, for example, by pressing Enter.

$form.on('submit', function (e) {
    /* Do AJAX stuff here. */
    hideForm();
    e.preventDefault();
});

In the showForm function, we will attach our window click listener so that we can capture clicks while the form is displayed. Note that we do not want our click of the #TheDiv to bubble-up and trigger our handler, so we will ensure our call to attachWindowClick is outside of the current call stack by using setTimeout with a delay of 0 milliseconds.

var showForm = function () {
    $form.show();
    $div.hide();
    $form.find('textarea').focus();
    setTimeout(attachWindowClick, 0);
};

The final code looks as follows:

$(function () {
    var $div = $('#TheDiv');
    var $form = $('#TheForm');
    var $window = $(window);

    var attachWindowClick = function () {
        $window.on('click.TheForm', function (e) {
            if ($(e.target).is($form)) { return; }
            if ($.contains($form.get(0), e.target)) { return; }
            hideForm();
        });
    };

    var removeWindowClick = function () {
        $window.off('click.TheForm');  
    };

    var hideForm = function () {
        $form.hide();
        $div.show();
        removeWindowClick();
    };

    var showForm = function () {
        $form.show();
        $div.hide();
        $form.find('textarea').focus();
        setTimeout(attachWindowClick, 0);
    };

    $form.on('submit', function (e) {
        console.log('do ajax');
        hideForm();
        e.preventDefault();
    });

    $div.on('click', showForm);
});
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.