Как использовать $(this) внутри MVC3 Ajax.ActionLink OnBegin,OnComplete Events
Мой контроллер создает список ссылок, как это
<ul id="MainMenu">
@foreach (var item in Model.MenuItems)
{
<li>@Ajax.ActionLink(item.Caption,
item.ActionName,
item.ControllerName,
new AjaxOptions
{
UpdateTargetId = "pageBody",
OnBegin = "BeginUpdatePage",
OnComplete = "EndUpdatePage",
OnFailure = "FailUpdatePage"
})
</li>
}
</ul>
У меня есть такой javascript
function BeginUpdatePage() {
$("#MainMenu li").removeClass('selected');
$(this).parent().addClass('selected');
$("#pageBody").fadeTo('slow', 0.5);
}
function EndUpdatePage() {
$("#pageBody").fadeTo('slow', 1);
}
function FailUpdatePage() {
alert('There has been an error loading this page please try again.');
}
в функции BeginUpdatePage строки 1 и 3 выполняются нормально, а строка 2 "$(this).parent().addClass('selected');" явно ничего не делает... (я объявил этот класс в моем css).
Я посмотрел на документацию Jquery ( Jquery.ajax ()), где говорится, что "this" - это элемент, по которому щелкнули. Я также проверил "jquery.unobtrusive-ajax.js", который был в моем проекте по умолчанию. Этот файл также передает "this" при выполнении моей функции.
"result = getFunction(element.getAttribute("data-ajax-begin"), ["xhr"]).apply(this,arguments);"
Что я делаю не так здесь... Я видел другие примеры, которые использовали эту технику, но я терпел неудачу весь день!
Как я могу получить к элементу, на котором щелкнули, внутри моего Бегина, завершить функции.
5 ответов
Ребята, спасибо за все ваши предложения, хотя ваше решение работает отлично, я хотел попробовать использовать встроенные утилиты Ajax.
Я нашел обходной путь после просмотра документов Jquery.Ajax(), а также проверки "jquery.unobtrusive-ajax.js" - это скорее взлом, чем правильное использование, я не уверен, кто поставил "jquery.unobtrusive-ajax". JS "файл вместе, но если кто-нибудь знает, как по электронной почте им, возможно, отправьте им ссылку на эту страницу:-)
это интересная часть "jquery.unobtrusive-ajax.js" в этой функции "функция asyncRequest(element, options) "
$.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"])
});
Когда этот код вызывает метод apply на каждом шаге beforeSend, Complete, error, он передается в двух циклах: "this" и "arguments"...
Работает create, но в контексте "this" это XHR (XMLHttpRequest), а не элемент, по которому щелкнули... также, проверив заголовки функций, вы можете увидеть, что он передает объект XHR в качестве первой команды. Так зачем же нам быть контекстом вызова?
Мое решение... изменить файлы "jquery.unobtrusive-ajax.js" и "jquery.unobtrusive-ajax-min.js"...
вместо того, чтобы передавать "this" (XHR) в методе apply, давайте вместо этого отправим реальный элемент!
Итак, вся функция теперь выглядит так:
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(element, arguments);
if (result !== false) {
loading.show(duration);
}
return result;
},
complete: function () {
loading.hide(duration);
getFunction(element.getAttribute("data-ajax-complete"), ["xhr", "status"]).apply(element, 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(element, arguments);
},
error: getFunction(element.getAttribute("data-ajax-failure"), ["xhr", "status", "error"])
});
options.data.push({ name: "X-Requested-With", value: "XMLHttpRequest" });
method = options.type.toUpperCase();
if (!isMethodProxySafe(method)) {
options.type = "POST";
options.data.push({ name: "X-HTTP-Method-Override", value: method });
}
$.ajax(options);
}
Теперь, когда вы создаете свои функции для обработки этих событий, вы можете использовать "this" для получения фактического элемента.
пример:
function BeginUpdatePage(xhr) {
$("#MainMenu li").removeClass('selected');
$(this).parent().addClass('selected');
$("#pageBody").fadeTo('slow', 0.5);
}
function EndUpdatePage(xhr,status) {
$("#pageBody").fadeTo('slow', 1);
}
function FailUpdatePage(data,status,xhr) {
alert('There has been an error loading this page please try again.');
}
Теперь для некоторых людей было бы проще просто использовать решение Дарина, просто написать свой собственный Jquery для обработки события click, эй, вы, вероятно, имеете лучший контроль над всем этим,
но я верю, что встроенный материал должен работать тоже. без необходимости возиться с этим. Поэтому я надеюсь, что кто-то может доказать, что я неправ, и на самом деле есть лучший способ сделать это, или ребята, которые соединили этот сценарий, могли бы его изменить.
разве у них есть веская причина для этого? объяснения приветствуются:-)
Еще раз спасибо всем, у кого были хорошие предложения по этому вопросу, я надеюсь, что это поможет людям в будущем.
ОБНОВЛЕНИЕ 20 января 2014 г.: Официальная версия ненавязчивого сценария Ajax 3.1 содержит это изменение и была опубликована одновременно с выпуском MVC 5.1 (17 января). Пойдите, проверьте, проверьте это:-)
Оригинальный ответ
Я столкнулся с этим некоторое время назад, чтобы достичь результата, который вы ищете. ОЧЕНЬ просто сделать.
Вокруг строки # 100 файла jquery.unobtrusive-ajax.js добавьте эту строку кода.
options.data.push({ name: "X-Requested-With", value: "XMLHttpRequest" });
options.context = element; // <--- Add this line
method = options.type.toUpperCase();
if (!isMethodProxySafe(method)) {
options.type = "POST";
options.data.push({ name: "X-HTTP-Method-Override", value: method });
}
Вот и все, вы должны быть в состоянии использовать this
ссылаться на исходный элемент сейчас.
Вы можете попробовать передать это так:
OnBegin = "function() { BeginUpdatePage(this); }"
а потом:
function BeginUpdatePage(element) {
$("#MainMenu li").removeClass('selected');
$(element).parent().addClass('selected');
$("#pageBody").fadeTo('slow', 0.5);
}
или просто использовать JQuery без каких-либо Ajax.*
материал:
<ul id="MainMenu">
@foreach (var item in Model.MenuItems)
{
<li>
@Html.ActionLink(
item.Caption,
item.ActionName,
item.ControllerName,
null,
new { @class = "someLink" }
)
</li>
}
</ul>
а потом:
$(function() {
$('.someLink').click(function() {
var link = $(this);
$.ajax({
url: this.href,
beforeSend: function() {
$("#MainMenu li").removeClass('selected');
$(link).parent().addClass('selected');
$("#pageBody").fadeTo('slow', 0.5);
},
complete: function() {
$("#pageBody").fadeTo('slow', 1);
},
success: function(result) {
$('#pageBody').html(result);
},
error: function() {
alert('There has been an error loading this page please try again.');
}
});
return false;
});
});
У меня есть другое решение, которое использует URL AJAX, чтобы выбрать исходную ссылку, по которой щелкнули. Это решение будет работать правильно только в том случае, если есть только один ActionLink с точным URL:
function BeginUpdatePage() {
// Get the URL that will be posted to
var targetUrl = this.url;
var sourceLink = null;
// loop through all action links applicable
$('#MainMenu a').each(function () {
var href = $(this).attr('href');
// the targetUrl contains the entire URL - including http://
// so we need to do an indexOf to see if the href is contained
// within the target URL
if (targetUrl.indexOf(href) > -1) {
sourceLink = $(this);
return false;
}
});
// we've now got the link that was clicked - do with it as you wish...
sourceLink.parent().addClass('selected');
}