Modifying ajax js for ajax Asp .net mvc

Many novice C # ASP .NET MVC programmers (hereinafter referred to as mvc) are faced with the task of sending data using Ajax. That's just in practice, this task is not so easy.

In my work, I try to adhere to certain principles of software development. One of them is minimization of writing code and creating universal classes and functions. This principle assumed jquery.unobtrusive-ajax.js and the Ajax class for mvc .

In this article, we are directly interested in Ajax.BeginForm.

Example:

@using (Ajax.BeginForm("UploadAvatarImage", "Dashboard", null,
 new AjaxOptions {HttpMethod = "POST", 
OnSuccess = "UpdateAvatars()", 
OnFailure = "document.refresh()" }, 
new {Id = "UploadAvatartForm", enctype = "multipart/form-data" }))
{
<div class="input-group pt-1 pl-1">
 <input type="file" name="avatarFile"class="form-control" id="fileUploaderControl" accept=".jpg"/>
</div>
<button class="btn btn-sm btn-primary btn-block m-1" type="submit" >Изменить</button>
}

Faced with the fact that Ajax.BeginForm does not pass input [type = file], I conducted a global search to find a solution to this problem. The old favorite stackoverflow on each solution offered the same thing. Do not use Ajax.BeginForm, use FormData, make a php handler and more clouds of tips for increasing code.

As I said earlier, in my products I adhere to the principles and since the answer that would satisfy my requirements was not found, I had to do everything myself.

The first thing that was needed is to determine which function in jquery.unobtrusive-ajax.js is responsible for generating the data.

$(document).on("submit", "form[data-ajax=true]", function (evt) {
        var clickInfo = $(this).data(data_click) || [],
            clickTarget = $(this).data(data_target),
            isCancel = clickTarget && (clickTarget.hasClass("cancel") || clickTarget.attr('formnovalidate') !== undefined);
        evt.preventDefault();
        if (!isCancel && !validate(this)) {
            return;
        }
        asyncRequest(this, {
            url: this.action,
            type: this.method || "GET",
// То что нас интересует
            data: clickInfo.concat($(this).serializeArray())
        });
    });

We are interested in the function $ (this) .serializeArray () . In the $ (this) variable, our form <form /> comes in and then it is sold to an array. Having tested it in the console, as well as its analogue serialize (), it was determined that these functions do not load files in principle. Hence the decision to rewrite it.

But first you need to solve the problem with downloading the file, for this we use the FileReader class .

$(document).on("change", "form[data-ajax=true] input[type=file]", function (evt) {
        var form = $($(evt.target).parents("form")[0]);
        if (evt.target.files.length > 0) {
            var fileObj = evt.target.files[0];
            var reader = new FileReader();
            reader.onload = function () {
                evt.target.setAttribute("data-ajax-image-data", reader.result);
                form.find("button[type=submit]")[0].classList.remove("disabled");
            }
            reader.onerror = function () {
                console.log("Error while loading");
                form.find("button[type=submit]")[0].classList.remove("disabled");
            }
            form.find("button[type=submit]")[0].classList.add("disabled");
            reader.readAsDataURL(fileObj);
        }
    });

A little about the code.

First, we tie the event change input, the choice fell on «change».

Then we check if the file is selected.

If the file is selected then we start downloading it. The problem was that the data should be stored somewhere, in the example we will write the data in the attribute of the object itself.

Lock the confirmation button until the file is downloaded.

In case of errors, write it to the console. This is not the final version of the function, everyone can upgrade it to fit their needs.

Once we have created the file data download, go to the serialization upgrade.

functionselfFormSerializeArray(form) {
        var array = form.serializeArray();
        for (var i = 0; i < form[0].length; i++) {
            if (form[0][i].type === "file") {
                var fileObj = form[0][i];
                var data = fileObj.getAttribute("data-ajax-image-data") || "";
                if (data !== "") {
                    array.push({ name: fileObj.name, value: data });
                   // console.log("SUCCESS");
                } else {
                    //console.log("ERROR");
                }
            }
        }
        return array;
    }

And we use this function in the main function.

$(document).on("submit", "form[data-ajax=true]", function (evt) {
        var clickInfo = $(this).data(data_click) || [],
            clickTarget = $(this).data(data_target),
            isCancel = clickTarget && (clickTarget.hasClass("cancel") || clickTarget.attr('formnovalidate') !== undefined);
        evt.preventDefault();
        if (!isCancel && !validate(this)) {
            return;
        }
        asyncRequest(this, {
            url: this.action,
            type: this.method || "GET",
            data: clickInfo.concat(selfFormSerializeArray($(this))) // clickInfo.concat($(this).serializeArray())
        });
    });

Upon completion, a handler and a data parser are required. In haste, it looks like this.

Handler

public PartialViewResult UploadAvatarImage()
        {
            if (!ImageHelper.LoadAvatarImage(this.Request.Form["avatarFile"]))
            {
                returnnull;
            }
            return PartialView("Null");
        }

Helper

publicstaticboolLoadAvatarImage(string data)
        {
            try
            {
                var file = AjaxFile.Create(data);
                returntrue;
            }
            catch (Exception ex)
            {
                returnfalse;
            }

Parser

publicAjaxFile(string data)
        {
            var infos = data.Split(',');
            this.Type = infos[0].Split(';')[0].Split(':')[1].Split('/')[1];
            this.Source = Convert.FromBase64String(infos[1]); ;
        }
        publicstatic AjaxFile Create(string data)
        {
            returnnew AjaxFile(data);
        }

Congratulations! Now you can upload files using standard Ajax for mvc.

Also popular now: