2


i have just shifted to unobtrusive ajax that ships with mvc-3 but it is breaking at one point. Here is my link

<%:Ajax.ActionLink("Edit", "Home", "Edit", new{id = Model.SomeID}, new AjaxOptions{OnSuccess = "DoSomething"})%>

this is my js function that will be called on success

<script type="text/javascript">
function DoSomething(data)
{
    var clickedLinkID = this.id; // this line breaks it used to work with microsoft ajax
    //rest of code goes here
}
</script>

i found this article in which imran describes how to solve the problem. but it involves adding one line to jquery.unobtrusive-ajax.js. Does it have any side effects? should i be changing jquery files? if not how can i get id of the link that was clicked without changing jquery.unobtrusive-ajax.js file

Muhammad Adeel Zahid
  • 17,474
  • 14
  • 90
  • 155

2 Answers2

0

Here is a complete copy of edited MS unobtrusive AJAX including a newly minified version. It contains the context (source element missing) fix plus another important fix whereby the documented "cancel" class was not honoured when applied to submit items (should prevent validation but doesn't).

jquery.unobtrusive-ajax

    /*!
    ** Unobtrusive Ajax support library for jQuery
    ** Copyright (C) Microsoft Corporation. All rights reserved.
    ** Fixed version (see full comments for details)
    */

    /*
        Fix for "validation ignores cancel class" applied from
        http://stackoverflow.com/questions/11561496/jquery-unobtrusive-validation-ignores-cancel-class-on-submit-button-if-used-in 

        Line 144 changed to:
            // Fixed to pass class name (needed for other fixes and useful anyway)
            $(form).data(data_click, name ? [{ name: name, value: evt.target.value, className: evt.target.className }] : []);

        Line 154 changed to:
            // Fixed for "cancel" class not honoured (so correct documented behavior of non-validating/cancel buttons are restored)
            if (clickInfo.length > 0 && clickInfo[0].className.indexOf('cancel') < 0 && !validate(this)) {

    */

    /*
        Fix for "source element missing on post-back event handler" applied from
        http://forums.asp.net/t/1663285.aspx?How+to+get+source+Element+when+using+Unobtrusive+Ajax+in+ASP+NET+MVC+3

        Line 101 inserted:
            // Fixed to pass source element in context (so source element can be discovered in handlers)
            options.context = element;

    */

    /*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
    /*global window: false, jQuery: false */

    (function ($) {
        var data_click = "unobtrusiveAjaxClick",
            data_validation = "unobtrusiveValidation";

        function getFunction(code, argNames) {
            var fn = window, parts = (code || "").split(".");
            while (fn && parts.length) {
                fn = fn[parts.shift()];
            }
            if (typeof (fn) === "function") {
                return fn;
            }
            argNames.push(code);
            return Function.constructor.apply(null, argNames);
        }

        function isMethodProxySafe(method) {
            return method === "GET" || method === "POST";
        }

        function asyncOnBeforeSend(xhr, method) {
            if (!isMethodProxySafe(method)) {
                xhr.setRequestHeader("X-HTTP-Method-Override", method);
            }
        }

        function asyncOnSuccess(element, data, contentType) {
            var mode;

            if (contentType.indexOf("application/x-javascript") !== -1) {  // jQuery already executes JavaScript for us
                return;
            }

            mode = (element.getAttribute("data-ajax-mode") || "").toUpperCase();
            $(element.getAttribute("data-ajax-update")).each(function (i, update) {
                var top;

                switch (mode) {
                case "BEFORE":
                    top = update.firstChild;
                    $("<div />").html(data).contents().each(function () {
                        update.insertBefore(this, top);
                    });
                    break;
                case "AFTER":
                    $("<div />").html(data).contents().each(function () {
                        update.appendChild(this);
                    });
                    break;
                default:
                    $(update).html(data);
                    break;
                }
            });
        }

        function asyncRequest(element, options) {
            var confirm, loading, method, duration;

            confirm = element.getAttribute("data-ajax-confirm");
            if (confirm && !window.confirm(confirm)) {
                return;
            }

            loading = $(element.getAttribute("data-ajax-loading"));
            duration = element.getAttribute("data-ajax-loading-duration") || 0;

            $.extend(options, {
                type: element.getAttribute("data-ajax-method") || undefined,
                url: element.getAttribute("data-ajax-url") || undefined,
                beforeSend: function (xhr) {
                    var result;
                    asyncOnBeforeSend(xhr, method);
                    result = getFunction(element.getAttribute("data-ajax-begin"), ["xhr"]).apply(this, arguments);
                    if (result !== false) {
                        loading.show(duration);
                    }
                    return result;
                },
                complete: function () {
                    loading.hide(duration);
                    getFunction(element.getAttribute("data-ajax-complete"), ["xhr", "status"]).apply(this, arguments);
                },
                success: function (data, status, xhr) {
                    asyncOnSuccess(element, data, xhr.getResponseHeader("Content-Type") || "text/html");
                    getFunction(element.getAttribute("data-ajax-success"), ["data", "status", "xhr"]).apply(this, arguments);
                },
                error: getFunction(element.getAttribute("data-ajax-failure"), ["xhr", "status", "error"])
            });

            options.data.push({ name: "X-Requested-With", value: "XMLHttpRequest" });

            // Fixed to pass source element in context (so source element can be discovered in handlers)
            options.context = element;

            method = options.type.toUpperCase();
            if (!isMethodProxySafe(method)) {
                options.type = "POST";
                options.data.push({ name: "X-HTTP-Method-Override", value: method });
            }

            $.ajax(options);
        }

        function validate(form) {
            var validationInfo = $(form).data(data_validation);
            return !validationInfo || !validationInfo.validate || validationInfo.validate();
        }

        $(document).on("click", "a[data-ajax=true]", function (evt) {
            evt.preventDefault();
            asyncRequest(this, {
                url: this.href,
                type: "GET",
                data: []
            });
        });

        $(document).on("click", "form[data-ajax=true] input[type=image]", function (evt) {
            var name = evt.target.name,
                $target = $(evt.target),
                form = $target.parents("form")[0],
                offset = $target.offset();

            $(form).data(data_click, [
                { name: name + ".x", value: Math.round(evt.pageX - offset.left) },
                { name: name + ".y", value: Math.round(evt.pageY - offset.top) }
            ]);

            setTimeout(function () {
                $(form).removeData(data_click);
            }, 0);
        });

        $(document).on("click", "form[data-ajax=true] :submit", function (evt) {
            var name = evt.target.name,
                form = $(evt.target).parents("form")[0];

            // Fixed to pass class name (needed for other fixes and useful anyway)
            $(form).data(data_click, name ? [{ name: name, value: evt.target.value, className: evt.target.className }] : []);

            setTimeout(function () {
                $(form).removeData(data_click);
            }, 0);
        });

        $(document).on("submit", "form[data-ajax=true]", function (evt) {
            var clickInfo = $(this).data(data_click) || [];
            evt.preventDefault();
            // Fixed for "cancel" class not honoured (so correct documented behavior of non-validating/cancel buttons are restored)
            if (clickInfo.length > 0 && clickInfo[0].className.indexOf('cancel') < 0 && !validate(this)) {
                return;
            }
            asyncRequest(this, {
                url: this.action,
                type: this.method || "GET",
                data: clickInfo.concat($(this).serializeArray())
            });
        });
    }(jQuery));

jquery.unobtrusive-ajax-fixed.min.js

    /*
    ** Unobtrusive Ajax support library for jQuery
    ** Copyright (C) Microsoft Corporation. All rights reserved.
    ** Fixed version (see full comments for details)
    */
    (function(a){var b="unobtrusiveAjaxClick",g="unobtrusiveValidation";function c(d,b){var a=window,c=(d||"").split(".");while(a&&c.length)a=a[c.shift()];if(typeof a==="function")return a;b.push(d);return Function.constructor.apply(null,b)}function d(a){return a==="GET"||a==="POST"}function f(b,a){!d(a)&&b.setRequestHeader("X-HTTP-Method-Override",a)}function h(c,b,e){var d;if(e.indexOf("application/x-javascript")!==-1)return;d=(c.getAttribute("data-ajax-mode")||"").toUpperCase();a(c.getAttribute("data-ajax-update")).each(function(f,c){var e;switch(d){case"BEFORE":e=c.firstChild;a("<div />").html(b).contents().each(function(){c.insertBefore(this,e)});break;case"AFTER":a("<div />").html(b).contents().each(function(){c.appendChild(this)});break;default:a(c).html(b)}})}function e(b,e){var j,k,g,i;j=b.getAttribute("data-ajax-confirm");if(j&&!window.confirm(j))return;k=a(b.getAttribute("data-ajax-loading"));i=b.getAttribute("data-ajax-loading-duration")||0;a.extend(e,{type:b.getAttribute("data-ajax-method")||undefined,url:b.getAttribute("data-ajax-url")||undefined,beforeSend:function(d){var a;f(d,g);a=c(b.getAttribute("data-ajax-begin"),["xhr"]).apply(this,arguments);a!==false&&k.show(i);return a},complete:function(){k.hide(i);c(b.getAttribute("data-ajax-complete"),["xhr","status"]).apply(this,arguments)},success:function(a,e,d){h(b,a,d.getResponseHeader("Content-Type")||"text/html");c(b.getAttribute("data-ajax-success"),["data","status","xhr"]).apply(this,arguments)},error:c(b.getAttribute("data-ajax-failure"),["xhr","status","error"])});e.data.push({name:"X-Requested-With",value:"XMLHttpRequest"});e.context=b;g=e.type.toUpperCase();if(!d(g)){e.type="POST";e.data.push({name:"X-HTTP-Method-Override",value:g})}a.ajax(e)}function i(c){var b=a(c).data(g);return!b||!b.validate||b.validate()}a(document).on("click","a[data-ajax=true]",function(a){a.preventDefault();e(this,{url:this.href,type:"GET",data:[]})});a(document).on("click","form[data-ajax=true] input[type=image]",function(c){var g=c.target.name,d=a(c.target),f=d.parents("form")[0],e=d.offset();a(f).data(b,[{name:g+".x",value:Math.round(c.pageX-e.left)},{name:g+".y",value:Math.round(c.pageY-e.top)}]);setTimeout(function(){a(f).removeData(b)},0)});a(document).on("click","form[data-ajax=true] :submit",function(c){var e=c.target.name,d=a(c.target).parents("form")[0];a(d).data(b,e?[{name:e,value:c.target.value,className:c.target.className}]:[]);setTimeout(function(){a(d).removeData(b)},0)});a(document).on("submit","form[data-ajax=true]",function(d){var c=a(this).data(b)||[];d.preventDefault();if(c.length>0&&c[0].className.indexOf("cancel")<0&&!i(this))return;e(this,{url:this.action,type:this.method||"GET",data:c.concat(a(this).serializeArray())})})})(jQuery)

I am disappointed that these critical normal behavioural fixes have not been corrected in such a long time (especially since there are just three simple edits). Even the latest September 2013 release of the AJAX toolkit is still using the now legacy "Sys" Microsoft AJAX Library whilst the rest of the world already migrated to jQuery UI. Maybe this will all be clarified with the RTM of Visual Studio 2013 specifically MVC 5?

Tony Wall
  • 1,382
  • 20
  • 18
  • Microsoft have finally released an update to their unobtrusive AJAX libraries on 17th January which appears to address the issues (I'm testing right now). If it works then it's best to remove any customized scripts and stick with the automatic updates from Microsoft via NuGet. – Tony Wall Jan 29 '14 at 11:35
-1

As you are now using jQuery you need to wrap it in the $ to get the context. So the code will be something like

$(this).addClass("someclass");

You can find more from the api docs here.

lancscoder
  • 8,658
  • 8
  • 48
  • 68
  • Iancscoder: "this" in this context isn't an element in MVC3. It's an ajax object created by jquery without any reference to the source element. – rossisdead Oct 11 '12 at 13:52