ASP MVC 6: sending multiselectselect as POST - asp.net

I have a view in my app, that allows user to set up 2 multiselects.
The problem is: how can I send contents of those multiselects back to controller.
So far I have:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<div id="member-list">
<div class="row" id="transfer">
<div class="col-md-6">
<select multiple="multiple" id="right-select">
#foreach (var item in Model.AnotherContacts)
{
<option value="#item.Id" onclick="transfer(this)">
#item.Email - #item.Name
</option>
}
</select>
</div>
<div class="col-md-6">
<select multiple="multiple" id="left-select">
#foreach (var item in Model.Group.Members)
{
<option value="#item.Contact.Id" onclick="transfer(this)">
#item.Contact.Email - #item.Contact.Name
</option>
}
</select>
</div>
</div>
</div>
<div class="col-md-3">
<input type="submit" class="btn btn-grey" value="Save" />
</div>
</div>
And now: how to write a controller to have there list of items, hat I have in both multiselects?
[HttpPost]
public ActionResult Manage(int id)
{
return View();
}

Well first for a form post to be successful you need to add name attributes to your inputs.
<select multiple="multiple" id="left-select" name="leftSelect">
<select multiple="multiple" id="right-select" name="rightSelect">
Then your controller would be
[HttpPost]
public ActionResult Manage(int[] leftSelect, int[] rightSelect)
{
//your code
return View();
}
Notice the names of method parameters are the same as the name attributes on the select lists.
Note: I assumed your #item.Contact.Id and #item.Id are of type
int.

Make your controller expect several parameters
[HttpPost]
public ActionResult Manage(int id, int id2)
{
//your code
return View();
}
This of course depends on what you want to send to to the controller, but I hope you get the idea. You havent shown the code required, but I would guess you have selectLists that return strings, and if that is the case, change the parameters in the Manage Action to expect string variables

Related

Error when Search() Action Method returns Index View()

I have a Search Form which goes to my Search() action method within my Home Controller. and returns View("Index")
Search() method:
public IActionResult Search(SearchQuery FormData)
{
List<Flight> flights = new List<Flight>();
flights = (from flight in _context.Flights
where flight.FlightDateTime.Date == FormData.PreferredFlightTime.Date
&& flight.ArrivalAirportId == FormData.ArrivalAirportId
&& flight.DepartureAirportId == FormData.DepartureAirportId
select flight).ToList();
ViewBag.FlightSearchResults = flights;
return View("Index");
}
Upon the initial load of the homepage it works fine when loading my Index() method and returning the view.
public IActionResult Index()
{
HomeViewModel mymodel = new HomeViewModel();
mymodel.Airports = GetAirports();
return View(mymodel);
}
However once the search form is submitted and the Search() action method is called, when the method returns return View("Index"); the page will not load due System.NullReferenceException: 'Object reference not set to an instance of an object.'
The above exception is thrown when it reaches #foreach (Airport airport in Model.Airports)
Search form:
#using FlightBooker;
#model FlightBooker.Models.HomeViewModel;
<form asp-controller="Home" asp-action="Search" method="post">
<div class="form-group">
<label for="fromAirport">Flying from:</label>
<select name=" {DepartureAirportId" class="form-control">
#foreach (Airport airport in Model.Airports)
{
<option value="#airport.AirportId">#airport.AirportCode</option>
}
</select>
<div class="form-group">
<label for="toAirport">Flying to:</label>
<select name="ArrivalAirportId" class="form-control">
#foreach (Airport airport in Model.Airports)
{
<option value="#airport.AirportId">#airport.AirportCode</option>
}
</select>
</div>
<label for="fromAirport">Departure Date:</label>
<br />
<input type="date" / id="date" name="PreferredFlightTime">
<br />
<label for="fromAirport">No. passengers:</label>
<select class="form-control" name="TotalPassengers">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
</select>
<button type="submit" class="btn btn-primary mt-3">Search Flights</button>
</div>
</form>
Comment from Codecaster above solved this. I updated my Search() action method passing the model to the Index view and repeating the code in my index method.
Updated Search() action method:
public IActionResult Search(SearchQuery FormData)
{
List<Flight> flights = new List<Flight>();
flights = (from flight in _context.Flights
where flight.FlightDateTime.Date == FormData.PreferredFlightTime.Date
&& flight.ArrivalAirportId == FormData.ArrivalAirportId
&& flight.DepartureAirportId == FormData.DepartureAirportId
select flight).ToList();
ViewBag.FlightSearchResults = flights;
HomeViewModel mymodel = new HomeViewModel();
mymodel.Airports = GetAirports();
return View("Index", mymodel);
}

Create Form in ASP.NET

i'm working on an ASP.NET web applications and i don't know how to get the value from my form and how to launch a method on my controller from a view.
This is my View :
`<h1 style="text-align:center">Authentification</h1>
<div class="row">
<div class="col-md-8">
<section id="loginForm">
<div class="form-horizontal" style="text-align:right">
<h4>Veuillez saisir vos identifiants</h4>
<div class="form-group">
<div class="col-md-10">
<input type="text" placeholder="Saisir ici votre login" size="40" runat="server" ID="UserName" name="login" CssClass="form-control" />
</div>
</div>
<div class="form-group">
<div class="col-md-10">
<input type="password" placeholder="Saisir ici votre mot de passe" size="40" runat="server" ID="Password" name="mdp" TextMode="Password" CssClass="form-control" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="TestConnexion" class="submit" />
</div>
</div>
</div>
</section>
</div>
`
This is the controller containing the method i would like to use from my Form situated in my view
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.UI.WebControls;
namespace PhoneTeleX.Controllers
{
public class ConnexionController : Controller
{
String login;
String mdp;
public ConnexionController()
{
}
public ConnexionController(String login, String mdp)
{
this.login = login;
this.mdp = mdp;
this.TestInfoConnexion(login, mdp);
}
private void TestInfoConnexion(String login, String mdp)
{
DAOConnexionController monDAOConnexion = new DAOConnexionController(login, mdp);
if (monDAOConnexion.testInfoConnexion(login, mdp))
{
// FrmChoix frm = new FrmChoix();
//frm.Show();
//frm.getNomLogin(login);
//GSBFormConnexion.ActiveForm.Close();
}
else
{
Console.WriteLine("Connexion impossible, veuillez vérifier votre login et/ou votre mot de passe");
}
}
}
}
For the moment i can't launch any action from my input button and i dont kkow why.
Can you help me ?
Open the form by rendering the View (Index.cshtml file in the example below).
Action to display form in ConnexionController:
[HttpGet]
public ActionResult Index() {
var viewModel = new MyIndexViewModel();
// do database access, put retrieved data into ViewModel ...
return View("Index", viewModel);
}
The <form> tag is rendered by the "Index.cshtml" view and will be submitted to the specified action after the "Submit" button is clicked.
Index.cshtml:
#model MyIndexViewModel
#using (Html.BeginForm("Index", "Connexion", FormMethod.Post)) {
#* Show validation errors, if any *#
#Html.ValidationSummary()
#* Use MVC EditorFor to render the inputs *#
#Html.EditorFor(m => m.Login)
#Html.EditorFor(m => m.Password)
<button type="submit">Submit</button> #* This will submit the form *#
}
After the form was submitted, you will hit the POST Index action in ConnexionController:
[HttpPost]
public ActionResult Index(MyIndexViewModel postdata) {
// validate submitted data
if (!ModelState.IsValid) {
// show form again with validation errors
return View("Index", postdata);
}
// process the submitted data ...
var submittedLogin = postData.Login;
// on success
return new HttpStatusCodeResult((int) HttpStatusCode.OK); // HTTP 200
}
Note that web applications do not work in the same way as Windows Forms applications because the different steps run on different computers (server/client). You will benefit from working through the tutorial: Getting Started with ASP.NET MVC 5.

How to post table rows data to a controller w/o using ajax in asp.net core

What is want to achieve is I have a form to adds rows with data to a html table, it's like a temporary table and all the data from it will be added in just one submit button. How can I possibly do this?
This is my sample table structure, data from it must be added to db
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<table class="table">
<thead>
<tr>
<!--some other fields-->
<th>Amount</th>
<th>Check #</th>
<th>Check Date</th>
</tr>
</thead>
<tbody>
<tr>
<!--some other fields-->
<td>
<input asp-for="Amount" class="form-control" />
<span asp-validation-for="Amount" class="text-danger"></span>
</td>
<td>
<input asp-for="Check_No" class="form-control" />
<span asp-validation-for="Check_No" class="text-danger"></span>
</td>
<td>
<input asp-for="Check_Date" class="form-control" />
<span asp-validation-for="Check_Date" class="text-danger"></span>
</td>
</tr>
<!--row 2-->
<!--row 3-->
<!--row 4-->
<!--etc..-->
</tbody>
</table>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
And here is my controller code so far, i don't know what do I need to change
// POST: Books/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Year,Month,Document_Code,GLA_Code,Expense_Code,Function_Code,Document_Reference_No,Document_Date,Quantity,Amount,Check_No,Check_Date,Remarks,Encoder")] Book book)
{
if (ModelState.IsValid)
{
_context.Add(book);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(book);
}
What must needed to be change in my view and controller, and help will is appreciated.
Thank you.
There's a couple of issues here.
First, if you've got a table of "books" (plural), the input names need to be indexed. You then also need to accept something like List<Book> instead of Book as the param to your action method. It's a little hard to tell with just the code provided, but I'd imagine you're repeating these inputs, all with the same names for each row. If that's the case, only the values for the last item will be posted. Making it a list of items enables you to post them all.
Simplistically, that means your inputs need to have names like [0].Amount, which Razor will generate for you if you use a for loop and render the inputs like:
<input asp-for="#Model[i].Amount" class="form-control" />
If you're adding the additional rows (and contained inputs) via JavaScript, you'll need to ensure that you're generating these indexed names properly yourself. A JS templating library may help in this regard.
Second, do not use Bind. Just don't. It's awful, horrible, and kills both puppies and kittens. For more explanation see my post, Bind is Evil. Use a view model instead. As a general rule you should never post an entity class. Your entity classes serve the database and its concerns, which are almost always different from the concerns of the view. Additionally, you should never just blindly save something posted by a user. Even if you insist on using your entity class to bind to, you can improve the security and safety of your code exponentially by literally mapping the values from the posted version of the class over to a new instance you create. Then, you know exactly what is being persisted to the database (without the godforsaken Bind) and you also have the opportunity to sanitize input as necessary.
I was facing a similar problem, but using ASP.NET Core 3.1 and Razor Pages. I was looking for a way to add and remove rows from a table with JavaScript, and then post it. My problem was to post the table without Ajax. Based in the question and in the accepted answer, I could do that.
Here is Index.cshtml.cs:
public class IndexViewModel {
public string Name { get; set; }
public IList<ResourceViewModel> Resources { get; set; }
}
public class ResourceViewModel {
public string Key { get; set; }
public string Value { get; set; }
}
public class IndexModel: PageModel {
[BindProperty]
public IndexViewModel ViewModel {get; set; }
public void OnGet() {
// You can fill your ViewModel property here.
}
public void OnPost() {
// You can read your posted ViewModel property here.
}
}
Here is Index.cshtml:
#page
#model IndexModel
#{
ViewData["Title"] = "Index";
}
<form method="post">
<div class="form-group">
<label asp-for="ViewModel.Name"></label>
<input asp-for="ViewModel.Name" class="form-control" />
</div>
<div class="form-group">
<table class="table">
<thead>
<th>Key</th>
<th>Value</th>
</thead>
<tbody>
#for(int i = 0; i < Model.ViewModel.Resources.Count; i++) {
<tr>
<td>
<input asp-for="ViewModel.Resources[i].Key" type="hidden" />
#Model.ViewModel.Resources[i].Key
</td>
<td>
<input asp-for="ViewModel.Resources[i].Value" type="hidden" />
#Model.ViewModel.Resources[i].Value
</td>
</tr>
}
</tbody>
</table>
</div>
<button type="submit" class="btn btn-primary">Send</button>
</form>
Notice I've used type="hidden" because I didn't want the user to edit the table directly.
I hope you find this useful!

Use drop down result to filter another dropdown C# MVC

I am trying to update a drop down based on the users selection in the first drop down. I found this SO post on the topic, but Im not quite sure how to add the jquery to filter values to my Razor view. Can someone point me in the right direction?
My view so far:
#using System.Security.Claims;
#model UpdateClaimFormModel;
<h2>UpdateClaimView</h2>
#using (#Html.BeginForm())
{
<select name="emailcheese">
<option selected disabled>Select User</option>
#foreach (var i in Model.UserNames)
{
<option>#i.ToString()</option>
}
</select>
<select name="authpolicy">
<option selected disabled>Select Claim:</option>
#foreach (var i in Model.UserClaims)
{
<option>#i.Type.ToString()</option>
}
</select>
<div class="form-group">
<button type="submit" class="btn btn-default">Whoo</button>
</div>
}
My Goal:
Select User [bob, bill, jim]
Select Claim: If user bob:[1,2,3], If user bill:[1,4,8], If user him:[4,5,6]
so simpley you can do something like this
#using (#Html.BeginForm())
{
<select name="emailcheese" id="selectUserNames">
<option selected disabled>Select User</option>
#foreach (var i in Model.UserNames)
{
<option>#i.ToString()</option>
}
</select>
<select name="authpolicy" id="selectAuthPolicy">
</select>
<div class="form-group">
<button type="submit" class="btn btn-default">Whoo</button>
</div>
}
now in the script part
$(function(){
var userClaims = #Html.Raw(Json.Encode(Model.UserClaims));
$(document).on('change','#selectUserNames'function(){
var selectedVal = $(this).val();
if(selectedVal == 'bob')
{
var html ='<option selected disabled>Select Claim:</option>';
for(var i=1;i<userClaims.length;++i)
{
if(i==1||i==2||i==3)
{
html=html+'<option>'+userClaims[i].Type+'</option>';
}
}
$('#selectAuthPolicy').html(html);
}
})
})
this is just a basic dea of how you can achieve this i just tried for bob there are many other ways to immplement ths

Return Different Views From MVC Controller

I've a MVC application, whose SharedLayout view(Master Page) gives user capability to search. They could search their order by Order No or By Bill no. So there are two option buttons the Shared View along with the textbox. Code is somewhat like this
#using (Html.BeginForm("Track", "Tracking", FormMethod.Post))
{
<div style="text-align: center">
<textarea cols="20" id="txtNo" name="txtOrderNo" rows="2" ></textarea>
</div>
<div style="text-align: center">
<input type="radio" name="optOrderNo" checked="checked" value="tracking" />Order No <input type="radio" name="optRefNo" value="tracking" />Ref No
</div>
<div style="text-align: center">
<input type="submit" value="Track" />
</div>
}
So it'll go to TrackingController and Track Method in it and return the view. It works fine for a single search as a View is associated with a controller's methods. It works fine but how could i conditionally return the other view based on the radio button selection.
What i come up with is this
[HttpPost]
public ActionResult Track(FormCollection form)
{
string refNo = null;
if (form["optRefNo"] == null)
{
string OrderNo = form["txtOrderNo"];
var manager = new TrackingManager();
var a = manager.ConsignmentTracking(OrderNo);
var model = new TrackingModel();
if (OrderNo != null)
model.SetModelForConsNo(a, consNo);
return View(model);
}
refNo = form["txtConsNo"];
return TrackByRef(refNo);
}
public ActionResult TrackByRef(string refNo)
{
//what ever i want to do with reference no
return View();
}
Kindly guide.
Thanks
View has an overload where the first parameter is a string. This is the name (or path) to the view you want to use, rather than the default (which is a view that matches the action's name).
public ActionResult TrackByRef(string refNo)
{
//what ever i want to do with reference no
return View("Track");
// or, if you want to supply a model to Track:
// return View("Track", myModel);
}

Resources