问题
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
回答1:
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?
回答2:
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.
来源:https://stackoverflow.com/questions/6135029/context-is-missing-when-using-unobtrusive-ajax-in-asp-net-mvc-3