【问题标题】:Context is Missing when using Unobtrusive ajax in asp.net mvc-3在 asp.net mvc-3 中使用 Unobtrusive ajax 时缺少上下文
【发布时间】:2011-09-02 08:44:16
【问题描述】:


我刚刚转移到 mvc-3 附带的不显眼的 ajax,但它在某一时刻出现了问题。 这是我的链接

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

这是我的 js 函数,将在成功时调用

<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>

我找到了this article,其中 imran 描述了如何解决问题。但它涉及向 jquery.unobtrusive-ajax.js 添加一行。它有任何副作用吗?我应该更改 jquery 文件吗?如果不是,我如何在不更改 jquery.unobtrusive-ajax.js 文件的情况下获取被点击的链接的 ID

【问题讨论】:

    标签: asp.net-mvc ajax asp.net-mvc-3 unobtrusive-javascript unobtrusive


    【解决方案1】:

    这是经过编辑的 MS 非侵入式 AJAX 的完整副本,包括一个新的缩小版本。它包含上下文(缺少源元素)修复以及另一个重要的修复,即在应用于提交项目时不遵守记录的“取消”类(应该阻止验证但不会)。

    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)
    

    我很失望,这些关键的正常行为修复在这么长时间内都没有得到纠正(尤其是因为只有三个简单的编辑)。甚至 2013 年 9 月最新发布的 AJAX 工具包仍在使用现在遗留的“Sys”Microsoft AJAX 库,而世界其他地方已经迁移到 jQuery UI。也许这一切都将通过 Visual Studio 2013 的 RTM 特别是 MVC 5 得到澄清?

    【讨论】:

    • 微软终于在 1 月 17 日发布了对其不显眼的 AJAX 库的更新,这似乎解决了这些问题(我现在正在测试)。如果它有效,那么最好删除任何自定义脚本并坚持使用 Microsoft 通过 NuGet 提供的自动更新。
    【解决方案2】:

    当您现在使用 jQuery 时,您需要将其包装在 $ 中以获取上下文。所以代码会是这样的

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

    您可以从 api 文档here 中找到更多信息。

    【讨论】:

    • Iancscoder: "this" 在这个上下文中不是 MVC3 中的一个元素。它是由 jquery 创建的一个 ajax 对象,没有对源元素的任何引用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-21
    • 2019-02-15
    • 2012-04-12
    • 1970-01-01
    • 2011-06-12
    • 1970-01-01
    • 2012-11-21
    相关资源
    最近更新 更多