2

JSFIDDLE: http://jsfiddle.net/nqsfoqzz/10/

I'm having trouble figuring out what the this selector is in my code below. If I call the function removeAndClose(elem); as shown near the end of the click event (currently commented out), the value of $(this) is correct, which is .removeleg. But I need to control the removeAndClose() function based on a click event in a popup, which is the reason for $noticeMessage within the click event, as well as the reason for the function noticePopup(). I have removeAndClose(elem) added to the Confirm button, which is where the this problem comes up.

Since I'm using the removeAndClose() function within $noticeMessage, elem is undefined.

I've put together a jsfiddle that shows the problem: http://jsfiddle.net/nqsfoqzz/10/ To see the CONFIRM button, first click the 'ADD LEG' button. Then click 'Remove Leg' from the newly added element. You should then see the popup to confirm or cancel the removal.

Main Click Event:

    $('.missionlegswrapper').on('click', '.removeleg', function(e){
        e.preventDefault();

        var elem = $(this);

        // Notice Message
        $noticeMessage = 
                '<div>' + 
                    '<div>Are you sure you want to remove this leg? All the information you\'ve entered will be lost.</div>' + 
                    '<div>' + 
                        '<a href="javascript:void(0);" class="button confirm green" onClick="removeAndClose(elem);">Confirm</a>' + 
                        '<a href="javascript:void(0);" class="button cancel red" onClick="closePopup();">Cancel</a>' + 
                    '</div>' + 

                    '<div class="clear"></div>' + 
                '</div>';

        // Notice Popup
        noticePopup('error',$noticeMessage);

        //removeAndClose(elem);
    });

Additional Functions:

    /**
      * Notice Popup Function
      * messageType: The message to be entered into the popup
      * message: error, notice, warning (services as class name identifier)
      */
    function noticePopup(messagetype,message){

        // Append Backdrop to Body
        $('body').append('<div class="noticepopupbackdrop"></div>');

        // Append Popup to Body
        $('body').append(
            '<div class="noticepopup ' + messagetype + '">' + 
                '<div class="noticepopup_outer">' + 
                    '<div class="noticepopup_inner">' + 
                        '<div class="noticepopup_header">' + 
                            '<span>Attention</span>' + 
                            '<div class="noticeclosebttn"></div>' + 
                        '</div>' + 
                        '<div class="noticepopup_content">' + 
                            '<div class="noticepopupcontent_inner">' + 

                                message + 

                                '<div class="clear"></div>' + 
                            '</div>' + 

                            '<div class="clear"></div>' + 
                        '</div>' + 

                        '<div class="clear"></div>' + 
                    '</div>' + 

                    '<div class="clear"></div>' + 
                '</div>' + 

                '<div class="clear"></div>' + 
            '</div>'
        );

        // Initial Open
        $('div.noticepopupbackdrop').fadeIn(150);
        $('div.noticepopup').css({display: 'block'}).animate({top: '50%', opacity: '1.00'}, 300);

        // Grab Width and Height and Center Popup on Page Load
        popupWidthHeight();

        // On Resize
        $(window).on('resize', function(){

            // Grab Width and Height and Center Popup on Resize
            popupWidthHeight();
        });

        // On Click Close
        $('div.noticepopupbackdrop,div.noticeclosebttn').on('click', function(){
            closePopup();
        });
    }


    /**
      * Close Popup Function
      */
    function closePopup(){
        $('div.noticepopup').fadeOut(150);
        $('div.noticepopupbackdrop').fadeOut(175);

        setTimeout(function(){
            $('div.noticepopupbackdrop,div.noticepopup').remove();
        }, 350);
    }


    /**
      * Get Notice Popup Width and Height Function
      */
    function popupWidthHeight(){

        var noticeWidth = $('div.noticepopup').width();
        var noticeHeight = $('div.noticepopup').height();

        $('div.noticepopup').css({marginTop: -(noticeHeight / 2), marginLeft: -(noticeWidth / 2) });
    }


    /**
      * Close Popup Notice and Remove Mission Leg
      */
    function removeAndClose(thisObj){
        thisObj.closest('.missionlegitem').remove();

        console.log(thisObj);

        // Close Popup
        var popupCloseTime = setTimeout(function(){
            closePopup();
        },25);
    }
TygerKrash
  • 1,362
  • 2
  • 20
  • 38
Pegues
  • 1,693
  • 2
  • 21
  • 38
  • http://stackoverflow.com/questions/28101466/how-do-i-maintain-the-correct-scope-in-javascript-even-listeners/28101576#28101576 and http://stackoverflow.com/questions/31029318/difference-in-declaring-javascript-objects/31029689#31029689 – messerbill Oct 30 '15 at 13:42
  • I've read a lot of posts messerbill, and I've not found one that quite addresses my problem. – Pegues Oct 30 '15 at 13:46
  • 1
    You should make the popup part of your markup and control its visibility (and message content) by adding/removing classes, not creating it every time you need it. – dtanders Oct 30 '15 at 13:48
  • 1
    I would suggest binding the `onclick` function via jQuery. – Stryner Oct 30 '15 at 13:49

1 Answers1

1

The below code can be made a lot prettier and abstracted but in essence you could separate the HTML design from the functional behavior and something similar to the below.

I only separated the HTML from the functional code a little but feel free to go further than that to better re-usability.

Your Mission Leg Wrapper click event code could change to this:

// Data Entry Form Remove Leg
$('.missionlegswrapper').on('click', '.removeleg', function(e){
    e.preventDefault();

    var elem = $(this);

    // Notice Message
    // Removed in-line click events
    // Added identifiers through use of data-id to each link
    $noticeMessage = 
        '<div>' + 
        '<div>Are you sure you want to remove this leg? All the information you\'ve entered will be lost.</div>' + 
        '<div>' + 
        '<a data-id="notice-message-confirm" href="javascript:void(0);" class="button confirm green">Confirm</a>' + 
        '<a data-id="notice-message-cancel" href="javascript:void(0);" class="button cancel red">Cancel</a>' + 
        '</div>' + 

        '<div class="clear"></div>' + 
        '</div>';

    // Add click event handlers in JavaScript instead
    // Assigning the "this" context through the use of "bind"
    $(document).on('click', '[data-id="notice-message-confirm"]', removeAndClose.bind(this));
    $(document).on('click', '[data-id="notice-message-cancel"]', closePopup);

    // Notice Popup
    noticePopup('error',$noticeMessage);

    //removeAndClose(elem);
});

Your removeAndClose() method now is in context of the clicked link because of bind(this)

/**
  * Close Popup Notice and Remove Mission Leg
  */
function removeAndClose(){
    console.log(this);
    $(this).closest('.missionlegitem').remove();

    // Close Popup
    var popupCloseTime = setTimeout(function(){
        closePopup();
    },25);
}

See working example here


The code above is still "messy" and you could wrap each notification in it's own object and each manages it's own event handling, etc..

Nope
  • 22,147
  • 7
  • 47
  • 72
  • 1
    So simple. Beautiful solution. You just made me feel bad about myself for not having noticed to do this before. Thanks Francois! – Pegues Oct 30 '15 at 14:36