MVC Razor form button not calling controller specified - c#

So within my view, I have:
<div id="createProductModal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Create Product</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
#using (Html.BeginForm("Create", "Product", FormMethod.Post, new { id = "createProductForm", #class = "form-horizontal"}))
{
<div class="form-group">
<div class="col-md-4">
#Html.LabelFor(m => Model.Product.Name, new { #class = "control-label" })
</div>
<div class="col-sm-8">
#Html.TextBoxFor(m => Model.Product.Name, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-4">
#Html.LabelFor(m => Model.Product.IsActive, new { #class = "control-label" })
</div>
<div class="col-sm-8">
#Html.CheckBoxFor(m => Model.Product.IsActive, new { #class = "form-control" })
</div>
</div>
}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal" onclick="$('#createProductForm').submit();">Add product</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
And then in my ProductsController I have added an action like so:
[HttpPost]
public ActionResult Create(Product product)
{
return View();
}
But for some reason when clicking submit it redirects me to this URL:
http://localhost/Product/Create
And throws a 404 error like so:
The resource cannot be found.
I've not defined a route within the route configs surely this shouldn't matter?
Does anyone understand what i seem to be doing wrong?

Second parameter of Html.BeginForm is the controller name. Given that you have a ProductsController, instead of
Html.BeginForm("Create", "Product", ...
Try
Html.BeginForm("Create", "Products"
Check FormExtensions.BeginForm

Related

Bootstrap - present confirmation modal after post back to controller

I am trying to create a Bootstrap modal pop up "Ticket successfully created" once you submit a form which posts data through to IActionResult to add to database. However my modal is like transparent with just text and I'm also getting a runtime error of : Obj ref not set to an instance of object
I have a feeling that modal popup is causing the passing of data back to the controller to not work. What is the way around this?
GetTicket view
#model Project.HelpDeskViewModel
<fieldset>
#using (Html.BeginForm())
{
<div class="container">
<div class="form-group">
<div class="row m-4 text-center">
<div class="col-4">
</div>
<div class="col-4">
<h2 style="text-align:center;font-weight:bold">Get A Ticket</h2>
</div>
</div>
</div>
<div class="form-group">
<div class="row m-3">
<div class="col-4" style="text-align:left">
#Html.LabelFor(m => m.category)
</div>
<div class="col-4">
#Html.DropDownListFor(m => m.category, new SelectList(Model.categoryList, "Value", "Text"), "Select category", new { #class = "form-control" })#Html.ValidationMessageFor(model => model.category,
"", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
<div class="row m-3">
<div class="col-4" style="text-align:left">
#Html.LabelFor(m => m.ticketDescription)
</div>
<div class="col-4">
#Html.TextAreaFor(m => m.ticketDescription, new { #class = "form-control" })#Html.ValidationMessageFor(model => model.ticketDescription,
"", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
#*Modal for ticket creation*#
<div class="modal" id="MyModal" role="dialog">
<div class="modal-dialog">
<div class="model-content">
<div class="modal-header">
<button class="close" data-dismiss="modal">×</button>
<h4>Ticket Created</h4>
</div>
<div class="modal-body">
<p> Your Helpdesk ticket has been succesfully submitted</p>
</div>
<div class="modal-footer">
<button class="btn btn-primary" data-dismiss="modal"> close</button>
</div>
</div>
</div>
</div>
</div>
<div class="row m-3">
<div class="col-4">
</div>
<div class="col-4" style="text-align:left">
<button type="submit" class="btn btn-primary form-control" data-target="#MyModal" data-toggle="modal">Submit</button>
</div>
</div>
</div>
}
</fieldset>
Controller
[HttpPost]
public IActionResult GetTicket(HelpDeskViewModel h)
{
HelpDeskViewModel sess = new HelpDeskViewModel();
try
{
//session variable passing userID
sess.userID = HttpContext.Session.GetString("userID");
if (!ModelState.IsValid) return View(h);
//h.empID = null; //add ticket record without employeeID - ticket hasn't been assigned yet
h.userID = sess.userID; //add userID from session
_db.helpdesk.Add(h);
_db.SaveChanges();
}
catch (Exception ex)
{
global.gLogger.log.Debug("Debug message: ", ex.Message);
global.gLogger.log.Error(new Exception(), ex.Message);
global.gLogger.log.Error(new Exception(), ex.StackTrace);
global.gLogger.log.Fatal("Fatal message: ", ex.Message); ;
}
return View("GetTicket");
}
You can use ViewBag for open bootstrap modal after successfully return from server to client
Client Side View
#if(ViewBag.SuccessfullyTicketCreated != null)
{
<script>
$('#myModal').modal('show'); // open model by use jQuery
</script>
}
Server side Controller
_db.SaveChanges();
ViewBag.SuccessfullyTicketCreated = true; // create ViewBag after savechange success
I hope help you simple way
Only use of ajax call can solve your problem without creating any further issues. if you are not using jQuery, you can also send ajax call using Javascript using fetch() method.
<form id="form" action="/Controller/GetTicket" method="post">
<div class="container">
<div class="form-group">
<div class="row m-4 text-center">
<div class="col-4">
</div>
<div class="col-4">
<h2 style="text-align:center;font-weight:bold">Get A Ticket</h2>
</div>
</div>
</div>
<div class="form-group">
<div class="row m-3">
<div class="col-4" style="text-align:left">
#Html.LabelFor(m => m.category)
</div>
<div class="col-4">
#Html.DropDownListFor(m => m.category, new SelectList(Model.categoryList, "Value", "Text"), "Select category", new { #class = "form-control" })#Html.ValidationMessageFor(model => model.category,
"", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
<div class="row m-3">
<div class="col-4" style="text-align:left">
#Html.LabelFor(m => m.ticketDescription)
</div>
<div class="col-4">
#Html.TextAreaFor(m => m.ticketDescription, new { #class = "form-control" })#Html.ValidationMessageFor(model => model.ticketDescription,
"", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
#*Modal for ticket creation*#
<div class="modal" id="MyModal" role="dialog">
<div class="modal-dialog">
<div class="model-content">
<div class="modal-header">
<button class="close" data-dismiss="modal">×</button>
<h4>Ticket Created</h4>
</div>
<div class="modal-body">
<p> Your Helpdesk ticket has been succesfully submitted</p>
</div>
<div class="modal-footer">
<button class="btn btn-primary" data-dismiss="modal"> close</button>
</div>
</div>
</div>
</div>
</div>
<div class="row m-3">
<div class="col-4">
</div>
<div class="col-4" style="text-align:left">
<button type="submit" class="btn btn-primary form-control" data-target="#MyModal" data-toggle="modal">Submit</button>
</div>
</div>
</div>
</form>
Use Javascript:
<script> function onSubmit(){
$.ajax({
url:'/Controller/GetTicket',
type:'post',
data: $('#form').serialize(),
success: function(){
// code here;}
})
}</script>

MVC partial view controller not running on load

Im trying to load a MVC partial view in to a modal popup. The popup contains a drop down list which I am trying to populate on the ActionResult that loads when the view is loaded. The problem is the controller code isn't getting ran.
My code is as follows -
View:
<div id="modal_form_horizontal_addnote" class="modal fade">
<div class="modal-dialog modal-md">
<div class="modal-content">
<div class="modal-header bg-primary">
<button type="button" class="close" data-dismiss="modal">×</button>
<h5 class="modal-title">Add Note</h5>
</div>
#Html.Partial("AddNote", new IHD.Core.Models.CreateTicketNoteModel { TicketHeaderId = Model.Id })
</div>
</div>
The partial view:
#model IHD.Core.Models.CreateTicketNoteModel
#using (Html.BeginForm("AddNote", "Ticket", FormMethod.Post))
{
#Html.HiddenFor(model => model.TicketHeaderId)
#Html.AntiForgeryToken()
<div class="row">
<div class="col-md-12">
<div class="tab-content">
<div class="tab-pane active" id="highlighted-justified-tab1">
<div class="form-group">
#Html.LabelFor(model => model.WorkType, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-12">
#Html.DropDownListFor(model => model.WorkType, new SelectList(Model.WorkTypeOptions, "Key", "Value", Model.WorkType), new { #name = "select", #class = "form-control" })
#Html.ValidationMessageFor(model => model.WorkType, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
</div>
</div>
}
The controller:
public ActionResult AddNotePhase(int id = 0, int taskId = 0)
{
CreateTicketPhaseNoteModel note = new CreateTicketPhaseNoteModel();
note.TicketHeaderId = id;
// Populate the work type dropdown list
note.WorkTypeOptions.Add("", "-- Select a Work Type --");
note.WorkTypes = _workTypeService.GetAll().ToList();
foreach (var c in note.WorkTypes)
{
note.WorkTypeOptions.Add(c.Id.ToString(), c.Description);
}
//note.PhaseTask = taskId;
return PartialView(note);
}
You controller code isn't being hit because you are passing a model to the partial view and not calling the action. You need to use #{Html.RenderAction();} instead to call your action with the appropriate values.

Submitting a form from a partial view

I'm trying to submit a form from a modal generated in a partial view. And I don't know how to get back the submitted form.
Here is the view:
#model Myproject.ViewModels.GetMonitorFromDeviceViewModel
#{
ViewBag.Title = "GetMonitorFromDevice";
Layout = "~/Views/Shared/ManagementPage.cshtml";
}
<div id="Accordion">
#{
foreach (var type in Model.AvailableTypesAvailableMonitors)
{
<div class="card">
<div class="card-header">
<a class="card-link" data-toggle="collapse" data-parent="#accordion" href="##type">
#type
</a>
</div>
<div id="#type" class="collapse show">
<div class="card-body">
#{
foreach (var monitor in Model.ActiveMonitors)
{
if (monitor.Type == #type)
{
<p>
#monitor.Name
<span class="btn btn-xs btn-primary btnEdit" onclick="createModal('#Url.Action("NameMonitor", "DeviceManager" , new { idDevice = monitor.DeviceOwner.ID, monitorName = monitor.Name })')">Details</span>
</p>
}
}
}
</div>
</div>
</div>
}
}
</div>
And here is my modal at the bottom of the page:
<div class="modal fade" id="myModal" role="dialog" data-backdrop="static" data-keyboard="false">
<div class="modal-dialog">
<div class="modal-content" id="modelContent">
</div>
</div>
</div>
<script>
function createModal(url) {
$('#modelContent').load(url);
$('#myModal').modal('show');
}
</script>
And finally, here is my partial view that is displayed as a modal:
#model MyProject.ViewModels.NameMonitorModal
#using (Html.BeginForm("NameMonitor", "DeviceManager", FormMethod.Post))
{
<div class="modal-body">
<div class="form-group">
#Html.LabelFor(model => model.NewName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.NewName, new { htmlAttributes = new { #class = "form-control", #Value = Model.TrueName } })
#Html.ValidationMessageFor(model => model.NewName, "", new { #class = "text-danger" })
</div>
</div>
#Html.HiddenFor(model => model.TrueName)
#Html.HiddenFor(model => model.IdDevice)
</div>
<div class="modal-footer">
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save name" class="btn btn-default" data-dismiss="modal" />
</div>
</div>
</div>
}
In my controller, I have an action for my partial view called ActionResult NameMonitor.
In order to catch the submited form, I tried to add another action with the [HttpPost] tag with the same name but doesn't work. I also tried to use the main page action with the [HttpPost] tag but it doesn't work either. As you can see, I have specified the action and controller in the form itself but its still not working.
Now, I'm a little bit out of idea of how I can get the information from my modal back.
data-dismiss="modal" will close the modal without submitting the form, see Dismiss and submit form Bootstrap 3
You can change the submit button to call a JavaScript function to submit the form, then close the modal.
function submitModal() {
$('#myFormId').submit();
$('#myModal').modal('hide');
}

Partial view that does not use the ActionName that I specify

I am currently developing an application in C # with ASP.NET MVC and entity Framework.
I use a partialview to edit data, for example I have a list of "module" in table form, I can add a module, delete one or edit one.
To create a module I proceed as follows:
My view :
<asp:UpdatePanel ID="ModuleUpdatePanel" runat="server">
<ContentTemplate>
<!-- Modal -->
<asp:Label ID="Label1" runat="server" Text=""></asp:Label><br />
<div class="modal fade" id="ModuleModal" tabindex="-1" role="dialog" aria-labelledby="ModuleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
#Html.Action("_CreateModule")
</div>
</div>
</div>
</ContentTemplate>
</asp:UpdatePanel>
The controller's method returning the partialview inside my modal:
[Authorize]
public ActionResult _CreateModule()
{
ModuleViewModel ViewModel = new ModuleViewModel { };
return PartialView(ViewModel);
}
The partialview :
#using (Html.BeginForm("CreateModule", "Parametres", FormMethod.Post))
{
#model Lynx.ViewModels.ModuleViewModel
<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" id="ModuleModalLabel">
Ajouter un module
</h4>
</div>
<div class="modal-body">
<div class="form-group">
#Html.TextBoxFor(m => m.Module.Libelle_Module, new { #class = "form-control", #placeholder = "Libellé du module" })
#Html.ValidationMessageFor(m => m.Module.Libelle_Module)
</div>
<div class="form-group">
#Html.TextBoxFor(m => m.Module.Capacite_Max_Module, new { #class = "form-control", #placeholder = "Capacité max (Palettes/heure)" })
#Html.ValidationMessageFor(m => m.Module.Capacite_Max_Module)
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
Annuler
</button>
<input type="submit" class="btn btn-success" value="Enregistrer" />
</div>
}
The controller's method adding the module:
[Authorize]
[ActionName("CreateModule")]
public void CreateModule(Modules module)
{
if (ModelState.IsValid)
{
if (Dal.GetModule(module.PK_Code_Module) == null)
{
Dal.AddModule(Dal.GetMaxIdModule() + 1, module.Libelle_Module, module.Capacite_Max_Module);
}
}
}
For this part, everything works. Where I have a problem is at the level of my module edition (I use the same process)
View :
<div class="modal-content">
#Html.Action("_EditModule", "Parametres", new { id = #module.PK_Code_Module })
</div>
The controller's method returning the partialview inside my modal:
[Authorize]
public ActionResult _EditModule(int Id)
{
Modules module = Dal.GetModule(Id);
return PartialView(module);
}
The PartialView :
#using (Html.BeginForm("EditModule", "Parametres", FormMethod.Post))
{
#model Lynx.Models.Modules
<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" id="EditModuleModalLabel">
Modifier un module
</h4>
</div>
<div class="modal-body">
<div>
<b>Id Module</b>
#Html.TextBoxFor(model => model.PK_Code_Module, new { #class = "form-control", #readonly = "readonly" })
</div>
<div>
<b>Libellé</b>
#Html.TextBoxFor(model => model.Libelle_Module, new { #class = "form-control" })
</div>
<div>
<b>Capacité max du module (colis/heure)</b>
#Html.TextBoxFor(model => model.Capacite_Max_Module, new { #class = "form-control" })
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
Annuler
</button>
<input type="submit" class="btn btn-success" value="Enregistrer" />
</div>
}
The controller's method Editing the module:
[Authorize]
[ActionName("EditModule")]
public void EditModule(Modules module)
{
if (Dal.GetModule(module.PK_Code_Module) != null)
{
Dal.UpdateModule(int.Parse(module.PK_Code_Module), module.Libelle_Module, module.Capacite_Max_Module);
}
String URL = HttpContext.Request.Url.AbsoluteUri;
string[] lines = Regex.Split(URL, "/");
if (lines[lines.Length - 1] == "Parametres")
{
Response.Redirect("Parametres");
}
else
{
Response.Redirect("Index");
}
}
Here my button "Enregistrer" does absolutely nothing ... As if he ignored my "Bginform"
Any ideas ?
Put [HttpPost] in the action on your controller. Like that:
[HttpPost]
[Authorize]
[ActionName("EditModule")]
public void EditModule(Modules module)
{
if (Dal.GetModule(module.PK_Code_Module) != null)
{
Dal.UpdateModule(int.Parse(module.PK_Code_Module), module.Libelle_Module, module.Capacite_Max_Module);
}
String URL = HttpContext.Request.Url.AbsoluteUri;
string[] lines = Regex.Split(URL, "/");
if (lines[lines.Length - 1] == "Parametres")
{
Response.Redirect("Parametres");
}
else
{
Response.Redirect("Index");
}
}

MVC Model is empty when postback

I have this model, Customer . When i get the information with an id, it works just fine.
Like ;
/Customer/Entity/5
#model ProgSpace.Models.Customer
#{
ViewBag.Title = Model.Name;
Layout = "~/Views/Shared/_MainLayout.cshtml";
}
#section bodypane
{
#using (Html.BeginForm("Entity", "Customer", FormMethod.Post, new { #enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="col-md-12">
<div class="col-md-1">
<label>Customer No:</label>
<h4># #(Model.ID) </h4>
</div>
<div class="clearfix"></div><br />
<div class="col-md-2">
<div class="col-md-12">
<div class="col-md-12 fileupload fileupload-exists" data-provides="fileupload">
<div class="fileupload-preview fileupload-exists thumbnail" style="width: 200px; height: 150px;">
<img src="#Model.Picture.Path" />
</div>
<div>
<span class="btn btn-default btn-file">
<span class="fileupload-new">Add Pic </span>
<span class="fileupload-exists">Change</span><input name="file" id="file" type="file">
</span>
Remove
</div>
</div>
</div>
</div>
<div class="col-md-10">
<div class="col-md-3">
<label>Name *</label>
#Html.TextBoxFor(model => model.Name, new { #class = "form-control"})
</div>
<div class="col-md-3">
<label>Company</label>
#Html.TextBoxFor(model => model.Contact.Company, new { #class = "form-control"})
</div>
<div class="col-md-3">
<label>Phone </label>
#Html.TextBoxFor(model => model.Contact.Phone, new { #class = "form-control" })
</div>
</div>
<div class="clearfix"><br /></div>
<p> </p>
<div class="col-md-12">
<div class="btn-group">
<button class="btn btn-danger btn-lg">Cancel</button>
<button type="submit" class="btn btn-success btn-lg">Send</button>
</div>
</div>
</div>
}
}
And in the controller i have these actions.
public ActionResult Entity(int id)
{
Customer cust= sis.Customers.Where(t => t.ID == id).FirstOrDefault();
return View(cust);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Entity(Customer cust, HttpPostedFileBase file)
{
if (ModelState.IsValid)
{
/* Do something */
}
else
{
}
return View(cust);
}
When the verb is GET , it's fine. But when i post this form and when the second action (HttpPost action) kicks in , view throws an error..
Object reference not set to an instance of an object
which marks the Model.ID is null in the view.
<div class="col-md-1">
<label>Customer No:</label>
<h4># #(Model.ID) </h4> ---> THIS HERE THROWS NULL EXCEPTION
</div>
I've tried to add a HiddenFor for the Model.ID like
#Html.HiddenFor(t => t.ID)
but it didn't change anything.
How do i get back to the same view with the same context again ?

Categories