ASP.Net core Model's date property is blank in edit mode - asp.net-core

I have a Razor pages web app and one of the models' is for colleague info and includes their date of birth.
When I look at the scaffolded pages for a colleague, the Date of Birth field is populated in the details page but not the edit page.
Images below will show what I mean.
Here is the Details page
And here is the Edit page
As you will know, as the Edit page is blank, If I change another field e.g. Staff Position and save, the DOB for the colleague becomes null.
As I say the pages are from the EF Core scaffolding so I believe the HTML for the form should be correct.
Edit Page HTML
<div class="form-group">
<label asp-for="Colleague.DateOfBirth" class="control-label"></label>
<input asp-for="Colleague.DateOfBirth" class="form-control" />
<span asp-validation-for="Colleague.DateOfBirth" class="text-danger"></span>
</div>
Colleague is a bind Property of the Colleague model in the Page Model. ALl other fields, as seen in the image populate fine.
Update
As I say it is using Model Binding
[BindProperty]
public Colleague Colleague { get; set; }
OnPost
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Attach(Colleague).State = EntityState.Modified;
try
{
selectedBranch = Colleague.BranchID;
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ColleagueExists(Colleague.ColleagueID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("../BranchColleagues", new { id = selectedBranch });
}
[DataType(DataType.Date)]
[Display(Name = "Date of Birth")]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateTime? DateOfBirth { get; set; }

I also faced the same problem. It works while I use .Value in input tag
<input asp-for="Colleague.DateOfBirth.Value" class="form-control" />

I am placing my quick fix solution as the question has been empty now for a month.
By removing this annotation from the POCO class:
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
The date value now appears in the edit form as required.

Related

Razor pages view renders original form value instead of modified when reshown

Moving from ASP.NET Core MVC to Razor pages, there must be an issue in my understanding of passing data to a Razor view.
Here's a simple view:
#page
#model TestModel
#{
System.Diagnostics.Debug.WriteLine(Model.Name);
}
<form class="form-horizontal" method="get">
Name: <input type="text" class="form-control" asp-for="Name">
<button type="submit" class="btn btn-default">Send...</button>
</form>
And here is the view model class with one event handler:
public class TestModel : PageModel
{
[BindProperty(SupportsGet = true)]
public string Name { get; set; } = "";
public TestModel() {}
public IActionResult OnGet()
{
Name += "N";
return Page();
}
}
Then running the project:
Debug.WriteLine shows "N" as expected
input fields has "N" default value as expected
overwrite "N" in the input field eg. to "A" then press Send button
Debug.WriteLine shows "AN" as expected so view has got the value modified by OnGet()
the input field in the page itself contains the value "A" instead of "AN", the generated HTML contains:
value="A"
View does not render the modified Model.Name value but the original from the form data.
How can it be corrected to make view to render the modified string?
You can try to add ModelState.Clear(); in OnGet handler.When binding data in client side,it will get value from ModelState prior to Model.
public class TestModel : PageModel
{
[BindProperty(SupportsGet = true)]
public string Name { get; set; } = "";
public TestModel() {}
public IActionResult OnGet()
{
Name += "N";
ModelState.Clear();
return Page();
}
}

ASP.Net Core How to set value to input

I'm confused about how to place values in a text form.
I created a simple form.
test.cshtml
##Model.Name is #Model.Name
<form method=post>
Name:<input asp-for="Name" />
<button asp-page="test">Submit</button>
</form>
test.cshtml.cs is
[BindProperty(SupportsGet = true)]
public string Name { get; set; }
public IActionResult OnGet()
{
Name = "value-get";
return Page();
}
public IActionResult OnPost()
{
Name = "value-post";
return Page();
}
first get result is
#Model.Name is value-get
Name:[value-get] [submit]
image
OK. This is fine. The Name is now "value-get".
I change the text box value = 123.
#Model.Name is value-get
Name:[123][submit]
image
then post it.
#Model.Name is now "value-post". Because I change it at OnPost. But the text field is still 123.
#Model.Name is value-post
Name:[123][submit]
image
I do same thing at OnGet and OnPost. I can set text field by OnGet, but I can't set it by OnPost.I would like to know why this is the case and tell me about the structure.
When binding data in client side,it will get value from ModelState prior to Model .You can try to add ModelState.Clear(); into Post method.
public IActionResult OnPost()
{
ModelState.Clear();
Name = "value-post";
return Page();
}
result:

Why are my Guids being cleared and time being stripped from my DateTime fields in AspnetCore app?

Net 5.0
I have several fields on a form, two are readonly fields. One is a Guid the other is a DateTime.
When changes are submitted, the Guid is set to 00000000-0000-0000-0000-000000000000 and the time is removed from my DateTime column 2021-04-13 02:36:37.4567940 becomes 2021-04-13 00:00:00.0000000
<div class="form-group">
<label asp-for="Record.MyGuid" class="control-label"></label>
<input asp-for="Record.MyGuid" class="form-control" readonly/>
<span asp-validation-for="Record.MyGuid" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Record.FormInserted" class="control-label"></label>
<input asp-for="Record.FormInserted" class="form-control" readonly/>
<span asp-validation-for="Record.FormInserted" class="text-danger"></span>
</div>
As they appear on the model
[Display(Name="Website ID")]
[Required(ErrorMessage = "There should not be a record without an Id. Please report this.")]
[Editable(false)]
public Guid MyGuid { get; private set; }
[Display(Name="Submission date")]
[DataType(DataType.Date)]
[Required(ErrorMessage = "Submission date is required.")]
public DateTime FormInserted { get; set; }
When the record is retrieved, it has a complete Guid and date. However, when the Post action starts those values are changed even though the form still correctly displays the values.
Here is the Post handler. When I inspect the object Record, the values have been changed when it reaches the if(Record.Id > 0) step.
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
// At this point, the Guid is now all Zeros
// and the time has been removed from the DateTimee
if(Record.Id > 0)
{
await _RecordData.Update(Record);
}
else
{
// No Id means new record. Add it.
_RecordData.Add(Record);
}
// Commit the changes to the database
await _RecordData.Commit();
// Message to pass to the details page
TempData["StatusMessage"] = "Record saved!";
// Redirect to Details page
return RedirectToPage("./Edit", new { RecordId = Record.MyGuid });
}
What do I need to do to prevent this from happening and preserve the read-only data?
The issue is caused by your model class.
You can change your model like following.
[Display(Name="Website ID")]
[Required(ErrorMessage = "There should not be a record without an Id. Please report this.")]
public Guid MyGuid { get; set; }
[Display(Name="Submission date")]
[DataType(DataType.DateTime)]
[Required(ErrorMessage = "Submission date is required.")]
public DateTime FormInserted { get; set; }
Delete the line [Editable(false)] and change DataType.Date to DataType.DateTime.
Besides delete the code [Editable(false)],you also need to delete the code private.

Asp.NET Core Model Binding input type checkbox not remains unchecked

I am facing some strange issue, I am using Asp.net Core.
I have Model class which I am binding to my razor view and here is the model implementation.
{
PatientDetailReport = new ReportModel();
itemid = true;
}
public ReportModel PatientDetailReport { get; set; }
public bool itemid { get; set; }
Report Model Class has few bool properties like
public bool IdentityNumberDisplay { get; set; }
I am trying to bind model in both of these ways as mentioned by mostly blogs and also on stackoverflow
(1) <input type="checkbox" asp-for="#Model.PatientDetailReport.IdentityNumberDisplay" />
(2) #Html.CheckBoxFor(m=>m.PatientDetailReport.IdentityNumberDisplay,new { })
</td>
but both of these cases remains unchecked.
for first case, I also tried with value=#Model.PatientDetailReport.IdentityNumberDisplay
but at jquery level I have to check it with value =True or False (as string) I am able to modify the checkbox, but the value is not posting on Controller.
Please can anyone guide me regarding to this case.
Why the case 2 is not working,however most of the blogs are saying to use like that?
Thanks
I could reproduce your problem, make sure PatientDetailReport.IdentityNumberDisplay has been set to true in your case.
Since your code does not assign value to it and the default value false results in checkbox unchecked.
You could set default value like below to have a test:
public bool IdentityNumberDisplay { get; set; } = true;
<form method="post">
#Model.PatientDetailReport.IdentityNumberDisplay
#*see the value of IdentityNumberDisplay*#
<input type="checkbox" asp-for="#Model.PatientDetailReport.IdentityNumberDisplay" />
#Html.CheckBoxFor(m=>m.PatientDetailReport.IdentityNumberDisplay,new { })
<input type="submit" value="submit" />
</form>
I resolved this issue using JQuery by checking Checkbox value from Model which is coming as 'True' in string format, and then assigned checked property to true.
#Html.CheckBoxFor(m=>m.PatientDetailReport.IdentityNumberDisplay
,new {value=Model.PatientDetailReport.IdentityNumberDisplay })
$.each($("input[type='checkbox']"), function (e) {
console.log($(this).val());
//debugger;
if ($(this).val() === 'True') {
$(this).prop('checked', true);
}
})
I am not sure it is correct or not but this resolved my issue for asp.net core model's bool property for checkbox or radio button.

ASP.Net Core Razor Pages: How to return the complex model on post?

I created a new ASP.Net Core 2 (Razor Pages) Project
My model is:
public class FormularioGenerico
{
public FormularioGenerico()
{
}
public string IP { get; set; }
public List<string> items { get; set; } = new List<string>();
}
On the page I put
on the page.cshtml.cs
public class EditarModel : PageModel
{
[BindProperty]
public FormularioGenerico ff { get; set; }
[BindProperty]
public string Message { get; set; }
public void OnGet()
{
this.ff = new FormularioGenerico();
ff.IP = "C# FORM";
ff.items.Add("OK1");
ff.items.Add("OK2");
ff.items.Add("OK3");
}
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
var m = ModelState.IsValid; // true
Debug.WriteLine(this.ff.IP); // is Always returning null
Debug.WriteLine(this.ff.items.Count); // is Always returning null
}
}
on the page.cshtml:
#model Formulario.Pages.EditarModel
...
<h1>#Model.ff.IP</h1>
#foreach (var i in Model.ff.items)
{
<div>#i</div>
}
<button type="submit">Enviar</button>
The items are correctly output. But the complete object does not go to the OnPost.
The problem is: The model is not coming fully populated on the OnPost.
How to receive the full object that was created on the OnGet, plus the changes made by the user on the form, on the post to OnPostAsync() ?
The BindProperty attribute is used to inform ASP.NET Core that the values that the form submitted should be mapped to the specified object. In your case you set the values for the ff property but you do not have the equivalent input values so that ASP.NET Core will get these values in order to store them back to the ff property.
In order to make it work you will have to replace your razor code with the following code:
<form method="post">
<h1>#Model.ff.IP</h1>
<input asp-for="#Model.ff.IP" type="hidden" /> #* create a hidden input for the IP *#
#for (int i = 0; i < Model.ff.items.Count(); i++)
{
<input asp-for="#Model.ff.items[i]" type="hidden" /> #* create a hidden input for each item in your list *#
<div>#Model.ff.items[i]</div>
}
<button type="submit">Enviar</button>
</form>
Very important. To make this work you can not use the foreach loop because ASP.NET core will not be able to find the values. You will have to use a for loop.
The inputs that I added are hidden because I guess you do not want them to be visible but you can remore the type="hidden" so that you will be able to see them. Every change that you make to these inputs will be submitted to the OnPostAsync method.