Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asp.net Core, How to post file and model to controller in JQuery/Ajax? [duplicate]

This question is not a repetition with this because all details are fully described in this question and will be very suitable for beginners

I have a view that inherits from a model. my field are in a form and I want to post form (or Model) to controller with JQuery/Ajax and insert it in database. I read this article and can upload image with ajax but i can not post whole form or model with data to controller.

my view :

@model ajax1.Models.Info

<form method="post" enctype="multipart/form-data">

<div class="form-group">
    <label asp-for="FirstName" class="col-lg-2 col-sm-2 control-label "></label>
    <div class="col-lg-6">
        <input asp-for="FirstName" class="form-control" />
        <span asp-validation-for="FirstName"></span>
    </div>
</div>

<div class="form-group">
    <label asp-for="LastName" class="col-lg-2 col-sm-2 control-label"></label>
    <div class="col-lg-6">
        <input asp-for="LastName" class="form-control" />
        <span asp-validation-for="LastName"></span>
    </div>
</div>

<input type="file" id="files" name="files" multiple />
<input type="button" id="upload"  value="Upload Selected Files" />
</form>

JQuery Code at the bottom of view:

@section Scripts{
<script>
        $("#upload").click(function (evt) {
            var fileupload = $("#files").get(0);
            var files = fileupload.files;
            var data = new formdata();
            for (var i = 0; i < files.length; i++) {
                data.append(files[i].name, files[i]);
            }
            $.ajax({
                type: "post",
                url: "/home/uploadfilesajax",
                contenttype: false,
                processdata: false,
                data: data,
                success: function (message) {
                    alert(message);
                },
                error: function () {
                    alert("there was error uploading files!");
                }
            });
        });

</script>

}

Controller :

    [HttpPost]
    public async Task<IActionResult> UploadFilesAjax(Info model)
    {
        var files = HttpContext.Request.Form.Files;
        foreach (var Image in files)
        {
            if (Image != null && Image.Length > 0)
            {
                var file = Image;
                var uploads = Path.Combine(_appEnvironment.WebRootPath, "img\\");
                if (file.Length > 0)
                {
                    var fileName = Guid.NewGuid().ToString().Replace("-", "") + Path.GetExtension(file.FileName);
                    using (var fileStream = new FileStream(Path.Combine(uploads, fileName), FileMode.Create))
                    {
                        await file.CopyToAsync(fileStream);
                        model.imgName = fileName;
                    }
                }
            }
        }

        using (var db = _iServiceProvider.GetRequiredService<ApplicationDbContext>())
        {

            db.Info.Add(model);
            db.SaveChanges();
        }
        string message = "success";
        return Json(message);
    }

Model :

public class Info
{
    [DisplayName("First Name")]
    [Required(ErrorMessage = "Enter First Name")]
    public string FirstName { get; set; }

    [DisplayName("Last Name")]
    [Required(ErrorMessage = "Enter Last Name")]
    public string LastName { get; set; }

    [DisplayName("select image")]
    public string imgName { get; set; }
}

When i put a breakpoint on the action and click on the submit button the application dose not go to action. How can i post all form or model to controller? I want if 'ModelStates.IsValid == false' the validation error shows.

like image 926
topcool Avatar asked Jan 30 '23 06:01

topcool


1 Answers

You have few issues in your client side code.

You are using incorrect case for contenttype,contenttype and formdata. Remember javascript is case sensitive.

Your current code is only adding the image to the FormData object. you can loop through your input elements and add that as well.

This should work.

$(function () {

    $("#upload").click(function (evt) {
        evt.preventDefault();

        var fileupload = $("#files").get(0);
        var files = fileupload.files;
        var data = new FormData();
        for (var i = 0; i < files.length; i++) {
            data.append(files[i].name, files[i]);
        }

        // You can update the jquery selector to use a css class if you want
        $("input[type='text'").each(function (x, y) {
            data.append($(y).attr("name"), $(y).val());
        });

        $.ajax({
            type: "post",
            url: "/home/uploadfilesajax",
            contentType: false,
            processData: false,
            data: data,
            success: function (message) {
                alert(message);
            },
            error: function () {
                alert("there was error uploading files!");
            }
        });
    });  
});

You can still use the model validation framework to check for the property level validation of your view model. Since you are making an ajax call, you need to send the validation errors in a JSON response back to the client where it can display it to the user.

[HttpPost]
public async Task<IActionResult> UploadFilesAjax(Info model, IEnumerable<IFormFile> files)
{
    if (ModelState.IsValid)
    {
        var uploads = Path.Combine(hostingEnvironment.WebRootPath, "images");
        foreach (var file in files)
        {
            if (file != null && file.Length > 0)
            {
                var fileName = Guid.NewGuid().ToString().Replace("-", "") +
                                Path.GetExtension(file.FileName);
                using (var s = new FileStream(Path.Combine(uploads, fileName),
                                                            FileMode.Create))
                {
                    await file.CopyToAsync(s);
                    model.imgName = fileName;
                }
            }
        }
        return Json(new { status = "success", message = "success" });
    }
    else
    {
        var list = new List<string>();
        foreach (var modelStateVal in ViewData.ModelState.Values)
        {
            list.AddRange(modelStateVal.Errors.Select(error => error.ErrorMessage));
        }
        return Json(new { status = "error", errors = list });
    }
}

Now in the client side code, read the status property of the response and if it is error, loop through the errors property and display it to the user. In the below sample, i am simply alerting the errors to the user, but you can change it to display it in some part of your page.

$(function () {

    $("#upload").click(function (evt) {
        evt.preventDefault();
        var fileupload = $("#files").get(0);
        var files = fileupload.files;
        var data = new FormData();
        for (var i = 0; i < files.length; i++) {
            data.append('files', files[i]);
        }

        // You can update the jquery selector to use a css class if you want
        $("input[type='text'").each(function (x, y) {
            data.append($(y).attr("name"), $(y).val());
        });

        $.ajax({
            type: "post",
            url: "/home/uploadfilesajax",
            contentType: false,
            processData: false,
            data: data
        }).done(function(res) {
            if (res.status === "success") {
                alert(res.message);
            } else {
                $.each(res.errors,function(a, b) {
                        alert(b);
                    });
            }
        }).fail(function(xhr, b, error) {
            alert(error);
        });
    });  
});
like image 58
Shyju Avatar answered Jan 31 '23 21:01

Shyju