Как использовать $ (this) внутри MVC3 Ajax.ActionLink OnBegin, OnComplete Events - PullRequest
10 голосов
/ 09 июля 2011

Мой контроллер создает список таких ссылок

<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.');
}

в строке функций 1 и 3 функции BeginUpdatePage выполняется нормально, но строка 2"$ (это) .parent () addClass ( 'выбрано');".явно ничего не делает ... (я объявил этот класс в моем css).

Я посмотрел на документы Jquery ( Jquery.ajax () ), там написано "this"это элемент, который был нажатЯ также проверил "jquery.unobtrusive-ajax.js", который был в моем проекте по умолчанию.Этот файл также пропускает «this» при выполнении моей функции.

"result = getFunction(element.getAttribute("data-ajax-begin"), ["xhr"]).apply(this,arguments);"

Что я здесь не так делаю ... Я видел других примеров , которые использовали эту технику, но я былвесь день терпит неудачу!

Как мне добраться до элемента, который был нажат, внутри моего Бегина, завершить функции.

Ответы [ 5 ]

10 голосов
/ 30 января 2013

ОБНОВЛЕНИЕ 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 для ссылки на элемент источника.

3 голосов
/ 09 июля 2011

Спасибо, ребята, за все ваши предложения, Дарин, хотя ваше решение работает отлично, я хотел попробовать и использовать встроенные утилиты Ajax.

Я нашел обходной путь после просмотра Jquery.Ajax () Docs , а также проверка «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" ...

который создает, но в контексте "это" - это 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, эй, вы, вероятно, имеете лучший контроль над всем этим,

, но я верю, что встроенный материал должен работать тоже.без необходимости возиться с этим.Поэтому я надеюсь, что либо кто-то может доказать, что я неправ, и на самом деле есть лучший способ сделать это, либо ребята, которые соединили этот сценарий, могли бы его изменить.

разве у них есть веская причина для этого?объяснения приветствуются: -)

Еще раз спасибо всем, у кого были хорошие предложения по этому вопросу. Я надеюсь, что это поможет людям в будущем.

3 голосов
/ 09 июля 2011

Вы можете попробовать передать его так:

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;
    });
});
0 голосов
/ 09 декабря 2011

У меня есть другое решение, которое использует 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');
}
0 голосов
/ 28 сентября 2011

Как насчет проверки event.srcElement?

...