Hi I'm trying to make a Razor page with a simple form that add the new element into a list, but the OnPost() method is never calling. I have a breakpoint on the first line of the method and it never hits, but in the OnGet() it works.
This is my OnPost() method:
public void OnPost()
{
newDocument = Int32.Parse(Request.Form[nameof(newDocument)]);
newAge = Int32.Parse(Request.Form[nameof(newAge)]);
newTriage = (Triage)Int32.Parse(Request.Form[nameof(newTriage)]);
newName = Request.Form[nameof(newName)];
newGender = Request.Form[nameof(newGender)];
newSymptoms = Request.Form[nameof(newSymptoms)];
var newPatient = new Patient
{
Document = newDocument,
Name = newName,
Age = newAge,
Gender = newGender,
Triage = newTriage,
Symptoms = newSymptoms
};
patients.Add(newPatient);
OrderPatients();
}
And the razor page have this form:
<form>
<div class="form-group">
<label for="patientDoc">Documento</label>
<input asp-for="newDocument" type="number" class="form-control" id="patientDoc" placeholder="ingrese documento">
</div>
<div class="form-group">
<label for="patientName">Nombre</label>
<input asp-for="newName" type="text" class="form-control" id="patientName" placeholder="Nombre">
</div>
<div class="form-group">
<label for="patientAge">Edad</label>
<input asp-for="newAge" type="number" class="form-control" id="patientAge" placeholder="Edad">
</div>
<div class="form-group">
<label for="patientGender">Género</label>
<input asp-for="newGender" type="text" class="form-control" id="patientGender" placeholder="Género">
</div>
<div class="form-group">
<label for="patientTri">Prioridad</label>
<select asp-for="newTriage" class="form-control" id="patientTri">
#foreach (Triage tri in Enum.GetValues(typeof(Triage)))
{
<option>#tri</option>
}
</select>
</div>
<div class="form-group">
<label for="patientSymp">Sintomas</label>
<input asp-for="newSymptoms" type="text" class="form-control" id="patientSymp" placeholder="Sintomas">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
I have read that you have to put this line #addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers at the beginning of the page, but I did it and still the OnPost doesn't hit.
Anyone knows what is wrong?
The default method type for form is GET, so it hits your OnGet handler because you didn't specify the method. Change <form> to <form method="post"> and it should work.
Forget it. I just had to add the method="form" at the beginning of the form like this:
<form method="post">
. . .
</form>
Gonna leave this around here for another newbie like me who might need it.
Related
I am developing my first web application with ASP.NET Core 6, and I have a form that shows some fields that I already have information inside of my database.
The problem is: these fields needs to be read-only, because my user needs to considerate the information from my database. If is null, then he needs to insert a value.
Here is an example (consider the field with already set readonly). Most of fields will need this code:
<div class="form-group row">
<div class="col-3">
<label for="Renda Bruta">Associado Desde:</label>
<input type="text" class="form-control">
</div>
<div class="col-3">
<label for="Renda Liquida">Cota Capital</label>
<input type="text" class="form-control">
</div>
<div class="col-6" style="text-align:center">
<label for="ServidorPublico">IAP:</label>
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Quantidade" value="#Html.DisplayFor(model => model.iAP.QuantidadeProduto)" ReadOnly="readonly"/>
<input type="text" class="form-control" placeholder="Produtos" value=""#Html.DisplayFor(model => model.iAP.Pro)" ReadOnly="readonly"/>
</div>
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label for="Renda Bruta">Margem Contribuição</label>
<input type="text" class="form-control">
</div>
<div class="col-8" style="text-align:center">
<label for="ServidorPublico">Cheque Especial</label>
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Dias de Utilização" />
<input type="text" class="form-control" placeholder="Valor Utilizado" />
<input type="text" class="form-control" placeholder="Valor Contratado" />
</div>
</div>
</div>
I already build the form, and put some fields readonly with ReadOnly="readonly", but is there a way to loop all fields and put readonly with a loop or I really need to write in all fields the code `ReadOnly="readonly" ? My form is really big
But is there a way to loop all fields and put readonly with a loop or
I really need to write in all fields the code `ReadOnly="readonly" ?
My form is really big
Yes, you can set that ReadOnly attribute based on the value of your textbox field.
In this scenario you have to consider two way, either you should consider your textbox name attribute or type="text" attribute. Upon these two very way we will be decided which textbox set to readonly which is not.
For [type='text'] Attribute:
When [type='text'] means we will check all the textbox type of text and check if the textbox have value and set the readonly attribute:
View:
<div class="form-group row">
<div class="col-3">
<label for="Renda Bruta">Associado Desde:</label>
<input type="text" name="Associado" class="form-control">
</div>
<div class="col-3">
<label for="Renda Liquida">Cota Capital</label>
<input type="text" name="Cota" class="form-control">
</div>
<div class="col-6" style="text-align:center">
<label for="ServidorPublico">IAP:</label>
<div class="input-group mb-3">
<input type="text" name="Quantidade" class="form-control" placeholder="Quantidade" value="Test Value" />
<input type="text" name="Produtos" class="form-control" placeholder="Produtos" value="Test Value Products" />
</div>
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label for="Renda Bruta">Margem Contribuição</label>
<input type="text" name="Margem" class="form-control">
</div>
<div class="col-8" style="text-align:center">
<label for="ServidorPublico">Cheque Especial</label>
<div class="input-group mb-3">
<input type="text" name="Dias" class="form-control" placeholder="Dias de Utilização" />
<input type="text" name="Utili" class="form-control" placeholder="Valor Utilizado" />
<input type="text" name="Contra" class="form-control" placeholder="Valor Contratado" />
</div>
</div>
</div>
Script:
#section scripts {
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<script src="https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js"></script>
<script>
$(document).ready(function () {
$("input[type='text']").each(function (index, item) {
console.log(item);
if ($(item).val() != "") {
$(item).attr('readonly', true);
}
});
});
</script>
}
Note: When will will set readonly to a textbox which has value based on the text type then we have to consider like input[type='text']
For name Attribute:
#section scripts {
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<script src="https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js"></script>
<script>
$(document).ready(function () {
$("input").each(function (index, item) {
console.log(item);
if ($(item).val() != "") {
$(item).attr('readonly', true);
}
});
});
</script>
}
Note: Remember in this scenario, you need to set name property for your textbox to identify uniquely as you can see I have added name property
Output:
what I understand that you want to make the input field enterable when the value of it is null. this is done by javascript.
I suggest to make all input fields read only.
use javascript to test each field, if its value is null make it enterable.
for example:
<input type="text" id="text1" class="form-control" placeholder="Quantidade" value="#Html.DisplayFor(model => model.iAP.QuantidadeProduto)" ReadOnly="readonly"/>
<script>
window.onload = function() {
if (document.getElementById("text1").value.length == 0)
{
document.getElementById("text1").readOnly = false;
}}
</script>
so basically when the page is loading the script will check if the input is null or not and it will do the action.
I am facing the issue of data validation being executed on load of a new page even though it is clearly coming from a Get method. Is there something that's triggering the validations on page load?
I have a button on a view to add a new Student record in the new screen :
View :
<a type="button" id="btnAddStudent" href='#Url.Action("Details","Student")' class="btn btn-tertiary" title="Add Student">Add Student</a>
The controller code for the Details action method in Student Controller is as follows.
[HttpGet]
public ActionResult Details(StudentInfo model)
{
//This is populating the model parameters as expected.
helper.StudentInfo(ref model);
return View(model);
}
The view for the Details screen is as follows. The page loads but is throwing validation errors even though it's a Get method.
<form id="frmSubmit" asp-action="Details" asp-controller="Student" method="post">
<input type="hidden" asp-for="StudentId" />
<div class="row">
<div class="col-xs-12">
#Html.ValidationSummary("", new { #class = "alert alert-danger validation" })
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label asp-for="Name">*StudentName</label><br />
<input asp-for="Name" class="form-control" maxlength="100" placeholder="Enter student name..." />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label asp-for="AddressLine1"></label><br />
<input asp-for="AddressLine1" class="form-control" placeholder="Enter address..." />
<span asp-validation-for="AddressLine1" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label asp-for="AddressLine2"></label><br />
<input asp-for="AddressLine2" class="form-control" maxlength="100" />
<span asp-validation-for="AddressLine2" class="text-danger"></span>
</div>
</div>
</div>
<div class="box">
<div class="form-group pull-right">
<button type="submit" class="btn btn-primary" value="save"> Save</button>
</div>
</div>
Is there something I am doing wrong? I have verified that the debug control goes to the Get method.There's alos no on load scripts which are doing any sort of validation.
1.Your get method contains the model parameter, when the request hit the method it will judge the ModelState by default. And when you hit the get method by your shared <a>, it send request without any data, so the ModelState is invalid.
2.Default Tag helper displays ModelState's value not Model.
In conclusion, you will render the ModelState error although it is a get method.
Two ways you can resolve this problem. The first way is that you can add ModelState.Clear() before you return View:
public ActionResult Details(StudentInfo model)
{
ModelState.Clear(); //add this....
helper.StudentInfo(ref model);
return View(model);
}
The second way is do not add the model as parameter:
public ActionResult Details()
{
var model = new StudentInfo();
helper.StudentInfo(ref model);
return View(model);
}
I am relatively new to asp.net mvc. My project is using clean architecture with repository and UnitOfWork patterns (I know repository pattern is largely debated these days, and that is no concern for this question). It has an asp.net core web api project and a separate MVC core project.
In the api, I have an updateModel action that expects an id to be passed in the URL, and the model to be passed in the body:
[HttpPut("update-book/{id}")]
public IActionResult UpdateBook(int id, [FromBody] ComicBookViewModel book)
{
try
{
var b = _unitOfWork.ComicBooks.GetBookById(id);
if (b != null)
{
_unitOfWork.ComicBooks.UpdateBook(id, book);
return Accepted(book);
}
else
{
return NotFound($"Book with id {id} not found");
}
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError, $"{ex.Message}");
}
}
In the MVC app, I have a page that calls the API and displays a list of entities from the database. Each entity has an edit button. The edit button calls this action in the controller:
[HttpGet]
public async Task<IActionResult> EditComic(int id)
{
ComicBookWithAuthorsAndCharactersViewModel? model = null;
string uri = $"https://localhost:5001/api/ComicBook/get-book-by-id/{id}";
HttpClient client = _httpClientFactory.CreateClient(
name: "ComicbookInventory.Api");
var request = new HttpRequestMessage(HttpMethod.Get, uri);
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
model = await response.Content.ReadFromJsonAsync<ComicBookWithAuthorsAndCharactersViewModel>();
}
return View(model);
}
and then displays a simple edit page:
#model ComicBookInventory.Shared.ComicBookWithAuthorsAndCharactersViewModel
#{
ViewData["Title"] = "EditComic";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Edit #Model?.Title</h1>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="EditComic">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Id" class="control-label"></label>
<input asp-for="Id" class="form-control" />
<span asp-validation-for="Id" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Description" class="control-label"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="IsRead" /> #Html.DisplayNameFor(model => model.IsRead)
</label>
</div>
<div class="form-group">
<label asp-for="DateRead" class="control-label"></label>
<input asp-for="DateRead" class="form-control" />
<span asp-validation-for="DateRead" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Rating" class="control-label"></label>
<input asp-for="Rating" class="form-control" />
<span asp-validation-for="Rating" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Genre" class="control-label"></label>
<input asp-for="Genre" class="form-control" />
<span asp-validation-for="Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CoverUrl" class="control-label"></label>
<input asp-for="CoverUrl" class="form-control" />
<span asp-validation-for="CoverUrl" class="text-danger"></span>
</div>
<div class="form-group">
#*<input type="hidden" name="Id" value="#Model.Id" />*#
<input type="submit" value="Save" class="btn btn-primary"/>
</div>
</form>
</div>
</div>
<div>
<a asp-action="GetAllComics">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
The submit button at the bottom of the edit page then calls this action in the controller:
[HttpPost]
public ActionResult EditComic(ComicBookWithAuthorsAndCharactersViewModel model)
{
var userId = Request.HttpContext.Request;
string uri = $"https://localhost:5001/api/ComicBook/update-book/{id}";
HttpClient client = _httpClientFactory.CreateClient(
name: "ComicbookInventory.Api");
var put = client.PutAsJsonAsync<ComicBookWithAuthorsAndCharactersViewModel>(uri, model);
put.Wait();
var result = put.Result;
if (result.IsSuccessStatusCode)
{
return RedirectToAction("GetAllComics");
}
return View(model);
}
My question is, when this last action is executed, I need to pass the id and model back to the api. How can I accomplish this?
I'm not necessarily looking for answers, just for someone to point me in the right direction. As I said, I'm new to asp.net core MVC apps.. just need some direction.
I don't get any compile-time errors, but if I set a breakpoint in the
EditComic(ComicBookWithAuthorsAndCharactersViewModel model) method below, the result is set to http 400 on this line:
var result = put.Result is set to Http 400.
My code is here: https://github.com/rnemeth90/ComicBookInventoryApp
I'm working on the main branch currently.
I figured it out just now. I had to mark some properties as nullable in my view model and then re-run the EF core migration to update the db schema. I am not passing these values back to the api from the application in this view (and therefore not passing them to EF core). So that is why I was getting the 400. CharacterIds and AuthorIds are now nullable in this class. Seems to work. Need to test it some more.
As the title says, I am wondering how I would go about parsing out multiple lines of text from a single TextBox, but submit each of those values individually to my database.
The users have a display where they enter in a barcode that represents a physical location at the facility, and they can put multiple plants in that location. So instead of having them submit a new form for every single plant, I figured this would be an easier way to do so.
However, I'm struggling to understand HOW to make this happen in my controller on the HttpPost event for Create();
The info that gets passed is: ID, UserId, PlantId, Barcode, Date, and Time. The ID (auto updated) and PlantId would be the only things that change. The Barcode, Date and Time should be the same value. I have removed all my failed attempts in my examples here so you can see how it works WITHOUT what I'm wanting to do.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,PlantId,Barcode,UserId,Date,Time")] VegLocationModel vegLocationModel)
{
if (ModelState.IsValid)
{
_context.Add(vegLocationModel);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Create));
}
return View(vegLocationModel);
}
View:
#model tester.Models.VegLocationModel
#{
ViewData["Title"] = "Create";
var userName = "TEST";
var currentDate = DateTime.Now.Date.Month.ToString() + "/" + DateTime.Now.Date.Day.ToString() + "/" + DateTime.Now.Date.Year.ToString();
var currentTime = string.Format("{0:hh:mm:ss tt}", DateTime.Now);
Html.Hidden("UserId");
Html.Hidden("Date");
Html.Hidden("Time");
}
<h1>Create</h1>
<h4>VegLocationModel</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Barcode" class="control-label"></label>
<input asp-for="Barcode" class="form-control" style="min-width:100%"/>
<span asp-validation-for="Barcode" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="PlantId" class="control-label"></label>
<textarea asp-for="PlantId" class="form-control" rows="10" cols="50">
</textarea>
<span asp-validation-for="PlantId" class="text-danger"></span>
</div>
<div class="form-group">
<input id="UserId" type="hidden" value="#userName" asp-for="UserId" class="form-control" />
<span asp-validation-for="UserId" class="text-danger"></span>
</div>
<div class="form-group">
<input id="Date" type="hidden" value="#currentDate" asp-for="Date" class="form-control" />
<span asp-validation-for="Date" class="text-danger"></span>
</div>
<div class="form-group">
<input id="Time" type="hidden" value="#currentTime" asp-for="Time" class="form-control" />
<span asp-validation-for="Time" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
the value of your textarea posted to Action "Create" is in type of string not int,so you couldn't bind it with VegLocationModel
you could try as below:
[HttpPost]
public IActionResult Create(SomeTest someTest,string plantid)
{
List<int> plantids = plantid.Split("\r\n").Select(m=>Convert.ToInt32(m)).ToList();
return Ok();
}
the result:
try as below to update your database:
public async Task<IActionResult> Create(SomeTest someTest)
{
List<string> plantids = someTest.PlantId.Split("\r\n").ToList();
var soemtestlist = new List<SomeTest>();
foreach (var id in plantids)
{
soemtestlist.Add(
new SomeTest(){
Barcode= someTest.Barcode,
Time= someTest.Time,
UserId= someTest.UserId,
PlantId = id
});
}
_context.SomeTest.AddRange(soemtestlist);
await _context.SaveChangesAsync();
return Ok();
}
The Result:
In the multiline textbox, the new line can be separated as \r\n (works in windows) OR \n\r depending on the operating system. So, logic is simple. Just split your multiline textbox with either \n\r or \r\n and store it in separate rows in the database.
The form fields do not return the value of the form even thought the asp-controller and asp-action is stated.
The form does go to the right controller function and returns the right view, however, it does the form object is NULL.
#using ActionAugerMVC.Models
#model Tuple<IEnumerable<Cities>,Content,IEnumerable<Content>,Quote>
#addTagHelper "*,Microsoft.AspNetCore.Mvc.TagHelpers"
<div class="sidebar__item">
<p class="subheading">Instant Quote Request</p>
<form class="register__form" role="form" asp-controller="Plumbing" asp-action="QuoteForm" method="post">
<div class="text-danger" asp-validation-summary="All"></div>
<div class="form-group">
<label class="sr-only">Full Name </label>
<input asp-for="#Model.Item4.FullName" type="text" class="form-control" placeholder="Full name">
</div>
<div class="form-group">
<label class="sr-only">Your phone</label>
<input asp-for="#Model.Item4.Phone" type="tel" class="form-control" placeholder="Your phone">
<span asp-validation-for="#Model.Item4.Phone" class="text-danger"></span>
</div>
<div class="form-group">
<label class="sr-only">E-mail</label>
<input asp-for="#Model.Item4.Email" type="email" class="form-control" placeholder="E-mail">
<span asp-validation-for="#Model.Item4.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label class="sr-only">Your Message</label>
<input asp-for="#Model.Item4.Message" type="text" class="form-control" placeholder="Your Message">
</div>
<input type="submit" value="Get a Quote Now" class="btn btn-accent btn-block">
</form>
</div> <!-- .sidebar__item -->
And the Controller looks like this, with the Quote object being null.
The hard coded, values appear correctly in the view, but the Quote object returned by the form is null.
[HttpPost]
public IActionResult QuoteForm(Quote quote)
{
if (ModelState.IsValid)
{
/* quote.FullName = "Umar Aftab";
quote.Email = "test#email.com";
quote.City = "Calgary";
quote.Message = "Test Message";
quote.Phone = "6474543769";
*/
}
return View(quote);
}
The issue is your use of a Tuple as your view's model combined with asp-for. For example, with something like:
<input asp-for="#Model.Item4.FullName" type="text" class="form-control" placeholder="Full name">
The name of the input is going to end up as Item4.FullName. However, your action accepts only Quote, which means the modelbinder needs the input to be named just FullName in order to bind it properly. You either need to accept the same model the view uses (though I've never tried posting a Tuple so not sure if that will even work), or you can use a partial view to work around the issue.
Essentially, you just would need to move all the fields related to just Quote to a partial view. Then, in this view, you can include them via:
#Html.Partial("_QuoteFields", Model.Item4)
That should be enough psych Razor out enough to just name the fields like FullName instead of Item4.FullName. If it's not, then you may need to reset the HtmlFieldPrefix, via:
#Html.Partial("_QuoteFields, Model.Item4, new ViewDataDictionary(ViewData) { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "" } })
The model on your view is different than the model you're trying to bind it to in the controller. You're not going to get the key/value pairs to match up
Put your razor in a partial view with Quote as the model and try that.
_QuoteForm.cshtml
#model Quote
<div class="form-group">
<label class="sr-only">Full Name </label>
<input asp-for="FullName" type="text" class="form-control" placeholder="Full name">
</div>
<div class="form-group">
<label class="sr-only">Your phone</label>
<input asp-for="Phone" type="tel" class="form-control" placeholder="Your phone">
<span asp-validation-for="Phone" class="text-danger"></span>
</div>
<div class="form-group">
<label class="sr-only">E-mail</label>
<input asp-for="Email" type="email" class="form-control" placeholder="E-mail">
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<label class="sr-only">Your Message</label>
<input asp-for="Message" type="text" class="form-control" placeholder="Your Message">
</div>
OriginalView.cshtml
using ActionAugerMVC.Models
#model Tuple<IEnumerable<Cities>,Content,IEnumerable<Content>,Quote>
#addTagHelper "*,Microsoft.AspNetCore.Mvc.TagHelpers"
<div class="sidebar__item">
<p class="subheading">Instant Quote Request</p>
<form class="register__form" role="form" asp-controller="Plumbing" asp-action="QuoteForm" method="post">
<div class="text-danger" asp-validation-summary="All"></div>
#Html.Partial("_QuoteForm", Model.Item4)
<input type="submit" value="Get a Quote Now" class="btn btn-accent btn-block">
</form>
</div> <!-- .sidebar__item -->