Событие удаления элемента управления Kendo Upload не имеет ответа

У меня есть элемент управления загрузкой кендо, подобный этому:

@(Html.Kendo().Upload()
    .Name("attachments")
    .Async(a => a
        .Save("UploadAsync", "Intel")
        .Remove("RemoveAsync", "Intel")
        .AutoUpload(true)
    )
    .Events(e => e
        .Success("onSuccessfulUpload")
        .Remove("onRemoveFile")
    )
    .Validation(v => v.AllowedExtensions(exts))
)

В контроллере его метод Save выглядит так:

public ActionResult UploadAsync(IEnumerable<HttpPostedFileBase> attachments)
{
    string filename;
    // ... do things ...
    return Json(new { ImageName = filename }, "text/plain");
}

где переменной filename присваивается значение.

Его метод Remove в контроллере выглядит очень похоже:

public ActionResult RemoveAsync(string[] fileNames)
{
    string filename;
    // ... do things ...
    return Json(new { ImageName = filename }, "text/plain");
}

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

Загрузка работает должным образом, и событие Success также работает должным образом. (Предупреждение просто для тестирования.)

function onSuccessfulUpload(e) {
    alert(e.response.ImageName);
}

Проблема возникает при удалении файла.

Когда я добираюсь до события Remove, e не имеет .response. Есть e.files и e.sender, но нет ответа.

function onRemoveFile(e) {
    alert(e.response);                    // undefined!
    alert(JSON.stringify(e.files));       // works, but does not have what I need
}

Как получить доступ к тому, что возвращает метод RemoveAsync?


person CarenRose    schedule 25.09.2017    source источник


Ответы (2)


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

Вы можете попытаться поместить имя результата в заголовки, и вы сможете прочитать результат:

// Controller
Response.AddHeader("ImageName", imageName); // before Json(...)

// View/JS
alert(e.headers['ImageName']);

Я не проверял это, и я вижу риск того, что событие remove на самом деле не читает асинхронный ответ, что объясняет, почему объект response недоступен.

В этом случае вы можете попробовать использовать следующий обходной путь: не вызывайте никакие URL-адреса при удалении (или используйте какое-либо действие без какого-либо тела, просто результат), а внутри обратного вызова события выполните RemoveAsync самостоятельно.

// View/JS
function onRemoveFile(e) {
    $.post('@Html.Url("RemoveAsync", "Intel")', e.files, function(response) {
        alert(response);
    });
}

Это некрасиво, но должно работать и давать нужные результаты.

person thmshd    schedule 25.09.2017
comment
Я посмотрел на порядок событий: js onUpload › Controller.UploadAsync() › js onSuccess… js onRemoveFile › Controller.RemoveAsync › js onSuccess Оба переходят к конкретному событию, прежде чем они перейдут к контроллеру, затем переходят к успеху мероприятие. Вот почему я мог получить ответ JSON после загрузки просто потому, что это происходило в этом событии Success. - person CarenRose; 25.09.2017

Покопавшись некоторое время, я нашел ответ.

Ключ лежал в порядке событий. Мое первое предположение заключалось в том, что событие Success было вызвано после успешной загрузки, а событие Remove было вызвано после успешного (?) удаления.

Фактический порядок событий таков:

js при загрузке > Controller.UploadAsync() > js при успешном выполнении

js onRemoveFile > Controller.RemoveAsync > js onSuccess

Я создал два параллельных массива в javascript для представления файлов, загруженных в e.files на стороне клиента, которые содержат uid для каждого файла, и имена файлов, созданные методом контроллера на стороне сервера (который переименовывает файлы).

var fileUids = [];
var fileSaveNames = [];

Я изменил функцию onSuccessfulUpload на эту, когда обнаружил, что существует e.operation, указывающая, какая операция была успешной:

function onSuccess(e) {
    if (e.operation == "upload") {
        var filename = e.response.ImageName;
        var uid = e.files[0].uid;

        fileUids.push(uid);
        fileSaveNames.push(filename)
        // ...
    }
    else if (e.operation == "remove") {
        var uid = e.files[0].uid;
        var saveIdx = fileUids.indexOf(uid);

        fileSaveNames.splice(saveIdx, 1);
        fileUids.splice(saveIdx, 1);
        // ...
    }
}

Затем я обновил функцию removeFile, которая, как я теперь знал, вызывалась до метода в контроллере.

function removeFile(e) {

    var uid = e.files[0].uid;
    var idx = fileUids.indexOf(uid);
    e.data = { fileToRemove: fileSaveNames[idx] };
}

Назначение e.data произошло из-за эта ветка со следующей информацией:

Решение: все, что нужно, это определить функцию для события загрузки и изменить полезную нагрузку «данные».

Добавьте функцию загрузки JS, чтобы добавить параметр «codeID» в моем случае.

$("#files").kendoUpload({
    [...]
    upload: function (e) {
        e.data = { codeID: $("#id").val() };
    }
});

Теперь на контроллере добавляем параметр и все.

[HttpPost]
public ActionResult Save(IEnumerable<HttpPostedFileBase> files, Guid codeID) { }

Вместо того, чтобы быть в событии Upload, мой находится в событии Remove.

Я выбрал имя параметра fileToRemove, и новый метод RemoveAsync в контроллере выглядит так:

public ActionResult RemoveAsync(string[] fileNames, string fileToRemove)
{
    string returnName = "";

    if (!string.IsNullOrWhiteSpace(fileToRemove))
    {
        // ... do things ...
    }

    return Json(new { ImageName = returnName }, "text/plain");
}
person CarenRose    schedule 25.09.2017