I use AJAX to send data inside a bootstrap modal to a controller in ASP.NET MVC. After its operation is completed inside this controller, a success or failure response is sent back to bootstrap modal using following code:
Controller:
[HttpPost]
public JsonResult Action([Bind(Include = "Id,firstName,lastName")] InqueryViewModel model)
{
JsonResult json = new JsonResult();
if (ModelState.IsValid)
{
Inquery inquery = new Inquery();
inquery.firstName = model.firstName;
inquery.lastName = model.lastName;
var result = SaveInqueries(inquery);
json.Data = new { Success = true };
}
else
{
json.Data = new { Success = false, Message = "Unable to perform an action on sending" };
}
return json;
}
As you notice above, code is dividing the logic into 2 types of responses, i.e., success or failure. Following code inside bootstrap model is used to handle this response:
JavaScript
<script>
$("#actionButton").click(function () {
$.ajax({
url: '#Url.Action("Action","Home")',
type: "post",
data: $("#actionForm").serialize()
})
.done(function (response) {
if (response.Success) {
//data is saved.
$(".alert-success").show();
$("#actionForm").hide();
}
else {
$(".errorDiv").html(response.Message);
}
});
});
</script>
Above code is working as expected if response is a success, but its not showing .errorDiv on a failure response. Instead, bootstrap modal is being disappeared. Following is bootstrap modal code:
HTML:
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Get Your Survey</h5>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="alert alert-success collapse">
<span>
Success
</span>
</div>
<form id="actionForm">
<div class="form-group">
#Html.TextBoxFor(m => m.firstName, new { placeholder = "First Name", #class = "form-control form-control-sm" })
</div>
<div class="form-group">
#Html.TextBoxFor(m => m.lastName, new { placeholder = "Last Name", #class = "form-control form-control-sm" })
</div>
<button id="actionButton" class="data-btn btn btn-outline-success" type="submit">
<i class='fa fa-paper-plane'></i>
Send
</button>
</form>
<div class="errorDiv">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
Can anyone see why this program is behaving like this?
Thank you.
Related
I want to create a reusable upload feature for images and have created a partialView for this. On click, the partial is loaded via ajax call and the user can browse for an image, the chosen image is displayed and on submit the file should be passed to the controller but the url for submission is always a 404.
Load the Bootstrap Modal
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="ajax-modal" data-target="#add-contact" data-url="#Url.Action("ShowModalUploadForm", new { Id= Model.Id })">
Add contact
</button>
var placeholderElement = $('#modal-placeholder');
$(document).on('click', 'button[data-toggle="ajax-modal"]', function (event) {
var url = $(this).data('url');
$.get(url).done(function (data) {
placeholderElement.html(data);
placeholderElement.find('.modal').modal('show');
});
});
This works...The issue is when I submit, the URL that is fored appears to not match what the controller is expecting
PartialView (omitted unnecessary portions)
<form id="UploadPhoto" asp-action="UploadPhoto" enctype="multipart/form-data" method="post">
<input name="VolunteerId" id="VolunteerId" type="hidden" value="#Model" />
<div class="col-md-12">
<div class="form-group">
<label>Upload Image</label>
<div class="input-group">
<span class="input-group-btn">
<span class="btn btn-default btn-file">
Browse… <input type="file" id="imgInp">
</span>
</span>
<input type="text" class="form-control" readonly>
</div>
<img id='img-upload' name='img-upload' />
</div>
</div>
</form>
$(document).on('click', '#btnSubmitUpload', function (event) {
event.preventDefault();
var form = $(this).parents('.modal').find('form');
var dataToSend = new FormData(form.get(0));
$.ajax({
url: '#Url.Action("UploadPhoto", "Volunteer", new { Area = "Admin" })',
method: 'post',
data: dataToSend,
processData: false,
contentType: false
}).done(function (data) {
//Do stuff here
}
});
});
$(document).on('change', '.btn-file :file', function () {
var input = $(this),
label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
input.trigger('fileselect', [label]);
});
$(document).on('fileselect', '.btn-file :file', function (event, label) {
var input = $(this).parents('.input-group').find(':text'),
log = label;
if (input.length) {
input.val(log);
} else {
if (log) alert(log);
}
});
$(document).on('change', '#imgInp', function () {
readURL(this);
});
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#img-upload').attr('src', e.target.result);
}
reader.readAsDataURL(input.files[0]);
}
}
VolunteerController
[HttpPost]
private async void UploadPhoto([FromForm] IFormFile file)
{
//await _storage.SaveBlobAsync("volunteers", file, BlobType.Image);
}
Open the F12 developer tools, where is your misalignment? Or we can also use the FormData object.
View:
#model ImageFileUpload.Models.Human
#{
ViewBag.Title = "SaveData";
}
<h2>SaveData</h2>
<div>
Create New
<br /><br />
<table class="table table-responsive">
<thead>
<tr style="background-color:#333;color:white;">
<th>Human Name</th>
<th>Human Image</th>
<th>Human Phone</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody id="SetHumanList">
<tr id="LoadingStatus"></tr>
</tbody>
</table>
</div>
#using (Html.BeginForm("SaveData", "Human", FormMethod.Post, new { id = "form", enctype = "multipart/form-data" }))
{
<div class="modal fade" id="MyModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
×
<h4 id="ModalTitle"></h4>
</div>
<div class="modal-body">
<fieldset id="SubmitForm">
#Html.HiddenFor(a => a.HumanId, new { #id = "HumId" })
<div class="form-group">
#Html.TextBoxFor(a => a.HumanName, new { #id = "HumName", #class = "form-control", #placeholder = "Name" })
</div>
<div class="form-group">
<input type="file" id="UploadFile" name="Upload" class="form-control w" />
</div>
<div class="form-group">
#Html.TextBoxFor(a => a.HumanPhone, new { #id = "HumPhone", #class = "form-control", #placeholder = "Phone" })
</div>
<div class="form-group">
<button id="SaveRecord" type="button" class="btn btn-warning">Create</button>
</div>
</fieldset>
</div>
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
<script src="~/Scripts/jquery.form.min.js"></script>
#Scripts.Render("~/bundles/jqueryval")
<script>
function AddNewHuman() {
$("#MyModal").modal("show")
}
$("#SaveRecord").click(function () {
var formData = new FormData();
formData.append("Upload", $('#UploadFile')[0].files[0]); //append the image file
var other_data = $('form').serializeArray();
$.each(other_data, function (key, input) { //append other input value
formData.append(input.name, input.value);
});
$.ajax({
type: "POST",
url: "/Human/SaveData",
data: formData,
contentType: false, // Not to set any content header
processData: false, // Not to process data
success: function (result) {
alert("Success");
window.location.href = "/Human/index";
//$("#MyModal").modal("hide"); //this line is unnecessary because the user has been redirect
}
})
});
</script>
}
Result
I have a multi step form that has multiple input with type of file.
in some step I call submit button and again I get back to same page without uploading any files because I dont want to upload these files in this step. for example user enters all information and select files that he wants and after that I go to controller and get back to page to show him confirmation page.
how can I fill input files with model properties? and again he submit the page that file property shouldnt be empty.
<input asp-for="CertImageFile" type="file" accept=".jpg, .jpeg, .png">
Model
public IFormFile CertImageFile { get; set; }
You can try to use ajax and partial view:
MyModelClass:
public class MyModelClass
{
public IFormFile CertImageFile { get; set; }
}
View:
#model MyModelClass
<div class="row">
<div class="col-md-6">
<div>
<input asp-for="CertImageFile" type="file" accept=".jpg, .jpeg, .png">
</div>
<button onclick="Confirm()">confirm</button>
</div>
<div id="modal"></div>
</div>
#section scripts{
<script type="text/javascript">
function Confirm() {
$.ajax({
url: "TestPartial",
type: "POST",
success: function (data) {
//put partial view to div
$("#modal").html(data);
$("#cartModal").modal('show');
}
});
}
function Submit() {
var pdata = new FormData();
var files = $("#CertImageFile").get(0).files;
pdata.append('CertImageFile', files[0]);
$.ajax({
url: "Submit",
type: "POST",
data: pdata,
processData: false,
contentType: false,
success: function (data) {
//you can do something or redirect to other page after post the data
}
});
}
</script>
}
Controller:
[HttpPost]
public IActionResult Save(MyModelClass myModelClass)
{
return Ok();
}
_Partial:
<div class="modal fade cart-modal" id="cartModal" tabindex="-1" role="dialog" aria-labelledby="ModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
Tip:
</div>
<div class="modal-body">
Do you want to submit the file?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal" onclick="Submit()">submit</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
Controller:
[HttpPost]
//pass IFormFile to action
public IActionResult Submit(MyModelClass myModelClass)
{
return Ok();
}
//view call action to pass partial view
public IActionResult TestPartial() {
return PartialView("_Partial");
}
result:
I have found a bug - and I haven't found any solution to this.
I have a code in ASP.NET Core (using VSPro 2019 16.5.0):
public IActionResult CreateSubGroup(MyClass model, string returnUrl = null)
{
if (ModelState.CreateMyClassValidation())
{
if (!db.MyClass.Where(x => x.Title == model.Title).Any())
{
ViewData["ReturnUrl"] = returnUrl;
var code = new MyClass { Title = model.Title, IdGroup = model.IdGroup, GroupCode = model.GroupCode};
db.MyClass.Add(code);
var result = db.SaveChanges();
if (result > 0)//if there was no issue (at least one row was changed)
{
this.AddNotification(MessagesHandler.Success, $"Item\"{model.Title}\" was successfully created.");
}
else
{
this.AddNotification(MessagesHandler.Error, $"Item \"{model.Title}\" cannot be created.");
}
}
else
{
this.AddNotification(MessagesHandler.Error, $"Item \"{model.Title}\" already exists.");
}
}
else
{
this.AddNotification(MessagesHandler.Error, $"ErrorMessage.");
}
return RedirectToLocal(returnUrl);
}
Creating of new Item always crashes with unique code exception from DB - During debuging I have found, that every row is executed twice (and I don't know why??) - so also the row db.SaveChanges() is executed twice and that's why I got this exception.
Second bad thing is, that not even the first attempt to save database is not executed (= new Item is not created in DB).
Have you seen this error?
EDIT:
I have found, that it happens only when data are posted from view with JS/AJAX (from modal window)
Here is the code for sending data:
<div class="modal fade" id="ModalWindow" tabindex="-1" role="dialog" aria-labelledby="ModalForm" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<form id="ModalForm" action="" method="post" class="validator">
<div class="modal-body">
<div class="form-group">
<label asp-for="Id"></label>
<input class="form-control" asp-for="Id" value="" readonly data-val="false">
<div class="form-text text-muted small">ID cannot be changed!</div>
</div>
<div class="form-group">
<label asp-for="Title"></label>
<input class="form-control mlfb-create" asp-for="Title" placeholder="Title" value="" autofocus tabindex="#(++tabindex)">
<span class="text-danger small" asp-validation-for="Title"></span>
</div>
<div class="form-group">
<label asp-for="IdGroup"></label>
<select class="selectpicker form-control" asp-for="IdGroup" data-live-search="true" data-style="btn-info" tabindex="#(++tabindex)">
#if (data?.GroupData != null)
{
#foreach (var item in data?.GroupData)
{
<option value="#(item.Id)">#item.Title</option>
}
}
</select>
</div>
<div class="form-group">
<label asp-for="GroupCode"></label>
<input class="form-control mlfb-create" asp-for="GroupCode" placeholder="Title" value="" autofocus tabindex="#(++tabindex)">
<span class="text-danger small" asp-validation-for="GroupCode"></span>
</div>
</div>
<div class="text-center modal-footer">
<button type="submit" class="btn btn-success _modal-buttton-save" tabindex="#(++tabindex)"><i class="fas fa-check mr-2"></i><span>Save</span></button>
<button type="reset" class="btn btn-secondary" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
#section scripts {
<script>
$(function () {
"use strict";
$(document).on('click', '._createSubFormButton', function () {
$('#ModalWindow').modal('show');
$('.modal-title').text('Creating of subgroup');
$('.modal-buttton-save span').text('Create');
$('#ModalForm').attr('action', '/MyCode/CreateSubGroup/?returnurl=' + window.location.href);
});
// Edit form
$(document).on('click', 'tr ._editSubFormButton', function () {
$('#ModalWindow').modal('show');
var $tr = $(this).closest('tr');
var Id = $tr.find('._Id').text();
var Title = $tr.find('._Title').text();
var IdGroup = $tr.find('._IdGroup').text();
var GroupCode = $tr.find('._GroupCode').text();
$('.modal-title').text('Editing of subgroup');
$('#ModalForm').attr('action', '/MyCode/EditSubGroup/' + Id + '?returnurl=' + window.location.href);
$('#Id').val(Id);
$('#Title').val(Title);
$('#GroupCode').val(GroupCode);
});
// form validation reset during closing modal form
$('#ModalWindow').on('hidden.bs.modal', function () {
$(this).find('form').trigger('reset');
$('#IdGroup').load();
$('.form-group .is-invalid').each(function () { $(this).removeClass('is-invalid'); });
$('.form-group .is-valid').each(function () { $(this).removeClass('is-valid'); });
$('.form-text.text-danger').each(function () { $(this).removeClass('text-danger'); });
$('.form-text.text-success').each(function () { $(this).removeClass('text-success'); });
$('.invalid-feedback').each(function () { $(this).remove(); });
});
$(document).on('submit', '#ModalForm', function (e) {
var form = $('#ModalForm');
if (form.valid()) {
console.log(form.serializeArray());
$.ajax({
url: form.attr("action"),
type: form.attr("method"),
data: form.serializeArray()
}).done(function () {
console.log('done');
$tr.find('._Number').text();
var $tr = $(this).closest('tr');
})
.fail(function () {
console.log('fail');
});
$('#ModalWindow').modal('hide');
}
});
error I got:
Have you tried debugging this code? Debugging with setting breakpoints and stepping through the code would help you find what is wrong with this code.
For some reason AJAX is not passing the error message. Whatever I try to submit in my form, I get red line (error message style) but without error message init, which makes hard for me to debug. Any ideas what is causing error message not to be displayed?
My AJAX function, pointing to store method in TicketCategory controller:
$(document).ready(function() {
$("#btn-add").click(function() {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
type: 'POST',
url: '/ticket-category/store',
data: {
name: $("#frmAddTicketCategory input[name=name]").val(),
},
dataType: 'json',
$('#frmAddTicketCategory').trigger("reset");
$("#frmAddTicketCategory .close").click();
window.location.reload();
},
error: function(data) {
var errors = $.parseJSON(data.responseText);
$('#add-ticket-category-errors').html('');
$.each(errors.messages, function(key, value) {
$('#add-ticket-category-errors').append('<li>' + value + '</li>');
});
$("#add-error-bag").show();
}
});
});
My view:
<div class="modal fade" id="addTicketCategoryModal">
<div class="modal-dialog">
<div class="modal-content">
<form id="frmAddTicketCategory">
<div class="modal-header">
<h4 class="modal-title">
Add New Task
</h4>
<button aria-hidden="true" class="close" data-dismiss="modal" type="button">
×
</button>
</div>
<div class="modal-body">
<div class="alert alert-danger" id="add-error-bag">
<ul id="add-ticket-category-errors">
</ul>
</div>
<div class="form-group">
<label>
Name
</label>
<input class="form-control" id="name" name="name" type="text">
</input>
</div>
</div>
<div class="modal-footer">
<input class="btn btn-default" data-dismiss="modal" type="button" value="Cancel">
<button class="btn btn-info" id="btn-add" type="button" value="add">
Add New Task
</button>
</input>
</div>
</form>
</div>
</div>
</div>
Controller:
public function create()
{
return view('ticket_category/ticket_cat',[
'tickets' => TicketCategory::all()
]);
}
public function store(Request $request)
{
$validator = Validator::make($request->input(), array(
'name' => 'required'
));
if ($validator->fails()) {
return response()->json([
'error' => true,
'messages' => $validator->errors(),
], 422);
}
$ticket_category = TicketCategory::create([$request->name]);
return response()->json([
'error' => false,
'ticket_category' => $ticket_category,
], 200);
}
see the error issue
I think value is an array of errors for a field that is why you are not able to display the errors. Try this
$('#add-ticket-category-errors').append('<li>' + value[0] + '</li>')
I have vuejs2 component on page (single file component). It's a simple bootstrap modal window with one file input. I only need to upload one file (no mutlifile upload or etc.)
What is in file:
<template>
<div class="modal fade" id="upload-file-modal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title">Upload file</h4>
</div>
<form id="app-file-upload-form" name="appFileUploadForm" #submit.prevent="uploadAppFile" novalidate enctype="multipart/form-data">
<div class="modal-body">
<div class="form-group">
<label for="app-file-fileinput">File</label>
<input type="file" name="file" id="app-file-fileinput" class="form-control" v-el="file" #change="attachFile">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Upload</button>
</div>
</form>
</div>
</div>
</div>
<script>
export default {
data() {
return {
file: ''
}
},
methods: {
attachFile(e) {
var files = e.target.files || e.dataTransfer.files;
if (!files.length)
return;
this.file = files[0];
},
uploadAppFile() {
console.log(this.file);
Vue.http.post('/api/v1/apps/' + this.appId + '/files', { file: this.file}).then((response) => {
console.log(response);
}, (response) => {
console.log(response);
});
}
}
}
So i have laravel controller for handle it.
public function upload(Request $request)
{
$attachedFile = $request->file;
return response()->json($request->all());
}
I put return response->json() for kinda debug this. When i attach file, file attaching to component(model?) field and not empty. But when vue.http.post happening the file comes to empty object.
First is console.log(file)
Second is server response.
I also tried with FormData()... it didn't work.
ps: i cut version field from code.
After few more times with formdata i got file upload working. Just put variable inside method.
uploadAppFile() {
let data = new FormData();
data.append('file', this.file);
Vue.http.post('/api/v1/apps/' + this.appId + '/files', data).then((response) => {});
}