Client side validation showing strange behavior on Bootstrap modal - c#

I have a page which list all Countries in a tabular form and view has a model like below:
public class CitySet
{
public IEnumerable<CityObject> Cities { get; set; }
[Required]
public string City { get; set; }
[Required]
public string CityCode { get; set; }
}
On the same page I have a link that allows the user to create a new Country via a modal popup(defined within that page)
Modal Popup section of the page is shown below:
#model CMS.Models.CitySet
<div class="box-header well" data-original-title="">
<h2>
<a operation="add" id="btnNewCity" data-toggle="modal" data-target="#myModal" href="#">Add New City</a>
</h2>
</div>
<div class="box-content">
#*Below table is to show all the added Cities in the tabular format on the page itself*#
<table id="myDataTable" class="table table-striped table-bordered ">
<thead>
<tr>
<th>City</th>
<th>Country </th>
<th>Creation Date</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Cities)
{
<tr id="#item.CityID">
<td>#item.City</td>
<td>#item.CountryName</td>
<td>#item.CreatedDate</td>
<td>
Edit
Delete
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
#using (Html.BeginForm("ManageCity", "Admin", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title" id="myModalLabel">Add City</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="City"> City </label>
#Html.TextBoxFor(model => model.City)
#Html.ValidationMessageFor(model=>model.City)
</div>
<div class="form-group">
<label for="CityCode"> City Code </label>
#Html.TextBoxFor(model => model.CityCode)
#Html.ValidationMessageFor(model=>model.CityCode)
</div>
<button type="submit" id="addNewCity" class="btn btn-primary">Save changes</button>
}
</div>
</div>
</div>
The javascript that triggers the modal popup is :
$(".model_edit").click(open_model_form);
function open_model_form(e) {
e.preventDefault();
if ($(e.currentTarget).attr("operation") == "add") {
//open popup
$('#myModal').modal('show');
}
}
[HttpPost, ValidateInput(true)]
public ActionResult ManageCity(FormCollection formData)
{
//Some data saving Operation
}
The behavior that I am seeing is when both the textboxes are empty and user presses Submit Button it shows Validation message against both, but if I enter value in any ONE of them, and press SUBMIT, it start posting the form, i.e. to Action "ManageCity" and does not check for Client side validation on the other textbox.
I have already included both Validate.js and UnObstrusive.js files on my layout page of this form page

Related

Button submit not responding with modal in ASP.NET MVC

I don't know why my "submit" button not responding. When I click on the edit button in each id, it can show a modal like this picture, so data is sent to the modal. But when I try to edit this data and click the button, it is not responding.
Here is my Index.cshtml
<div class="card-body">
<table id="datatablesSimple">
<thead>
<tr style="background-color:gray">
<th>No</th>
<th>Name</th>
<th>Action</th>
</tr>
</thead>
<tfoot>
<tr>
<th>No</th>
<th>Name</th>
<th>Action</th>
</tr>
</tfoot>
<tbody>
#{ var stt = 1;}
#foreach (var item in ViewBag.List)
{
var itemName = "#exampleModalss" + item.id_category;
var itemName1 = "exampleModalss" + item.id_category;
<tr>
<td>#stt</td>
<td>#item.name</td>
<td>
<button type="button" class="btn btn-danger" data-bs-toggle="modal"
data-bs-target="#itemName">Edit</button>
</td>
</tr>
stt++;
<form action="/Category/edit" method="post">
<div class="modal fade" id="#itemName1" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Edit Category Book</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div id="resultss" class="modal-body">
<div class="row">
<div class="col">
<div class="">
<label for="category-film" class="col-form-label" style="font-weight:bold;width : 140px">Name Category: </label>
<input class="form-control" type="text" id="name" name="name" value=#item.name>
<input class="form-control" type="hidden" id="id_category" name="id_category" value=#item.id_category>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button style="width:100px" type="submit" class="btn btn-primary">Edit</button>
</div>
</div>
</div>
</div>
</form>
}
</tbody>
</table>
</div>
My Controller
[HttpPost]
public ActionResult edit(FormCollection form)
{
Category cat = new Category();
cat.id_category = Convert.ToInt32(form["id_category"]);
category.edit(cat);
return PartialView("Index", new { msg = "1" });
}
My DAO
public void edit(Category category)
{
var result = myDb.categories.SingleOrDefault(c => c.id_category == category.id_category);
result.name = category.name;
myDb.SaveChanges();
}
Here is my result when clicking on the Edit button with each id of the category book.
I get stuck in it few days, anyone can help me. I think
Edited for details
FormCollection is for list your form is just about a name and category id
then your model is not appropriate please change your model i mean create model class which contain name and category.

Razor Pages async task return to modal

I'm new in Razor Pages and I can't really find a solution on my problem.
I have a modal, where I would like to update the Identity Roles(Add/Remove users). The async task works fine and I have the list for the members and nonmembers, but the modal close itself after the post.
How I can prevent it(modal close) what is the correct return in this case?
C#
public async Task<IActionResult> OnPostAddtoRoleAsync()
{
if(Input != null)
{
ToolboxRoles role = await _RoleManager.FindByIdAsync(Input.Id);
List<ToolboxUser> members = new List<ToolboxUser>();
List<ToolboxUser> nonMembers = new List<ToolboxUser>();
foreach (ToolboxUser user in _UserManager.Users)
{
var list = await _UserManager.IsInRoleAsync(user, role.Name) ? members : nonMembers;
list.Add(user);
}
Input.Role = role;
Input.Members = members;
Input.NonMembers = nonMembers;
}
return Page(); //I don't know what is the correct return action here, so the modal stay showed
}
Function calling:
<form method="post">
<button asp-page-handler="AddtoRole" asp-route-id="#item.Id" class="btn btn-default" data-id="#item.Id" data-name="#item.Name" data-toggle="modal"
data-target="#EditRole" data-backdrop="static" data-keyboard="false" style="margin-bottom: 10px;">
Update
</button>
Modal:
<div id="EditRole" class="modal fade" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header" style="background-color: #ffd800">
<h4 class="modal-title" style="text-align:left">Update Role</h4>
</div>
<div class="modal-body" style="background-image: linear-gradient(#ffd800,#fff)">
<form method="post">
<input type="text" id="modal_name" asp-for="Input.RName" />
<input type="text" id="modal_id" asp-for="Input.Id" />
#if (Model.Input != null)
{
<div class="row">
<div class="col-md-12" style="background-image: radial-gradient(#ffd800,#fff);border: 1px solid #f11322;margin-bottom: 10px;">
<h4 id="modal_text1" class="font-weight-bold" style="color: #f11322;"></h4>
</div>
</div>
<table class="table table-bordered table-sm">
#if (Model.Input.NonMembers.Count() == 0)
{
<tr><td colspan="2">All Users Are Members</td></tr>
}
else
{
#foreach (ToolboxUser user in Model.Input.NonMembers)
{
<tr>
<td>#user.UserName</td>
<td>
<input type="checkbox" name="AddIds" value="#user.Id">
</td>
</tr>
}
}
</table>
<div class="row">
<div class="col-md-12" style="background-image: radial-gradient(#ffd800,#fff);border: 1px solid #f11322;margin-bottom: 10px;">
<h4 id="modal_text2" class="font-weight-bold" style="color: #f11322;"></h4>
</div>
</div>
<table class="table table-bordered table-sm">
#if (Model.Input.Members.Count() == 0)
{
<tr><td colspan="2">All Users Are Members</td></tr>
}
else
{
#foreach (ToolboxUser user in Model.Input.Members)
{
<tr>
<td>#user.UserName</td>
<td>
<input type="checkbox" name="DeleteIds" value="#user.Id">
</td>
</tr>
}
}
</table>
}
<button asp-page-handler="UpdateRoles" class="btn btn-default">Save</button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
And the JS which I use to pass the values to the modal:
$('#EditRole').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget); // Button that triggered the modal
var id = button.data('id');
var name = button.data('name'); // Extract info from data-* attributes
// Update the modal's content
document.getElementById('modal_id').setAttribute('value', id);
document.getElementById('modal_name').setAttribute('value', name);
var modal = $(this);
modal.find('#modal_text1').text('Add Users to ' + name);
modal.find('#modal_text2').text('Remove Users from ' + name);
});
Thanks,
Devcore
return Page() you should call when you want to refresh page. If everything is OK after adding to list (you are sure that Add is performed) you can just: return Ok(), or return NoContent().
Read documentation: Microsoft docs.
I think it might be better to see the whole picture (how your modal is handling the return response from your OnPostAddtoRoleAsync() function).
as Lazar pointed out, What would be more beneficial is to return a response on whether the users were added to the roles correctly. Using Ok() or other various status codes depending on what happened to the users would be more beneficial in this instance.
You can prevent certain actions from taking place inside the modal by using event.preventDefault();. Again, we can't see how your frontend razor page is handling the modal since you have not provided that here. This source might help with using modals https://www.mikesdotnetting.com/article/349/razor-pages-and-bootstrap-modal-master-details
Let me know if this helps, thanks.
I think you should separate the modal body and make it as a partial view. Use jquery ajax to get the partial view, append it to the modal then open it.
I made a simple demo, you may refer to it.
Index.cshtml:
#page
#model IndexModel
#{
ViewData["Title"] = "Home page";
}
#Html.AntiForgeryToken()
<button id="Edit" data-id="1" class="btn btn-danger"
data-backdrop="static" data-keyboard="false" style="margin-bottom: 10px;">
Update
</button>
<div id="EditRole" class="modal fade" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header" style="background-color: #ffd800">
<h4 class="modal-title" style="text-align:left">Update Role</h4>
</div>
<div class="modal-body" style="background-image: linear-gradient(#ffd800,#fff)">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
#section scripts{
<script>
$("#Edit").click(function () {
var id = $(this).attr('data-id');
$.ajax({
type: 'POST',
url: 'Index?handler=AddtoRole',
data: {
id: id,
},
headers: {
RequestVerificationToken:
$('input:hidden[name="__RequestVerificationToken"]').val()
},
success: function (result) {
$('.modal-body').html(result);
$('#EditRole').modal('show');
}
});
})
</script>
}
Index.cshtml.cs:
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
[BindProperty]
public Student Input { get; set; }
public void OnGet()
{
}
public IActionResult OnPostAddtoRole()
{
Input.Name = "StudentA";
return Partial("_AddRolePartial",Input);
}
public void OnPost()
{
}
}
_AddRolePartial.cshtml:
#model RazorTest.Models.Student
<form method="post">
<div>
<label>Id:</label>
#Model.Id
</div>
<div>
<label>Name:</label>
#Model.Name
</div>
<button asp-page-handler="UpdateRoles" class="btn btn-default">Save</button>
</form>
Student.cs:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
Result:

How to show loader image until controller method completes in ASP.NET MVC?

I have an Index page like below and on button click I have some code to save data into database and then it goes on details page.
But I the code should go to the details page only after completing the database save operation; I want to show a loader image until then; how can I do this?
Currently I'm using begin post to post method and bind all model not using any ajax call. How can I show loader image and render before process complete to details page?
Index.cshtml
#model Dev.Models.DeviceReg
#using (Html.BeginForm("AddAsync", "Home", FormMethod.Post))
{
<div class="panel panel-primary">
<div class="panel-body">
<div class="row">
<div class="col-md-6">
<h4 id="aa">Name</h4>
<label>Select</label>
<table>
<tr>
<td>
#Html.DropDownListFor(m => m.Name, (SelectList)ViewBag.Name, "---Select Name---")
</td>
</tr>
</table>
</div>
</div>
<div class="row">
<div class="col-md-6">
<h4 id="aa">Model</h4>
<label>Select</label>
<table>
<tr>
<td>
#Html.DropDownListFor(m => m.Type, (SelectList)ViewBag.TypeName, "---Select Type---")
</td>
</tr>
</table>
</div>
</div>
<div class="panel-footer" align="left">
<button type="submit" id="save" class="btn btn-success">
<span class="glyphicon glyphicon-arrow-right"></span> save
</button>
</div>
</div>
}
HomeController.cs
public async Task<ActionResult> AddAsync(DeviceReg deviceRegistration)
{
foreach (var deviceId in collection)
{
// save device information into database
Models.Device newDevice = new Models.Device()
{
Id = Guid.NewGuid(),
DeviceTypeId = deviceRegistration.DeviceType,
PlatformId = deviceRegistration.PlatformType,
DeviceId = deviceId,
};
_repository.InsertDevice(newDevice);
_repository.Save();
}
return View("Details", deviceRegistration);
}
Details.cshml
#model Dev.Models.DeviceReg
<body style="background-color:black">
<div class="panel panel-primary">
<div class="panel-heading" align="center">
<h2 class="panel-title">Details</h2>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-6">
<h3><label>Current Data</label></h3>
<br />
</div>
</div>
<div class="row">
<div class="col-md-6">
<h4 id="aa">Name</h4>
<label>#Model.Name</label>
</div>
</div>
<div class="row">
<div class="col-md-6">
<h4 id="aa">Type</h4>
<label>#Model.TypeName</label>
</div>
</div>
<hr />
<br />
<label>Your process is running.</label>
<br />
<div class="row">
<div class="col-md-6">
<h3><label>Status</label></h3>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div style="clear: both">
<h2 style="float: left">10</h2>
<h6 style="float: right">Active Number</h6>
</div>
</div>
</div>
</div>
</div>
</body>
Well, if you need to show loader while post form is submitting, you can use javascript functions to show it, like
#using (Html.BeginForm("AddAsync", "Home", FormMethod.Post, new { onsubmit = "showLoader(this);" }))
{
...
}
plus JS
<script>
var showLoader = function(form){
$("<div />").css({
'position' : 'fixed',
'left' : 0,
'right' : 0,
'bottom' : 0,
'top' : 0,
'background' : '#0020ff36',
'z-index' : '99',
'text-align' : 'center'
}).appendTo($("body"))
.append(
$("<img />").attr("src", "https://mir-s3-cdn-cf.behance.net/project_modules/disp/35771931234507.564a1d2403b3a.gif")
);
}
</script>
or by jquery event, like
<script>
$("form").submit(function(){
//show loader
});
</script>
example of this code https://dotnetfiddle.net/gfEVSE
But, regarding to your clarification of the issue in comments, it's impossible to show Details page with progress of saving without Javascript or another additional requests.
Example without ajax but with aditional requests every N seconds
[HttpPost]
public ActionResult AddAsync(SampleViewModel deviceRegistration)
{
Task.Run(()=>
{
//Saving to DB
});
return RedirectToAction("Details", id = deviceRegistration.id);
}
public ActionResult Details(int id)
{
var isObjectExistInDb = checkIfExistInDb(id);
if (!isObjectExistInDb){
return View("ShowLoader", id);
}
return View(object);
}
where in ShowLoader.cshtml you need to reload page every N seconds.
With ajax it will be more clear, pretty code. Please, let me know, if you need example with ajax :)

How to pass iteration variable to bootstrap modal popup in partial view asp.net mvc

i have a delete button after the confirmation i want to call method.
but right now after model up is opened method can not be call from view to controller.
i want to call delete method after the confirmation on model popup click.if anyone has a solution please help me and if any other method for this gives an example.
here is my popup model
<div class="modal fade" id="confirmDelete" role="dialog" aria-labelledby="confirmDeleteLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Delete Parmanently</h4>
</div>
<div class="modal-body">
<p>Are you sure about this ?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-danger" id="confirm">Delete</button>
</div>
</div>
</div>
here is my jquery on same partial view page
<script type="text/javascript">
$('#confirmDelete').on('show.bs.modal', function (e) {
$message = $(e.relatedTarget).attr('data-message');
$(this).find('.modal-body p').text($message);
$title = $(e.relatedTarget).attr('data-title');
$(this).find('.modal-title').text($title);
});
$('#confirmDelete').find('.modal-footer #confirm').on('click', function(){
});
</script>
here is my view
<section class="content">
<div class="row">
<div class="col-md-12">
<div class="box box-primary" style="overflow-x:scroll;">
<div class="box-header">
<h3 class="box-title">Unit Detail</h3>
<div class="box_top_botton">
<a class="btn btn-md btn-primary" href="#Url.Action("AddUnit", "UnitMasters")">
<i class="glyphicon glyphicon-plus-sign"></i> Add Unit
</a>
</div>
</div><!-- /.box-header -->
<div class="box-body table-responsive">
<table class="table table-bordered table-striped example1">
<thead>
<tr>
<th></th>
<th>
#Html.DisplayNameFor(model => model.UnitId)
</th>
<th>
#Html.DisplayNameFor(model => model.UnitName)
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td nowrap style="font-size:14px !important;text-align:center !important;">
<a class="btn btn-xs btn-primary" href="#Url.Action("AddUnit", "UnitMasters", new { id = item.UnitId })">
<i class="glyphicon glyphicon-pencil"></i>
</a>
|
<a class="btn btn-xs btn-danger" href="#Url.Action("Delete", "UnitMasters", new { id = item.UnitId })" data-toggle="modal" data-target="#confirmDelete" data-title="Delete User" data-message="Are you sure you want to delete this user ?">
<i class="glyphicon glyphicon-trash"></i>
</a>
</td>
<td>
#Html.DisplayFor(modelItem => item.UnitId)
</td>
<td>
#Html.DisplayFor(modelItem => item.UnitName)
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</div>
#Html.Partial("DialogBox", "Home")
here is my controller
public ActionResult DeleteConfirmed(int id)
{
UnitMaster unitMaster = db.UnitMasters.Find(id);
db.UnitMasters.Remove(unitMaster);
db.SaveChanges();
return RedirectToAction("Index");
}
1) Make sure you have referenced to all of below jquery.js, bootstrap.css and bootstrap.js
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap.css" rel="stylesheet" />
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
2) Add pass your #item.UnitId to data-id data attribute to your glyphicon-trash link like
<a class="btn btn-xs btn-danger" href="#" data-toggle="modal" data-id="#item.UnitId" data-target="#confirmDelete" data-title="Delete User" data-message="Are you sure you want to delete this user ?">
<i class="glyphicon glyphicon-trash"></i>
</a>
3) Make changes to your script like below
<script type="text/javascript">
var unitId = 0;
$('#confirmDelete').on('show.bs.modal', function (e) {
var message = $(e.relatedTarget).data('message');
$(this).find('.modal-body p').text(message);
var title = $(e.relatedTarget).data('title');
$(this).find('.modal-title').text(title);
unitId = $(e.relatedTarget).data('id');
console.log(unitId);
});
$('#confirmDelete').find('.modal-footer #confirm').on('click', function () {
var urlToDelete = '#Url.Action("DeleteConfirmed", "ControllerName")/' + unitId;
console.log(urlToDelete);
//Here is your ajax delete call with above url
});
4) Your modal popup will remain same no any changes
Output:

ASP.NET MVC Using Partial Views as Dialogs

I have an ASP.NET MVC app. This app has a view that shows a list of records. I want to let my users add a record to this list. To do that, I've created a dialog that the user can enter information into. At this time, this dialog is a partial. I'm willing to change the implementation. I just need a dialog for adding. At this time, my views look like this:
Index.cshtml
<table class="table">
<thead>
<tr>
<th></th>
<th>First Name</th>
<th>Last Name</th>
<th>Email address</th>
</tr>
</thead>
<tbody>
#foreach (var user in Model.Users)
{
<tr>
<td></td>
<td>#user.FirstName</td>
<td>#user.LastName</td>
<td>#user.Email</td>
</tr>
}
</tbody>
</table>
<br />
<button type="button" class="btn btn-default" onclick="addPerson()">Add Person</button>
#* Add Person dialog *#
<div id="addPersonModal" class="modal">
<div class="modal-dialog">
#{Html.RenderAction("Add", "Person");}
</div>
</div>
<script type="text/javascript">
function addPerson() {
$('#addPersonModal').modal('show');
}
</script>
Add.cshtml
#model MyApp.Models.AddPersonModel
#{ Layout = null; }
<div class="modal-content">
#using(Html.BeginForm("Add", "Person", FormMethod.Post))
{
<div class="modal-header">
<h4 class="modal-title">Add New Person</h4>
</div>
<div class="modal-body">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="row">
<div class="col-md-6">
#Html.TextBoxFor(m => m.FirstName)
</div>
<div class="col-md-6">
#Html.TextBoxFor(m => m.LastName)
</div>
</div>
<div class="row">
<div class="col-md-12">
#Html.TextBoxFor(m => m.Email)
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Create</button>
</div>
#Html.AntiForgeryToken()
}
</div>
PersonController.cs
namespace MyApp.Controllers
{
public class PersonController : Controller
{
public ActionResult Index()
{
var model = new IndexModel();
return View(model);
}
public ActionResult Add()
{
var model = new AddPersonModel();
return View(model);
}
[HttpPost]
public ActionResult Add(AddPersonModel model)
{
if (ModelState.IsValid)
{
model.Save();
}
else
{
// I'm stuck here.
}
var listModel = new IndexModel();
return View("~/Views/Person/Index.cshtml", listModel );
}
}
}
Everything works except for validation. If the user enters some invalid data, the view reloads the entire screen and the data is lost. The dialog is also closed. I need to be able to show the values the user entered and the validation summary in the dialog window if the data is invalid. Yet, I'm not sure how to do this.

Categories