MVC Dropdown List containing Method Actions for Models, Possible? - razor

I have several models in my application which I want to create functionality to allow users to edit/create values within the database.
Of course each controller contains the action method, but I want to be able to provide the user with a dropdown that lists all of the models so when they select an option from the dropdown it takes the user to the correct view to Edit or Ceate an item in that model.
I.e. I have models for GoverningBody, Directorate, Region, and OperationalTeam, each of them have the following elements;
.....Id (int),
.....Name (string),
Live (bit)
(Live is used as a method for soft deleting of the value in order to protect historic data) I want to have a dropdown with these listed, the user selects one from the dropdown, clicks a button, and the user is then provided the Edit view, or Create view for that selected model.
I've done a but of research on the internet but cannot find any kind of solution nor anything that explains if what I'm attempting to achieve is even possible, and its most likely down to the fact that I don't know enough to know what I should be looking for.
I'm not asking for anyone to provide me with a solution, but any advice on what/where I should be looking, what terms to look for and learn about so I can attempt something on my own.
Any advice would be most appreciated.
Thanks

In my opinion, You can create two DropdownList, One is choose model and the other is choose action, I create a simple demo to show my opinion, Hope it can help you.
First, I create two models for this demo (User, GoverningBody), Then I Use Model Name to create controller with CURD action
public class UserController : Controller
{
public IActionResult Create()
{
return View();
}
public IActionResult Edit()
{
return View();
}
public IActionResult Update()
{
return View();
}
public IActionResult Delete()
{
return View();
}
}
public class GoverningBodyController : Controller
{
public IActionResult Create()
{
return View();
}
public IActionResult Edit()
{
return View();
}
public IActionResult Update()
{
return View();
}
public IActionResult Delete()
{
return View();
}
}
HomeController
public IActionResult Index()
{
List<SelectListItem> model = new List<SelectListItem>();
model.Add(new SelectListItem { Text = "User", Value = "User" });
model.Add(new SelectListItem { Text = "GoverningBody", Value = "GoverningBody" });
ViewBag.model = model;
List<SelectListItem> action = new List<SelectListItem>();
action.Add(new SelectListItem { Text = "Create", Value = "Create" });
action.Add(new SelectListItem { Text = "Edit", Value = "Edit" });
action.Add(new SelectListItem { Text = "Update", Value = "Update" });
action.Add(new SelectListItem { Text = "Delete", Value = "Delete" });
ViewBag.action = action;
return View();
}
View
<h2>Choose a model and an action you want to do with this model</h2>
<div>
Model: <select asp-items="#ViewBag.model" name="model" id="model"></select>
Action : <select asp-items="#ViewBag.action" name="action" id="action"></select>
</div>
<button type="button" onclick=go()>Go~</button>
#section Scripts{
<script>
function go(){
var controller = document.getElementById("model").value;
var action = document.getElementById("action").value;
window.location.href= "/"+controller+"/"+action;
}
</script>
}
Demo:

Related

How to pass value selected from DropDownList to Controller - MVC

I am having trouble getting the value selected in my dropdownlist in my Homecontroller. I have the DropDownList in a form but I think my format may be wrong. I'm new to MVC and new to HTML so I'm struggling pretty hard. Would appreciate some help.
Here is my controller (I put this in my homecontroller, is that a bad idea?):
public IActionResult Index()
{
_ = new List<MyjsonSettings>();
var obj = new StatusPortController(configuration);
List<MyjsonSettings> PortList = obj.GetPortNum();
List<SelectListItem> AppNameList = PopulateDropDown(PortList);
ViewData["Applications"] = AppNameList;
return View("~/Views/Home/dataview.cshtml");
}
public List<SelectListItem> PopulateDropDown(List<MyjsonSettings> PortList)
{
List<SelectListItem> AppNameList = new List<SelectListItem>();
for (int i = 0; i < PortList.Count(); i++)
{
AppNameList.Add(new SelectListItem {
Text = PortList[i].NAME, Value = (i+1).ToString()
});
}
return AppNameList;
}
Here is the view (dataview.cshtml):
#{
ViewData["Title"] = "Home Page";
}
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
#Html.DropDownList("Applications", ViewData["AppNameList"] as List<SelectListItem>)
<input type="submit" value="submit" />
}
Any ideas? No errors when I run, I just don't know how to get the response back.
you can rebuild the structure to a more usable way, and in order to submit form with drop down list or any type of fields you need to first return a view with Model and then submit the form to an action that receive same Model type as parameter
example:
model:
public class ApplicationsAddModel {
public ApplicationsAddModel (){
//constructer to initialize the list
ApplicationsList = new List<SelectListItem>();
}
public string test{ get; set; }
public int selectedApplicationId { get; set; }
public List<SelectListItem> ApplicationsList { get; set; }
}
controller
//this is the first action that return the model
[HttpGet]
public IActionResult Index()
{
ApplicationsAddModel model = new ApplicationsAddModel ();
//fill your drop down list
List<SelectListItem> AppNameList = PopulateDropDown(PortList);
model.ApplicationsList = AppNameList;
return View(model);
}
[HttpPost] //recive the form
public IActionResult Index(ApplicationsAddModel SubmittedModel)
{
var selectedApplication = SubmittedModel.selectedApplicationId; //get the selected value from ddl
//fill your drop down list
List<SelectListItem> AppNameList = PopulateDropDown(PortList);
model.ApplicationsList = AppNameList;
return View(SubmittedModel);
}
view (index.cshtml):
#model projectName.ApplicationsAddModel
#{ ViewData["Title"] = "Home Page"; }
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
#Html.LabelFor(m => m.selectedApplicationId)
#Html.DropDownListFor(m => m.selectedApplicationId, Model.ApplicationsList, "---", new { #class = "custom-select form-control" })
<input type="submit" value="submit" />
}
summary:
in MVC when you have to submit data to controller, create your model, go to controller and create your first action (GET) which fill the form with initial data and fill your drop down lists if exist, then create the (POST) action which receive the model of same type of the view and MVC will bind it automatically for you
best regards

How to handle form post from View Component (Razor Core 2)

This weekend a lot of struggle with a View Component.
I try to add a dropdownlist that does an auto postback onchange. This dropdownlist is on a view component.
I have 2 problems:
I don't get the asp-page-handler after the post, does it work like I implemented it on the form-tag?
Post calls method public void OnPost on razor page containing view
component. I would think it would be better to have a method on the
View Component like OnChangeProject?
The code of my View (View Component):
<form asp-page-handler="ChangeProject" method="post">
#Html.AntiForgeryToken()
#Html.DropDownList("id", new SelectList(Model, "Id", "Id"), new { onchange = "this.form.submit()" })
</form>
Thanks in advance!!
I exprienced the same problem and the way i fixed it is already answered in your question.
The form call is made at the page where you got your View Component embedded. I don't think it would be even possible to call a handler in your View Component with asp-page-handler as this is Razor Pages tag helper.
The way i got it work is simply putting the page-handler method on the PageModel that is embedding the View Component. In your case you can simply implement this handler on your Razor Page:
public IActionResult OnPostChangeProject()
{
// ... do Something
}
I don't know though how it would work to trigger a controller method in your View Component. Possibly create a new Controller class and route to it with asp-controller and asp-action in your form tag.
You should remember that the Page handlers could be viewed as convenience methods.
All the ASP.Net Core framework does is looks at the Query string parameters and Form data and translates it into Page handler calls.
And even though the Handlers are not available in View Components or Partial Views you still can get access to all the required ingredients by injecting IHttpContextAccessor into the View.
It will provide you with HttpContext.Request which contains both the Query and the Form properties.
You can then create your own Handler mapper. Here is one, for example:
public class HandlerMapping
{
public string Name { get; set; }
public System.Delegate RunDelegate { get; set; }
public HandlerMapping(string name, Delegate runDelegate)
{
RunDelegate = runDelegate;
Name = name;
}
}
public class PartialHandlerMapper
{
IHttpContextAccessor _contextAccessor;
public PartialHandlerMapper(IHttpContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
public void RouteHandler(List<HandlerMapping> handlerMappings, string PartialDescriminatorString = null)
{
var handlerName = _contextAccessor.HttpContext.Request.Query["handler"];
var handlerMapping = handlerMappings.FirstOrDefault(x => x.Name == handlerName);
if (handlerMapping != null)
{
IFormCollection form;
try
{
form = _contextAccessor.HttpContext.Request.Form;
}
catch
{
return;
}
if (!string.IsNullOrWhiteSpace(PartialDescriminatorString) && form[nameof(PartialDescriminatorString)] != PartialDescriminatorString)
return;
List<Object> handlerArgs = new List<object>();
var prmtrs = handlerMapping.RunDelegate.Method.GetParameters();
foreach (var p in prmtrs)
{
object nv = null;
var formValue = form[p.Name];
if (!StringValues.IsNullOrEmpty(formValue))
{
try
{
nv = TypeDescriptor.GetConverter(p.ParameterType).ConvertFromString(formValue);
}
catch (FormatException)
{
//throw new FormatException($"Could not cast form value '{formValue}' to parameter {p.Name} (type {p.ParameterType}) of handler {handlerName}. Make sure you use correct type parameter. ");
nv = Activator.CreateInstance(p.ParameterType);
}
catch (ArgumentException)
{
nv = Activator.CreateInstance(p.ParameterType);
}
}
else
nv = Activator.CreateInstance(p.ParameterType);
handlerArgs.Add(nv);
}
handlerMapping.RunDelegate.DynamicInvoke(handlerArgs.ToArray());
}
}
}
And inject it into the service container:
services.AddScoped<PartialHandlerMapper>();
And here is a shopping cart partial view code section example:
#inject ShoppingManager shoppingManager
#inject PartialHandlerMapper partialHandlerMappping
#{
string ToggleCartItemTrialUseHandler = nameof(ToggleCartItemTrialUseHandler);
string DeleteCartItemHandler = nameof(DeleteCartItemHandler);
List<HandlerMapping> handlerMappings = new List<HandlerMapping> {
new HandlerMapping (ToggleCartItemTrialUseHandler, (Guid? PicID, bool? CurrentValue) => {
if (PicID == null || CurrentValue == null)
return;
shoppingManager.UpdateTrial((Guid)PicID, !(bool)CurrentValue);
}),
new HandlerMapping (DeleteCartItemHandler, (Guid? PicID) => {
if (PicID == null)
return;
shoppingManager.RemoveProductFromCart((Guid)PicID);
})
};
partialHandlerMappping.RouteHandler(handlerMappings);
var cart = shoppingManager.GetSessionCart();
}
Form element example from the same view:
<td align="center" valign="middle">
<form asp-page-handler="#DeleteCartItemHandler">
<input name=PicID type="hidden" value="#i.PicID" />
<button>
Delete
</button>
</form>
</td>
Where #i is an Item in the shopping cart
It's possible to create a combo (Controller/ViewComponent) by decorating the controller with a ViewComponent(Name="myviewcomponent").
Then create the invokeasync as usual, but because the controller doesn't inherit from a ViewComponent, the return result would be one of the ViewComponent result (ViewViewComponentResult, et).
The form in the viewcomponent can then have a button with asp-controller/action tag helpers targetting the controller/action.

MVC5 Post data from partial view being used in main view

I have already tried many solutions available on web as per my understanding in context to this question but being new in MVC I am still unable to find a solution. Kindly help.
I have a view which is the home page of the website named as "Index.cshtml" and is situated under the following path:
WebsiteName/Areas/Website/Views/CypressHome/Index.cshtml
Secondly, I have a created a user trial form as partial view named as "_PartialHomeFormFreeTrial.cshtml" which is situated under the following path:
WebsiteName/Areas/Website/Shared/_PartialHomeFormFreeTrial.cshtml.
This form I have used inside my "Index.cshtml" as below:
<!--freetrialform-->
#Html.Partial("_PartialHomeFormFreeTrial")
<!--//freetrialform-->
Now, my partial page is posting data comprising of following elements:
#using (Html.BeginForm("Create", "Customer", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div>
#Html.EditorFor(model => model.CustomerName, new { htmlAttributes = new { #class = "input__field input__field--kuro" } })
#Html.ValidationMessageFor(model => model.CustomerName, "", new { #class = "text-danger" })
............
other fields such as email, phone, date, etc..
<input type="submit" id="" value="SEND REQUEST" />
</div>
}
Now, I have created a controller named "CustomerController" which has the following code to save the data of the form as used as partial view in the main view "Index.cshtml":
public class CustomerController : Controller
{
private WebsiteContext db = new WebsiteContext();
// GET: Website/Customer
public ActionResult Index()
{
return View();
}
// GET: Website/Customer/Create
public ActionResult Create()
{
ViewBag.StatusPlanID = new SelectList(db.StatusPlans, "StatusPlanID", "Status");
return View("Index");
}
// POST: Website/Customer/Create
[HttpPost]
public ActionResult Create([Bind(Include = "CustomerID,CustomerName,CustomerEmail,CustomerPhone,DateOfRegistration,StatusPlanID")] Customer customer)
{
if (ModelState.IsValid)
{
db.Customers.Add(customer);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.StatusPlanID = new SelectList(db.StatusPlans, "StatusPlanID", "Status", customer.StatusPlanID);
return View(customer);
}
}
I have tried many changes in my controller, return in the views and
many other things but I am getting the same error always. Neither the
validations are working nor the validated data is getting saved.
The error is as below:
Server Error in '/' Application.
The view 'Create' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Areas/Website/Views/Customer/Create.aspx
~/Areas/Website/Views/Customer/Create.ascx
~/Areas/Website/Views/Shared/Create.aspx
~/Areas/Website/Views/Shared/Create.ascx
~/Views/Customer/Create.aspx
~/Views/Customer/Create.ascx
~/Views/Shared/Create.aspx
~/Views/Shared/Create.ascx
~/Areas/Website/Views/Customer/Create.cshtml
~/Areas/Website/Views/Customer/Create.vbhtml
~/Areas/Website/Views/Shared/Create.cshtml
~/Areas/Website/Views/Shared/Create.vbhtml
~/Views/Customer/Create.cshtml
~/Views/Customer/Create.vbhtml
~/Views/Shared/Create.cshtml
~/Views/Shared/Create.vbhtml
And the url is changing as below:
1. On running the system initially: http://localhost:53872/
2. On clicking on submit: http://localhost:53872/Areas/Website/Customer/Create along with the
error as stated above.
For more information my WebsiteAreaRegistration.cs file contains the below code:
public class WebsiteAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Website";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Website_home",
"",
new { controller = "CypressHome", action = "Index", id = UrlParameter.Optional }
);
context.MapRoute(
"Website_default",
"Areas/Website/{controller}/{action}/{id}",
new { controller = "CypressHome", action = "Index", id = UrlParameter.Optional }
);
}
}
Though I have understood the problem but unable to figure out. Kindly help.
In your code last return statement is return View(customer). That's means after POST data it return a View (using HTTP GET method) as same name as Action that's Create. But your description you have a Create Action but you have no view page.
So please create a Create.cshtml with a Model corresponding customer Object.
Or change the return statement.
Based on your comment you can follow this Change.
1.Remove
public ActionResult Create()
{
ViewBag.StatusPlanID = new SelectList(db.StatusPlans, "StatusPlanID", "Status");
return View("Index");
}
2.then change
public ActionResult Index()
{
ViewBag.StatusPlanID = new SelectList(db.StatusPlans, "StatusPlanID", "Status");
return View(new Customer());
}
3.in Index.cshtml
#Model Customer
#Html.Partial("_PartialHomeFormFreeTrial",Model)
4.Then
return View("Index",customer);

ASP.NET Cross session list

I'm attempting to make a simple page that will compare multiple form submissions.
I have a html page with a form, and a for-loop that generates a div for each item in a list of form submissions. The list is passed from the controller. I am trying to maintain the list in the controller rather than rely on a database.
When I try to resubmit the form, which should add another object to the list, the list re initializes.
In debugging, I see that the list is empty when the form gets submitted. I'm unsure as to the correct terminology, but it seems that the list is emptied whenever the view is rendered. Is there a way to maintain list contents?
I know there are better ways to do this, and welcome any advice. I'm still learning, so pleas go easy.
Thanks!
This is the simplified controller.
namespace MvcApplication2.Controllers
{
public class HomeController : Controller
{
List<paymentPlan> plansList = new List<paymentPlan>();
public ActionResult Index()
{
return View(plansList);
}
[HttpPost]
public ActionResult Index(FormCollection collection)
{
paymentPlan Project = new paymentPlan();
Project.customerName = Convert.ToString(collection["customerName"]);
plansList.Add(Project);
return View(plansList);
}
}
}
This is my simplified view.
#model List<MvcApplication2.Models.paymentPlan>
#using (Html.BeginForm("index", "home", FormMethod.Post, new { Id = "signupForm" }))
{
<label for="customerName">Customer Name:</label>
<input type="text" name="customerName" class="form-control required" />
#Html.ValidationSummary(true)
<input type="submit" value="Calculate" class="btn btn-primary" />
}
#{
bool isEmpty = !Model.Any();
if (!isEmpty)
{
foreach (var i in Model)
{
<div>
Name: #i.customerName
</div>
}
}
}
This is my simplified model.
namespace MvcApplication2.Models
{
public class paymentPlan
{
public string customerName { get; set; }
}
}
I think that's a question of controller and asp.Net MVC lifecycle !
A controller lifetime is the same as the request, for each request a new controller is created and once the work is done it's disposed!
So try to remove this List<paymentPlan> plansList = new List<paymentPlan>(); and work with TempData[] or ViewData[] or Session[] like this :
Controller
public class HomeController : Controller
{
public ActionResult Index()
{
Session["plansList"] = ((List<paymentPlan>)Session["plansList"])!=null? (List<paymentPlan>)Session["plansList"] : new List<paymentPlan>();
return View((List<paymentPlan>)Session["plansList"]);
}
[HttpPost]
public ActionResult Index(FormCollection collection)
{
paymentPlan Project = new paymentPlan();
Project.customerName = Convert.ToString(collection["customerName"]);
((List<paymentPlan>)Session["plansList"]).Add(Project);
return View(plansList);
}
}
check this : http://www.asp.net/mvc/overview/getting-started/lifecycle-of-an-aspnet-mvc-5-application

How to get the selected value from the drop down list in MVC 4 and assign that value to another local variable for comparison variable

My Razor View
I want to get the selected value of securityReq_C
#{
var listItems = new List<System.Web.UI.WebControls.ListItem>
{
new System.Web.UI.WebControls.ListItem{Text ="1",Value="1"},
new System.Web.UI.WebControls.ListItem{Text ="2",Value="2"},
new System.Web.UI.WebControls.ListItem{Text ="3",Value="3"}
};
}
#Html.DropDownListFor(x => x.addasset.securityReq_C, new SelectList(listItems, "Value", "Text"), "N/A", new { id = "selectError6", onchange = "getAlldata()" }
You need to have this list on your model and bind the list to your dropdownListFor. You also need to "submit" this somehow i dont know if you use html.BeginForm or ajax.beginform or some other submit function but you will requier to submit the values somehow to your controller. Last but not least you need some function in your Controller to deal with the post from your form or whatever you send back to the controller.
VIEW
using (Ajax.BeginForm("ACTION", "CONTROLLER", new AjaxOptions()
{
HttpMethod = "POST",
OnBegin = "",
OnComplete = "",
UpdateTargetId = "TargetDivToBeUpdated"
}))
{
//Your dropdown Goes inside form
};
CONTROLLER
[HttpPost]
public ActionResult ACTION(MODEL)
{
//Logic
}
MODEL
public class YoURViewModeL
{
public YOuRList { get; set; }
}