I have 2 ASP.NET MVC action methods, I call the first method by passing and load some initial data, then I get some additional details from UI and call the second action method (Post action method from .cshtml). The data I received from the first call is missing in the post method. can anyone help me what am I doing wrong or missing here?
Action methods:
[Route("setprofile")]
public ActionResult SetProfile(string id)
{
ProfileData data = new ProfileData();
//do something
data.name= getData(id);
return this.View(data);
}
[Route("setprofile")]
[HttpPost]
public ActionResult SetProfile(ProfileData data)
{
// Here I'm not missing the data.name field value
}
View .cshtml file:
<div class="panel-body">
#using (Html.BeginForm("SetProfile", "Home", FormMethod.Post))
{
<div>
<h3> Name: #(this.Model.name)</h3>
</div>
<h3>
Comments:#Html.TextBoxFor(m => m.comments)
</h3>
}
I get the comments value but not getting the name field value from the model here.
Note: I need to display the value I received from the first action method as a label, not text box.
There are two things, Name is writen as text and in order to send back to server, you need to put it inside input element.
IF you dont want to show it #Html.HiddenFor(m => m.name) creates hidden input element.
Other than this, check ModelState for validation errors..
if (!ModelState.IsValid)
return BadRequest(ModelState);
.... your code here
if your model is not valid, the ProfileData returns result
You haven't added an input element for it to be sent back to the server when the form is submitted. If you don't want it to be visible, whilst still being posted back, add a hidden field for it:
#Html.HiddenFor(m => m.name)
Without that, all you're doing is rendering name to the markup but, once the form is submitted, it won't be sent back. Alternatively, you could render a textbox for the value whilst setting its readonly attribute. That would allow it to be visible, not changed, and still be sent back to the server.
#Html.TextBoxFor(m => m.name, new { #readonly = "readonly" })
Related
I have two <slect> list and I want to pass only Text to the controller. I don't know if its possible.
This is Html :
<form asp-action="Crea" method="post">
<select asp-for="Azienda_cliente" class="select2 form-control" id="ddlClienti" onchange="LoadSottoCliente(value)"></select>
<select asp-for="Azienda_sotto_clienti" class="select2 btn-block" id="ddlSottoClienti"></select>
<input type="submit" value="Crea" class="w-50 btn btn-success" />
</form>
And this is controller:
[HttpPost]
public async Task<IActionResult> Crea(Attiivita attivita)
{
if (ModelState.IsValid)
{
_db.Add(attivita);
await _db.SaveChangesAsync();
return RedirectToAction("Index");
}
return View();
}
Is it possible to post only Text from the select list?
Any suggestions how to do that?
Thanks in advance!
I have two <select> list and I want to pass only Text to the controller.
In your form, when you submit the form, the Value of the selected option would be posted to controller action method.
If you'd like to post Text of the selected option to controller action, you can try following two approaches:
Approach 1: populate your dropdown(s) with expected data as Value property.
<select asp-for="Azienda_cliente" asp-items="ViewBag.ClientItems" class="select2 form-control" id="ddlClienti" onchange="LoadSottoCliente(value)"></select>
In action method
ViewBag.ClientItems = new List<SelectListItem>
{
//normally we populate Value property with Id etc field
//in your code logic, you can populate it with your expected data (same as you set for Text property)
new SelectListItem { Value = "ClientName", Text = "ClientName" },
//...
//other items
};
For the second dynamic dropdown, you can set Value property with same data as Text of each <option>.
$("select#ddlSottoClienti").append(`<option value="${text_here}">${text_here}</option>`);
Approach 2: you can get text of the selected option(s), then submit data using jQuery Ajax etc on JavaScript client side.
$("input[type='submit']").click(function (ent) {
ent.preventDefault();
var Azienda_cliente = $("select#ddlCLienti option:selected").text();
var Azienda_sotto_clienti = $("select#ddlSottoClienti option:selected").text();
//make ajax request to your controller action
//...
})
Imagine a simple form that takes an email input like this:
#using (Html.BeginForm("save", "email", FormMethod.Post, new { #id = "my__form" }))
{
<div class="field">
#Html.LabelFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
#Html.TextBoxFor(model => model.Email, new { #placeholder = "Enter your email", #type = "email" })
</div>
<button type="submit" class="btn">Save email</button>
<div class='spinner'></div>
}
The spinner is not displayed initially (CSS):
.spinner {
display: none;
}
On form submit I show a spinner on the page:
$('.btn').on("click", function (event) {
event.preventDefault();
$('#my__form').submit();
$('.spinner').show();
});
My action is as follows:
[HttpPost]
[Route("email")]
public ActionResult Save(EmailViewModel model)
{
if (ModelState.IsValid)
{
//Do stuff with email
return RedirectToAction("action", "contoller");
}
return View(model);
}
Think of the above as pseudo-code that represents a more generic issue.
If a model state is invalid and the UI is updated in some way (in this case showing a spinner), what's the pattern or mechanism to reset the form?
For clarity, I am not talking here about standard data validation etc. I've tried having a hidden input on the form that I can populate using ModelState.AddModelError("spinner", false) and then acts as a 'switch' that javascript can read and then hide the spinner. This feels like a hack.
It feels like this is a common problem to which there is a common solution?
The hack you mentioned is really how it would be done using normal ASP.NET MVC.
There can be different implementations, such as storing the flag in a ViewBag instead. But the idea is the same.
You might be better off posting the form via AJAX, whose result might include a success flag and/or a list of validation errors. You can then manipulate the DOM in the submit handler via JavaScript based on this result.
This is my View:
#model test2.Models.ChatModel
#{
ViewBag.Title = "Channel";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<center>
<h2>Channel: #Model.channelName</h2>
#{
foreach (string line in Model.chatLog) {
<div>#line</div>
}
}
<br />
#using (Html.BeginForm("sendMessage", "Home", FormMethod.Post)) {
#Html.TextBoxFor(model => model.message)
<button type="submit"> Send Message </button>
}
</center>
Here is my Controller:
public ActionResult sendMessage(ChatModel model) {
//send message somewhere
//this is not working
return RedirectToAction("Channel", "Home", new { channel = model.channelName });
//this is working
return RedirectToAction("Channel", "Home", new { channel = "test" });
}
The error happens in the redirectToAction method. Somehow "model.channelName" is empty, but #Model.channelName in my view is correctly displaying the channel name.
It looks like when you send a Model to a view, and "resend" this model back to a controller, the informations are lost.
Is there an easy way to solve this?
PS Step by step:
Model gets channelName
Model is send to view
View correctly displays data from model
adding message to Model
sending model to controller
model does NOT contain information from step 1
You need to include model.channelName in the form. Try adding a:
#Html.HiddenFor(model => model.channelName)
Anything not posted by the form, will be null in your model (including your chatlog)
Actually the values model properties should be rendered as input elements within the form that is posted back to controller action. The properties which are not included would loose their values.
What you can do is create a hidden field for those to post :
#using (Html.BeginForm("sendMessage", "Home", FormMethod.Post)) {
#Html.TextBoxFor(model => model.message)
#Html.HiddenFor(model => model.channelName)
<button type="submit"> Send Message </button>
}
You would need to add same way other properties too that are posting null at action and you need those for some processing.
Hope it helps.
So what I have is a HTML-Form enabling the user to register for sportsevents. The user can register different profiles (e.g. his children) and every event can potentially have so called "Additional Attributes" like textboxes for T-Shirt-size etc.
#model Models.EventRegistrationModel
#{
Layout = null;
var playerCount = Model.PlayersToRegister.Count;
}
#using (Html.BeginForm("RegisterForEvent", "Event", FormMethod.Post)){
#Html.AntiForgeryToken()
<div class="form-group">
#for (int i = 0; i < playerCount; i++)
{
<div>
<p>#Model.PlayersToRegister[i].User.FullName</p>
</div>
<div
#Html.CheckBoxFor(model => Model.PlayersToRegister[i].PlayerShallGetRegistered)
</div>
//this is the "Additional Attributes"-section for each user-profile
#Html.Raw(Model.PlayersToRegister[i].Form.RenderHtml())
}
</div>
<input type="submit" value="Confirm Registration"/>
}
Since I do not create those events, I cannot know, what these "Additional Attributes" look like, which is why they are rendered dynamically using DynamicForm.
My problem is that I cannot access the user-input for those attributes in the controller. When I check the browser's console, I see the input being posted, but checking the dynamic form's value, it always says "null".
Here's my controller:
[HttpPost, ValidateAntiForgeryToken]
public ActionResult RegisterForEvent(EventRegistrationModel model)
{
for (int i = 0; i < playerList.Count; i++)
{
var form = Session["Form" + i] as Form;
model.PlayersToRegister[i].Form = form;
//var test = form
//var testtest = test.GetResponses(false);
}
return RedirectToAction("EventOverview");
}
As you can see, I tried to use the Form's "GetResponses"-Method, but it returned null.
public List<Response> GetResponses(bool completedOnly)
{
return InputFields.OrderBy(inputField => inputField.DisplayOrder).Select(field => new Response
{
Title = field.Title, Value = field.Response
}).Where(response => !completedOnly || !String.IsNullOrEmpty(response.Value)).ToList();
}
At the moment I am trying to get the values via Session, as this worked in an older version, where you were only able to register one profile at a time. The Session-variable gets assigned in the ActionResult returning the above View.
I've been trying various solutions from various threads over the past days (e.g. ModelState.Clear), but unfortunately nothing has been successful.
If you need more information, code or whatever, please let me know.
Since your form is dynamic you may want to use a dynamic model in the post method. Try something like this:
[HttpPost, ValidateAntiForgeryToken]
public ActionResult RegisterForEvent(FormCollection collection)
{
// stuff....
}
You'll have to do a bit of work parsing out the collection that comes in but it should have everything that was posted from the form. In general I don't recommend this as it can really spiral out of control. Having a well defined view model (as you did in the original posting) is much better in general. However, sometimes you really need something dynamic and this gets the job done.
I have a basic MVC form which is accessed through a GET Action with 3 string parameters pulled from the route.
[HttpGet]
public ActionResult Application(string x, string y, string z)
{
//create model, setup form, etc...
return View(model);
}
The route to access this form is configured as follows:
routes.MapRoute("Application",
"application/{x}/{y}/{z}",
new
{
controller = "Application",
action = "Application",
x = "",
y = "",
z = ""
});
And the form is configured as follows:
Html.BeginForm("Application", "Application", FormMethod.Post)
All of this works until I click submit on the resulting form. From a routing perspective the correct POST Action is called and the Model is bound correctly. The problem is I have lost all the x/y/z route information which I still need. How can I preserve the route information?
I've tried a couple things:
Added route details to the Form in Hidden fields which are added to the form content correctly but never get returned in the Model on postback
Tried using the RouteValueDictionary overload for Html.BeginForm but can't figure out how to make it work. I may just need a proper example of how to use it and how to access the state from the Controller
Update: This adds View sample to help address comments made regarding the use of Hidden Fields
#using (Html.BeginForm("Application", "Application", FormMethod.Post, new
{
autocomplete = "on",
id = "LoanApplication",
novalidate = string.Empty,
name = "Application"
}))
{
<fieldset>
#Html.HiddenFor(m => m.x)
#Html.HiddenFor(m => m.y)
#Html.HiddenFor(m => m.z)
#Html.HiddenFor(m => m.DigiCertId)
<br />
<input id="SubmitButton" type="submit" value="#Resources.SubmitApplicationButton" title="#Resources.SubmitApplicationButtonDescription" />
</fieldset>
}
You should really put these properties in the model, then have a HiddenFor for each one, like so:
#Html.HiddenFor(m => m.x)
#Html.HiddenFor(m => m.y)
#Html.HiddenFor(m => m.z)
Then in your post method (assuming it's like this), you can pass them in the RouteValueDictionary to the Get Method, like so:
[HttpPost]
public ActionResult Application(MyModel model) //whatever type your model is
{
//do whatever your post method does before redirect
return RedirectToAction("Application", new { x = model.x, y = model.y, z = model.z});
}
in addition to the ans suggested by mattytommo. i would recommend using TempData collection in asp.net MVC. this saves the data using the session storage but does it temprorarily and the data gets deleted once you access it.
this is present specifically for these purposes
so you can save the data in TempData as TempData["Values"] = new {X=x,Y=y,Z=z};
then access the TempData["Values"] after the post