I want to have a form on the webpage /create. This form contains : name, description and price. When filled in, it should send the data to the controller.
De controller does not receive the data and I don't know why.
I tried deleting the pages and recreate them, this did not work. I also tried #html.textlabelfor. this also did not work.
Here is my view code :
#using (Html.BeginForm("Create", "Beheer", FormMethod.Post))
{
<div class="form-group">
<label for="name">Name:</label>
<input type="text" class="form-control" placeholder="Fill article name" name="Naam">
</div>
<div class="form-group">
<label for="des">Description:</label>
<input type="text" class="form-control" placeholder="Fill in article description" name="Omschrijving">
</div>
<div class="form-group">
<label for="price">Price:</label>
<input type="number" class="form-control" placeholder="Fill in article price" name="Prijs">
</div>
<input type="submit" class="btn btn-default" value="submit" />
}
Here is my controller code:
[HttpPost]
public IActionResult Create(ArtikelModel artikelModel)
{
return View(artikelModel);
}
[HttpGet]
public IActionResult Create()
{
return View();
}
Here is my model :
public int Id { get; set; }
public string Naam { get; set; }
public string Omschrijving { get; set; }
public decimal Prijs { get; set; }
public byte[] Foto { get; set; }
public decimal Korting { get; set; }
public List<ReviewModel> Reviews { get; set; }
I expected the ArtikelModel to be filled with data the user put it.
Since you indicated that the controller method doesn't get called at all, the likely issue is the name of your controller as #LaljiDhameliya mentioned. So, since your view lists "Beheer" as the controller, due to ASP.NET MVC convention, your controller should be called "BeheerController" (you didn't include this bit of code in your question, so we can't see if that is the case)
Related
I'm building a profile page where I have to display a user's profile pic as well as 3 other pictures that he/she had previously selected. Now I'm passing into the view a "ProfileViewModels" viewmodel which contains two other viewmodels: of which one of them is a list of a viewmodel.
My images all display correctly. Each image is contained in a bootstrap card class of which contains two buttons; delete and update for each image in the card. Now, I'm surrounding each button with a form tag and embedding a hidden field that contains the id of each image so that when the user clicks on 'delete' or 'update' for a particular card which contains an image, it passes on the id of the selected image back to the controller needed for deletion.
However, on running my code, whenever I click on 'delete' or 'update' I'm getting null values in my controller and as such, I can't delete nor update my picture. Below are my viewmodels, cshtml view page and controller.
VIEMODEL INJECTED INTO THE VIEWPAGE:
public class ProfileViewModels
{
public List<PicturesViewModel> Pictures { get; set; }
public ProfilePicViewModel ProfilePic { get; set; }
}
public class ProfilePicViewModel
{
public string PictureId { get; set; }
public string PictureAddress { get; set; }
[Required]
public IFormFile Picture { get; set; }
}
public class PicturesViewModel
{
public string PictureId { get; set; }
public string Picture { get; set; }
public IFormFile PictureForm { get; set; }
[Required]
[MaxLength(140, ErrorMessage = "picture description should not be more than 140 characters")]
public string Description { get; set; }
}
#model ProfileViewModels
#{
var imgAddresses = new List<string>();
var imgIds = new List<string>();
}
#{ var path = "~/images/" + Model.ProfilePic.PictureAddress; }
#foreach (var pic in Model.Pictures)
{
imgAddresses.Add(pic.Picture);
imgIds.Add(pic.PictureId);
}
<div class="row mt-5">
<div class="col-sm-3 mb-5">
<img asp-append-version="true" src=#(path) alt="User Profile pic" class="rounded-circle" width="150" height="150" />
</div>
<!---other codes --->
<div class="col-sm-9">
<div class="card">
<div class="card-body m-0">
#for (int i = 0; i < Model.Pictures.Count; i++)
{
<div class="card d-inline-block mr-1 mb-3" style="width: 31%;">
<img src="~/images/#(imgAddresses[i])" alt="user_pictures" class="card-img-top" width="200" height="150" />
<div class="card-body">
<p class="card-text">#Model.Pictures[i].Description</p>
#using (HtmlHelperFormExtensions.BeginForm(Html, "DeletePicture", "User", FormMethod.Post, imgIds[i]))
{
<div asp-validation-summary="All"></div>
<input type="text" hidden value="#Model.Pictures[i].PictureId" />
<input type="text" hidden value="#(imgIds[i])" />
<button type="submit" class="card-link btn btn-outline-danger">Delete</button>
}
#using (HtmlHelperFormExtensions.BeginForm(Html, "AddPicture", "User", FormMethod.Post, imgIds[i]))
{
<div asp-validation-summary="All"></div>
<input type="text" hidden value="#Model.Pictures[i].PictureId" />
<input type="text" hidden value="#(imgIds[i])" />
<button type="submit" class="card-link btn btn-outline-success">Update</button>
}
</div>
</div>
}
}
CONTROLLER:
[HttpPost]
public async Task<IActionResult> AddPicture(ProfileViewModels model)
{
//code block for performing action
RedirectToAction("Profile");
}
[HttpPost]
public async Task<IActionResult> DeletePicture(ProfileViewModels model)
{
//code block for performing action
RedirectToAction("Profile");
}
What am I doing wrong?
<input type="text" hidden value="#Model.Pictures[i].PictureId" />
Please note that if the name attribute of the input field is omitted, the value of the input field within a <form> will not be sent at all.
imgIds.Add(pic.PictureId);
In your code we can find that you populate List<string> imgIds with PictureId(s) you passed through view model, so <input type="text" hidden value="#(imgIds[i])" /> might be same as <input type="text" hidden value="#Model.Pictures[i].PictureId" />.
when the user clicks on 'delete' or 'update' for a particular card which contains an image, it passes on the id of the selected image back to the controller needed for deletion.
To pass the selected image's id to controller for deletion, you can try to modify the code as below.
Specify name="SelectedPictureId" for hidden field
#using (HtmlHelperFormExtensions.BeginForm(Html, "DeletePicture", "User", FormMethod.Post, imgIds[i]))
{
<div asp-validation-summary="All"></div>
<input type="hidden" name="SelectedPictureId" value="#Model.Pictures[i].PictureId" />
<button type="submit" class="card-link btn btn-outline-danger">Delete</button>
}
DeletePicture action method
[HttpPost]
public async Task<IActionResult> DeletePicture(string SelectedPictureId)
{
//code block for performing action
return RedirectToAction("Profile");
}
Besides, this article explains what model binding is and how it works, you can refer to it for detailed information.
https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-5.0
I am creating a checkout form using razor and asp.net core 3.1.
After the checkout form is submitted, the order object is also created automatically. And the telephone field, which supposes to be optional, is also being created as an object with null values like below (if the user leave the input field blank and submits the form).
My simplified model looks like this
public partial class Order
{
public Order()
{
OrderStock = new HashSet<OrderStock>();
}
public int Id { get; set; }
public string Reference { get; set; }
public virtual Address Address { get; set; }
...
public virtual Telephone Telephone { get; set; }
public virtual ICollection<OrderStock> OrderStock { get; set; }
}
My razor page looks something like this:
<form id="CheckOut" asp-controller="CheckOut" asp-action="CreateOrder" method="post">
<div class="col-md-8 mb-3">
<label asp-for="Address.Street">Street <span>*</span></label>
<input asp-for="Address.Street" type="text" class="form-control mb-3" maxlength="50" />
</div>
...
<div class="col-12 mb-3">
<label asp-for="Telephone.TelephoneNumber">Phone No</label>
<input asp-for="Telephone.TelephoneNumber" type="number" class="form-control" min="0" maxlength="20"/>
</div>
<div class="col-12 mb-4">
<label asp-for="Email.EmailAddress">Email Address <span>*</span></label>
<input asp-for="Email.EmailAddress" type="email" class="form-control" maxlength="30"/>
</div>
So I have to get rid of this telephone-object being created, to make the database happy, because it's is trying to save an empty record into telephone table in my db.
The first solution, that I could think of is, using if-statement in my controller like this.
if (string.IsNullOrEmpty(order.Telephone.TelephoneNumber))
{
order.Telephone = null;
}
But that is clearly not the best solution to avoid this. It's there any better way to handle this?
I want to make a form that user have to fill out it.
But I'm getting an error.
Model:
public UserReport Input;
[Key]
//[Required]
public string ReportID { get; set; }
[Required]
public string Description { get; set; }
[Required]
[DataType(DataType.DateTime)]
public string Date { get; set; }
Controller:
private ApplicationDbContext _userReport;
public UserReport Input;
public PageController(ApplicationDbContext userReport)
{
_userReport = userReport;
}
[HttpGet]
public IActionResult SendReport()
{
return View();
}
[Authorize]
[HttpPost]
public async Task<IActionResult> SendReport(UserReport userReport)
{
var user = new UserReport { Description = Input.Description, Date = Input.Date };
var r = await _userReport.AddAsync(user);
}
View:
#model UserReport
<div class="col-md-6">
<form id = "SendReport" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Description"></label>
<input asp-for="Input.Description" class="form-control" />
<span asp-validation-for="Input.Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.Date"></label>
<input asp-for="Input.Date" class="form-control" />
<span asp-validation-for="Input.Date" class="text-danger"></span>
</div>
<button type = "submit" class="btn btn-primary">send report</button>
</form>
</div>
what is wrong with that?
It shows me this Error :System.NullReferenceException - Object reference not set to an instance of an object... who can help me to manage this error.
Show me where is my mistake please
I think you need to go back through the tutorials in the docs again. It doesn't seem like you really know what you're doing here. You've got a field named Input, which seems to be pulled from a Razor Page, but you're working in an MVC controller here. However, even that is off, because you'd typically see that as something like:
[BindProperty]
public UserReport Input { get; set; }
In a Razor Page. Here, it's not even a property, so even if this would normally do something, it wouldn't as a field, regardless.
The NullReferenceException comes because you reference this field, but never actually initialize it. Again, in a Razor Page (and if it was a property rather than a field), this would get filled with the post data (via BindProperty), but it doesn't work that way in a controller.
In your controller action, you've got a userReport param, so that is where the post data will go. However, since all the asp-for attributes in your view reference Input.Something, nothing will actually get bound to this param. This too seems to be pulled from a Razor Page, without considering that it only works this way in a Razor Page.
Long and short, it looks like you just copied code from other places, without actually understanding any of it or what it does, and cobbled it together into a controller and view. The whole thing is fundamentally broken top-down.
You have mixed with MVC and Razor Pages.
For MVC:
1.Model:
public class UserReport
{
[Key]
//[Required]
public string ReportID { get; set; }
[Required]
public string Description { get; set; }
[Required]
[DataType(DataType.DateTime)]
public string Date { get; set; }
}
2.SendReport.cshtml:
#model UserReport
<div class="col-md-6">
<form asp-action="SendReport" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Description"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Date"></label>
<input asp-for="Date" class="form-control" />
<span asp-validation-for="Date" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">send report</button>
</form>
</div>
3.Controller:
public class UserReportsController : Controller
{
private readonly YourDbContext _context;
public UserReportsController(YourDbContext context)
{
_context = context;
}
public IActionResult SendReport()
{
return View();
}
[HttpPost]
public async Task<IActionResult> SendReport([Bind("ReportID,Description,Date")] UserReport userReport)
{
if (ModelState.IsValid)
{
_context.Add(userReport);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(userReport);
}
}
For Razor Pages:
1.Model:
public class UserReport
{
[Key]
//[Required]
public string ReportID { get; set; }
[Required]
public string Description { get; set; }
[Required]
[DataType(DataType.DateTime)]
public string Date { get; set; }
}
2.SendReport.cshtml:
#page
#model SendReportModel
<div class="col-md-6">
<form id="SendReport" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Description"></label>
<input asp-for="Input.Description" class="form-control" />
<span asp-validation-for="Input.Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.Date"></label>
<input asp-for="Input.Date" class="form-control" />
<span asp-validation-for="Input.Date" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">send report</button>
</form>
</div>
3.SendReport.cshtml.cs:
public class SendReportModel : PageModel
{
private readonly YourDbContext _context;
public SendReportModel(YourDbContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public UserReport Input { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.UserReport.Add(Input);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
Reference:
Tutorial:Create a web app with ASP.NET Core MVC
Tutorial: Create a Razor Pages web app with ASP.NET Core
I need some help to solve this issue, I don't know how to figure out.
Basically I want to add dynamic fields on form but I can't bind the values on Submit Post.
The list is always null, don't have values.
Basically I have a view model with some fieds and one list.
My PlanoAcaoViewModel:
public class PlanoAcaoViewModel
{
public int IdPlanoAcao { get; set; }
public int Numero { get; set; }
public DateTime DataEncerramento { get; set; }
public List<PlanoEvidenciaIForm> ListaPlanoEvidenciaIForm { get; set; }
public class PlanoEvidenciaIForm
{
public int IdPlanoAcaoEvidencia { get; set; }
public IFormFile Arquivo { get; set; }
public string Nota { get; set; }
public DateTime Data { get; set; }
}
}
My Controller:
[HttpPost]
public async Task<IActionResult> Create(PlanoAcaoViewModel model)
{
var num = model.Numero; // It's ok, return the right number
var data = model.DataEncerramento ; // It's ok, return the right date
foreach (var it in model.ListaPlanoEvidenciaIForm)
{
// model.ListaPlanoEvidenciaIForm is NULL
}
}
My cshtml:
#model ProjetoGestor.ViewModel.PlanoAcaoViewModel
<form asp-action="Create" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="row">
<div class="col-auto">
<label asp-for="Numero" class="control-label"></label>
<input asp-for="Numero" class="form-control" disabled type="text" />
</div>
<div class="col-auto">
<label asp-for="DataEncerramento" class="control-label"></label>
<input asp-for="DataEncerramento" class="form-control" type="date" placeholder="dd/mm/yyyy" />
<span asp-validation-for="DataEncerramento" class="text-danger"></span>
</div>
</div>
<div class="row">
#* Dynamic Fields *#
<input asp-for="ListaPlanoEvidenciaIForm[0].Arquivo" class="form-control" type="file" />
<input asp-for="ListaPlanoEvidenciaIForm[0].Nota" class="form-control" />
</div>
<div class="row col-auto">
<div class="align-center">
<a class="btn btn-primary btn-xl" asp-action="Index">Voltar</a> |
<input type="submit" value="Criar" class="btn btn-primary btn-success btn-xl" />
</div>
</div>
</form>
And the dynamic fields
I already tried a lot of ways but without success:
// In this way the model.ListaPlanoEvidenciaIForm is NULL
<input asp-for="ListaPlanoEvidenciaIForm[0].Arquivo" class="form-control" type="file" />
<input asp-for="ListaPlanoEvidenciaIForm[0].Nota" class="form-control" />
// In this way don't do it the POST (don't call the method create post)
<input name="ListaPlanoEvidenciaIForm[0].Arquivo" class="form-control" type="file" />
<input name="ListaPlanoEvidenciaIForm[0].Nota" class="form-control" />
// In this way the model.ListaPlanoEvidenciaIForm have length > 0 but all values inside list are null
<input name="ListaPlanoEvidenciaIForm" class="form-control" type="file" />
<input name="ListaPlanoEvidenciaIForm" class="form-control" />
In this way also don't call the method creat post:
From https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-3.1;
When uploading files using model binding and IFormFile, the action
method can accept:
A single IFormFile.
Any of the following collections that represent several files:
IFormFileCollection
IEnumerable<IFormFile>
List<IFormFile>
There's no mention of a list of objects, each containing an IFormFile. So you may be hitting a limitation of MVC binding. I'd suggest you try to split the list of files from the other values;
public List<PlanoEvidenciaIForm> ListaPlanoEvidenciaIForm { get; set; }
public List<IFormFile> Arquivos { get; set; }
public class PlanoEvidenciaIForm
{
public int IdPlanoAcaoEvidencia { get; set; }
public string Nota { get; set; }
public DateTime Data { get; set; }
}
<!-- The IFormFile doesn't use [ ] -->
<input asp-for="Arquivos" class="form-control" type="file" />
<input asp-for="ListaPlanoEvidenciaIForm[0].Nota" class="form-control" />
Here is another issue I have faced in ASP.NET Core
Let say I have 2 Tables:
Accommodation
( ID, Name, LocationID)
Location
(ID, Address, Latitude, Longitude)
And I have a form:
Name:
Address:
Latitude:
Longitude:
Then when a button is clicked I want the value to be updated on both table and also MAP the LocationID to Accommodation table
How should I code it in EF Core? Like a proper way
You could try the following example I made :
Accommodation Model and Location Model
public class Accommodations
{
public int ID { get; set; }
public string Name { get; set; }
public int LocationID { get; set; }
[ForeignKey("LocationID")]
public Location Location { get; set; }
}
public class Location
{
public int ID { get; set; }
public string Address { get; set; }
//other stuff you want
}
DbSet two model in DbContext
public class MVCDbContext:DbContext
{
public MVCDbContext(DbContextOptions<MVCDbContext> options) : base(options)
{ }
public DbSet<Accommodations> Accommodations { get; set; }
public DbSet<Location> Location { get; set; }
}
The design of the view ,pay attention to the asp-for of the input tag
#model MVC2_1Test.Models.Accommodation.Accommodations
#{
ViewData["Title"] = "Accommondation";
}
<h2>Accommondation</h2>
<div class="row">
<div class="col-md-4">
<form id="form" class=".has-error" asp-action="CreateAccommodation">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group ">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" id="cusName" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Location.Address" class="control-label"></label>
<input asp-for="Location.Address" class="form-control" id="age" />
<span asp-validation-for="Location.Address" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
The action to update both table
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> CreateAccommodation([FromForm]Accommodations accommodation)
{
if (ModelState.IsValid)
{
_context.Add(accommodation);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(accommodation);
}