jqueryjquery-dirtyforms

Jquery dirtyforms not working properly on DIV click and window.location.href


I have used jquery.dirtyforms with bootstrap modal to notify user that something is not saved in this page. This worked perfectly with anchor links but I have a div on the page which is actually working as a link to some other page. This div has data-action attribute containing the URL of the other page and on click I am setting the data-action value to window.location.href to navigate. When I click the div it gave the confirmation message on default popup of browser instead of Bootstrap Modal. I have given a unique class to the div named tabDiv. I tried to add the support for div in jquery.dirtyforms.js and written this which did not work:

<div class="sf-active div_Header tabDiv" id="div_Header" data-action="@Url.Action("ViewContract", "Contract", new { Id = Request.QueryString["Id"] })">
    <span>First</span>
    <i class="i_Header"></i>
    ClickMe
    <div class="ContraHeader glyphicon"></div>
</div>
$(".div_Header").click(function(evt) {  
    evt.stopImmediatePropagation();
    var url = $(this).attr('data-action');
    if (url !== undefined)
        window.location.href = url;
});

What I tried to change in Jquery.DirtyForms.Js which does not work

var events = {
    bind: function (window, document, data) {
        $(window).bind('beforeunload', data, events.onBeforeUnload);
        $(document)
            .on('click', 'a:not([target="_blank"])', data, events.onAnchorClick)
            .on('submit', 'form', data, events.onSubmit)
            .on('click', 'div.tabDiv', data, events.onDivCLick);
    }, onDivCLick: function(ev){
        bindFn(ev);
    },

I want it to work on div click also. Presently it is working but the message on browser's default popup. I want to show the same Bootstrap Modal on this click also.


Solution

  • Using window.location.href with Dirty Forms is a bit tricky. Fortunately, you can customize the event binding to take control in this case.

    Keep in mind, the navigation needs to happen in 2 different cases:

    1. When the form is not dirty.
    2. When the user clicks "proceed" on the dialog.

    So, it is best to use a common function in both of those cases. It also works out best if there is only 1 event handler to ensure there are no event ordering issues.

    For the first case, you just need to insert the code to check the dirty status into your event. You can create your event inside of the bind.dirtyforms event to gain access to the events object instance, then simply call events.onAnchorClick(ev) inside your event at the appropriate time.

    Dirty Forms will cancel the event if the form is dirty. So, you need to check whether the ev.isDefaultPrevented() returns false. If so, it is safe to fire your navigation.

    For the second case, you can take advantage of the fact that Dirty Forms hangs onto the event object until the dialog is closed. If you store the URL in the ev.data property, you can gain access to it later on in the process. Specifically, Dirty Forms calls the onRefireClick event handler when (and only when) the user clicks "proceed". So, you can then fire your custom navigation there using the URL you previously stored in the event.

    <!DOCTYPE html>
    <html>
    <head>
        <style type="text/css">
            input.dirty, input.dirty + label, select.dirty, textarea.dirty {
                background-color: red;
            }
        </style>
        <link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/bootstrap/3.0.0/css/bootstrap.min.css" />
        <script type="text/javascript" src="//cdn.jsdelivr.net/g/jquery@1.11.3,bootstrap@3.0.0,jquery.dirtyforms@2.0.0(jquery.dirtyforms.min.js+jquery.dirtyforms.dialogs.bootstrap.min.js)"></script>
    </head>
    <body>
        <form action="/" id="dialog-form-thing" method="post"> 
            <input id="text1" type="text"/>
    
            <div class="sf-active div_Header tabDiv" id="div_Header" data-action="http://www.google.com/">
                <span>First</span>
                <i class="i_Header"></i>
                ClickMe
                <div class="ContraHeader glyphicon"></div>
            </div>
        </form>
    
        <script>
            $(function() {
                function navigate(url) {
                    if (url !== undefined)
                        window.location.href = url;
                }
    
                /*   Event binding code - call before first .dirtyForms  */
                $(document).bind('bind.dirtyforms', function (ev, events) {
                    var originalBind = events.bind;
    
                    events.bind = function (window, document, data) {
                        // Attach the original Dirty Forms events
                        originalBind(ev);
    
                        // Attach a custom event
                        $(document).on('click', 'div.tabDiv', data, function (ev) {
                            // Store the URL in the event object for later use
                            var navUrl = $(this).attr('data-action');
                            ev.data = { url: navUrl };
    
                            // Execute the Dirty Forms logic to open the 
                            // dialog if the page has dirty form(s).
                            events.onAnchorClick(ev);
    
                            // If the page has no dirty forms, this
                            // will return false, causing navigation.
                            if (!ev.isDefaultPrevented())
                            {
                                navigate(navUrl);
                            }
                        });
                    };
    
                    var originalOnRefireClick = events.onRefireClick;
    
                    events.onRefireClick = function (ev) {
                        if (ev.data && ev.data.url)
                        {
                            // If we previously stored the URL, navigate to it.
                            navigate(ev.data.url);
                        }
                        else
                        {
                            originalOnRefireClick(ev);
                        }
                    };
                });
    
                $('form').dirtyForms();
    
            });
        </script>
    </body>