MVC Net 6 Get Object from SelectList using its id - asp.net-mvc

Hello i am triying to figure out how to get the object after is selected in the selectlist, the selectlist holds the "Id" field and "Code" field, but i want to get access to the other fields of the object after is selected. I would like to show the "Amount" field and the "Coin.Name" of the object in the view after the selecction.
Order Model
public class Order
{
[Required]
[Key]
public int Id { get; set; }
[ForeignKey("Id")]
[Display(Name = "Proveedor")]
public int ProviderId { get; set; }
[Display(Name = "Proveedor")]
public virtual Provider Provider { get; set; } = null!;
[ForeignKey("Id")]
[Display(Name = "Pais")]
public int CountryId { get; set; }
[Display(Name = "Pais")]
public virtual Country Country { get; set; } = null!;
[ForeignKey("Id")]
[Display(Name = "Categoria")]
public int CategoryId { get; set; }
[Display(Name = "Categoria")]
public virtual Category Category { get; set; } = null!;
[Required]
[StringLength(100)]
[Display(Name = "Coigo de Orden")]
public string Code { get; set; } = null!;
[Required]
[Display(Name = "Moneda")]
public int CoinId { get; set; }
[Display(Name = "Moneda")]
public virtual Coin Coin { get; set; } = null!;
[Required]
[Display(Name = "Monto")]
[Precision(18, 2)]
public decimal Amount { get; set; }
[Required]
[DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)]
[Display(Name = "Fecha")]
public DateTime Date { get; set; }
[Required]
[DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)]
[Display(Name = "Fecha Tope")]
public DateTime DateEnd { get; set; }
[ForeignKey("Id")]
[Display(Name = "Comprador")]
public int BuyerId { get; set; }
[Display(Name = "Comprador")]
public virtual Buyer Buyer { get; set; } = null!;
[StringLength(500)]
[Display(Name = "Comentarios")]
public string Comments { get; set; }
[StringLength(500)]
[Display(Name = "Campo 1")]
public string Field1 { get; set; }
[StringLength(500)]
[Display(Name = "Campo 2")]
public string Field2 { get; set; }
[StringLength(500)]
[Display(Name = "Campo 3")]
public string Field3 { get; set; }
[StringLength(500)]
[Display(Name = "Campo 4")]
public string Field4 { get; set; }
[ForeignKey("Id")]
public int AuditUserId { get; set; }
public virtual User AuditUser { get; set; } = null!;
public DateTime AuditDateTime { get; set; }
public bool AuditDelete { get; set; }
}
Coin Model
public class Coin
{
[Required]
[Key]
public int Id { get; set; }
[Required]
[StringLength(100)]
[Display(Name = "Nombre")]
public string Name { get; set; }
[ForeignKey("Id")]
public int AuditUserId { get; set; }
public virtual User AuditUser { get; set; } = null!;
[Required]
public DateTime AuditDateTime { get; set; }
[Required]
public bool AuditDelete { get; set; }
}
Create Controller
public async Task<IActionResult> Create(int idPayment)
{
ViewData["id"] = idPayment;
ViewData["OrderId"] = new SelectList(_context.Orders.Include(o => o.Coin).Where(x => x.AuditDelete == false).OrderBy(x => x.Code), "Id", "Code");
ViewData["PaymentStatusId"] = new SelectList(_context.PaymentsStatus.Where(x => x.AuditDelete == false).OrderBy(x => x.Status), "Id", "Status");
return View();
}
Create View
#model WebApplicationDailyPayments.Models.Database.PaymentDetails
#{
ViewData["Title"] = "Crear";
}
<h1>Crear</h1>
<h4>Detalle de pagos</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="PaymentId" class="control-label"></label>
<select asp-for="PaymentId" class ="form-control" asp-items="ViewBag.PaymentId"></select>
</div>
<div class="form-group">
<label asp-for="OrderId" class="control-label"></label>
<select asp-for="OrderId" class ="form-control" asp-items="ViewBag.OrderId"></select>
</div>
<div class="form-group">
<label asp-for="PaymentStatusId" class="control-label"></label>
<select asp-for="PaymentStatusId" class ="form-control" asp-items="ViewBag.PaymentStatusId"></select>
</div>
<div class="form-group">
<label asp-for="AmountPaid" class="control-label"></label>
<input asp-for="AmountPaid" class="form-control" id="AmountPaid" />
<span asp-validation-for="AmountPaid" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Rate" class="control-label"></label>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="rateChecked" checked="">
<label class="form-check-label" for="flexSwitchCheckChecked">Multiplicar - Dividir</label>
</div>
<input asp-for="Rate" class="form-control" id="Rate"/>
<span asp-validation-for="Rate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="AmountPaidFinal" class="control-label"></label>
<input asp-for="AmountPaidFinal" class="form-control" id="AmountPaidFinal" readonly />
<span asp-validation-for="AmountPaidFinal" class="text-danger"></span>
</div>
<br/>
<div class="form-group">
<input type="submit" value="Crear" class="btn btn-primary" /> <a class="btn btn-primary" asp-action="Index" asp-route-idPayment="#ViewData["id"]">Regresar a la Lista</a>
</div>
</form>
</div>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script>
$(function(){
$("#AmountPaid,#Rate").keyup(function (e) {
var q=$("#AmountPaid").val().toString().replace(",",".");
var p = $("#Rate").val().toString().replace(",", ".");
var c = document.getElementById('rateChecked');
var result=0;
if(q!=="" && p!=="" && $.isNumeric(q) && $.isNumeric(p))
{
if(c.checked)
{
result = parseFloat(q) * parseFloat(p);
}
else
{
result = parseFloat(q) / parseFloat(p);
}
}
$("#AmountPaidFinal").val((Math.round(result * 100) / 100).toString().replace(".", ","));
});
});
</script>
}
Edit 1
I added in the controller to pass the Orders to the view
ViewData["Orders"] = _context.Orders.Include(o => o.Coin).Where(x => x.AuditDelete == false).ToList();
I added in the view to get the orders
#{
foreach (var item in (IEnumerable<WebApplicationDailyPayments.Models.Database.Order>)(ViewData["Orders"]))
{
var a = item.Id;
}
}
Now i get the Orders in the view, now i need to filter by Id selecetd in the selectlsit
Thank you

You can monitor select changes to perform corresponding operations.
Below is my test code, you can refer to it.
In the view, I use JavaScript to monitor whether the select changes, so as to obtain the selected Id for matching:
<div class="form-group">
<label asp-for="OrderId" class="control-label"></label>
<select id="my_select" asp-for="OrderId" class="form-control" asp-items="#ViewBag.OrderId"></select>
</div>
<script>
$("#my_select").change(function () {
var id = $(this).children(":selected").attr("value");
var array = #Html.Raw(Json.Serialize(ViewData["Orders"]));
for (var i = 0; i < array.length; i++) {
if(array[i].id == parseInt(id))
{
console.log("Coin.Name:"+array[i].coin.name);
console.log("Amount:" + array[i].amount);
}
}
});
</script>
Test Result:
Is this what you want?

Related

Asp.net core 6 get value from drop downlist

I am using the #Html.dropdownlistfor that allows the user to choose the customer that creates the deal. But the chhosed customer did not proceed to the controller which led to an unvalid model state. I got the reason that the model was not valid
but I did not know how to solve it. I have followed these links but the problem is still the same.
How do I get the Selected Value of a DropDownList in ASP.NET Core
MVC App
How to get DropDownList SelectedValue in Controller in MVC
SelectList from ViewModel from repository Asp.net core
Sorry if my question is naive I am new to ASP.net core MVC.
the code is as below:
namespace MyShop.ViewModels
{
public class CreateDealVM
{
public Deals deal { get; set; }
public IEnumerable<SelectListItem> CustomerListVM { get; set; }
}
}
The Model class:
namespace MyShop.Models
{
[Table("Deals")]
public class Deals
{
[Key]
[Display(Name = "ID")]
public int dealId { get; set; }
[ForeignKey("Customer")]
[Display(Name = "Customer")]
public Customer customer { get; set; }
[Display(Name = "CustomerName")]
public string? parentCustomerName { get; set; }
[Display(Name = "product")]
public DealTypeEnum product { get; set; }
[Display(Name = "Date")]
public DateTime saleDate { get; set; }
[Display(Name = "Quantity")]
public float quantity { get; set; }
[Display(Name = "Price")]
public float price { get; set; }
}
The Controller:
public IActionResult Create()
{
CreateDealVM vm = new CreateDealVM();
vm.CustomerListVM = _context.Customers.Select(x => new SelectListItem { Value = x.customerId.ToString(), Text = x.customerName }).ToList();
return View(vm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind("dealId,customer,product,saleDate,quantity,price")] Deals deal, CreateDealVM vm)
{
if (ModelState.IsValid)
{
try
{
vm.deal.customer = _context.Customers.Find(vm.CustomerListVM);
vm.deal = deal;
_context.Deals.Add(vm.deal);
_context.SaveChanges();
return RedirectToAction("Index");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return View(vm);
}
else
{
var errors = ModelState.Select(x => x.Value.Errors)
.Where(y => y.Count > 0)
.ToList();
//The Error showed here.
}
return View(vm);
}
The view:
#model MyShop.ViewModels.CreateDealVM
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Deals</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">
#Html.LabelFor(model => model.deal.customer, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.CustomerListVM,Model.CustomerListVM,"Select Customer", htmlAttributes: new { #class = "form-control"})
</div>
</div>
<div class="form-group">
<label asp-for="deal.product" class="control-label"></label>
<select asp-for="deal.product" class="form-control"></select>
<span asp-validation-for="deal.product" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="deal.saleDate" class="control-label"></label>
<input asp-for="deal.saleDate" class="form-control" />
<span asp-validation-for="deal.saleDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="deal.quantity" class="control-label"></label>
<input asp-for="deal.quantity" class="form-control" />
<span asp-validation-for="deal.quantity" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="deal.price" class="control-label"></label>
<input asp-for="deal.price" class="form-control" />
<span asp-validation-for="deal.price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
I just realise your Model is wrong
[Table("Deals")]
public class Deals
{
[Key]
[Display(Name = "ID")]
public int dealId { get; set; }
[ForeignKey("Customer")]
[Display(Name = "Customer")]
public int CustomerId { get; set; }
[Display(Name = "CustomerName")]
public string? parentCustomerName { get; set; }
[Display(Name = "product")]
public DealTypeEnum product { get; set; }
[Display(Name = "Date")]
public DateTime saleDate { get; set; }
[Display(Name = "Quantity")]
public float quantity { get; set; }
[Display(Name = "Price")]
public float price { get; set; }
public virtual Customer Customer { get; set; }
Change the Dropdown
<div class="col-md-10">
#Html.DropDownListFor(model => model.Deal.CustomerId,Model.CustomerListVM,"Select Customer", htmlAttributes: new { #class = "form-control"})
</div>
one more thing since you have created viewmodel for deal. You only need to do this on your Post Controller
public IActionResult Create()
{
CreateDealVM vm = new CreateDealVM();
vm.CustomerListVM = new SelectList (_context.Customers select new { Id = x.customerId.ToString(), Text = x.customerName }),
"Id","Text");
return View(vm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Deals deal)
{
CreateDealVM vm = new CreateDealVM();
vm.deal = deal;
vm.CustomerListVM = new SelectList (_context.Customers select new { Id = x.customerId.ToString(), Text = x.customerName }),
"Id","Text",VM.CustomerId);
if (ModelState.IsValid)
{
try
{
_context.Deals.Add(vm.deal);
_context.SaveChanges();
return RedirectToAction("Index");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return View(vm);
}
else
{
var errors = ModelState.Select(x => x.Value.Errors)
.Where(y => y.Count > 0)
.ToList();
//The Error showed here.
}
return View(vm);
}

Only Bind certain properties of the navigation properties inside my action method

I have the following 2 model classes:-
public Submission()
{
SubmissionQuestionSubmission = new HashSet<SubmissionQuestionSubmission>();
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Npi { get; set; }
public bool Independent { get; set; }
public string Comment { get; set; }
public virtual ICollection<SubmissionQuestionSubmission> SubmissionQuestionSubmission { get; set; }
}
public partial class SubmissionQuestionSubmission
{
public int SubmissionQuestionId { get; set; }
public int SubmissionId { get; set; }
public string Answer { get; set; }
public virtual Submission Submission { get; set; }
}
and i created the following view model:-
public class SubmissionCreate
{
public Submission Submission {set; get;}
public IList<SubmissionQuestion> SubmissionQuestion { set; get; }
public IList<SubmissionQuestionSubmission> SubmissionQuestionSubmission { set; get; }
}
then inside my view i only need to submit back the following fields:-
#model LandingPageFinal3.ViewModels.SubmissionCreate
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Submission.FirstName" class="control-label"></label>
<input asp-for="Submission.FirstName" class="form-control" />
<span asp-validation-for="Submission.FirstName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.LastName" class="control-label"></label>
<input asp-for="Submission.LastName" class="form-control" />
<span asp-validation-for="Submission.LastName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.Npi" class="control-label"></label>
<input asp-for="Submission.Npi" class="form-control" />
<span asp-validation-for="Submission.Npi" class="text-danger"></span>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="Submission.Independent" /> #Html.DisplayNameFor(model => model.Submission.Independent)
</label>
</div>
<div class="form-group">
<label asp-for="Submission.Comment" class="control-label"></label>
<textarea asp-for="Submission.Comment" class="form-control"></textarea>
<span asp-validation-for="Submission.Comment" class="text-danger"></span>
</div>
<div id="additionalInfo">
#for (var i = 0; i < Model.SubmissionQuestion.Count(); i++)
{
<label>#Model.SubmissionQuestion[i].Question</label><br />
<input asp-for="#Model.SubmissionQuestion[i].Question" hidden />
<textarea asp-for="#Model.SubmissionQuestionSubmission[i].Answer" class="form-control"></textarea>
<input asp-for="#Model.SubmissionQuestionSubmission[i].SubmissionQuestionId" hidden />
<br />
}
</div>
so i define the following binding inside my post action method, to only bind the fields inside my view, as follow:-
public async Task<IActionResult> Create([Bind(Submission.FirstName,Submission.LastName,Submission.Npi,Submission.Independent" +
"Submission.Comment,SubmissionQuestionSubmission.Answer,SubmissionQuestionSubmission.SubmissionQuestionId")] SubmissionCreate sc )
{
but the sc.Submission and the sc.SubmissionQuestionSubmission will be null inside my action method... so not sure what is the minimum binding i should define, to prevent hacking our application by posting back extra info and navigation properties other than the ones defined in my view?
You don't need to use bind to bind only the fields that appear in your view.
In fact, your view has set the name attribute for the fields you need to display, so
SubmissionCreate sc will only bind the corresponding fields in the view when accepting.
Just use this code to receive:
public async Task<IActionResult> Create(SubmissionCreate sc)
{
return View();
}
Update
Since you only bound some fields in the view, you only need to exclude the SubmissionQuestion field value:
public async Task<IActionResult> Create([Bind("Submission", "SubmissionQuestionSubmission")]SubmissionCreate sc)
{
return View();
}
If you want to be more precise, you can bind the fields you need to the Submission and SubmissionQuestionSubmission classes separately, as follows:
[Bind("FirstName,LastName,Npi,Independent,Comment")]
public class Submission
{
public Submission()
{
SubmissionQuestionSubmission = new HashSet<SubmissionQuestionSubmission>();
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Npi { get; set; }
public bool Independent { get; set; }
public string Comment { get; set; }
public virtual ICollection<SubmissionQuestionSubmission> SubmissionQuestionSubmission { get; set; }
}
[Bind("Answer,SubmissionQuestionId")]
public partial class SubmissionQuestionSubmission
{
[Key]
public int SubmissionQuestionId { get; set; }
public int SubmissionId { get; set; }
public string Answer { get; set; }
public virtual Submission Submission { get; set; }
}

MVC navigating from Index to enhanced Edit view

I have a simple Index view, where I am displaying products as a product catalog.
ViewModel:
public class Products
{
public int ID { get; set; }
public int CategoryID { get; set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public string ProductPicturePath { get; set; }
public string UnitCost { get; set; }
public string UnitPrice { get; set; }
public string LowestUnitPrice { get; set; }
public string SubscriptionPrice { get; set; }
public string UnitMargin { get; set; }
public string UnitProfit { get; set; }
public bool InCatalog { get; set; }
}
View:
#using freshNclean.Models
#model IEnumerable<freshNclean.Models.Products>
#{
ViewBag.Title = "Sortiment";
}
<div id="productCatalogContainer" class="container">
<div id="productCatalogHeaderSection" class="headerSection">
<h1 id="productCatalogHeaderTitle" class="headerTitle">
#ViewBag.Title
</h1>
<i id="productCatalogHeaderIcon" class="headerIcon fas fa-gem" aria-hidden="true"></i>
</div>
<!-- table section -->
<section id="productCatalogListPartialSection" class="table">
<div id="productCatalogSeparatorSection" class="separatorSection">
<hr id="productCatalogSeparator" class="separator" />
</div>
<div id="productCatalog" class="productTableSection row">
#foreach (var item in Model)
{
if (item.InCatalog == true)
{
<a id="productCatalogProductArea" class="tableArea col-xs-offset-1 col-xs-10 col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-3 col-lg-offset-2 col-lg-3" href="#Url.Action("Details", "ShowProduct", new { id = item.ID })">
#Html.HiddenFor(modelItem => item.ID, new { #class = "tableField col-xs-12 col-sm-12 col-md-12 col-lg-12" })
<img id="productCatalogProductImage" class="tableImage col-xs-12 col-sm-12 col-md-12 col-lg-12" src="#Url.Content(item.ProductPicturePath)" alt="Produktbild" />
<div id="productCatalogProductNameField" class="tableField col-xs-12 col-sm-12 col-md-12 col-lg-12">
#Html.DisplayFor(modelItem => item.ProductName)
</div>
<div id="productCatalogProductDescriptionField" class="tableField col-xs-12 col-sm-12 col-md-12 col-lg-12">
#Html.DisplayFor(modelItem => item.ProductDescription)
</div>
<div id="productCatalogLowestUnitPriceField" class="tableField col-xs-12 col-sm-12 col-md-12 col-lg-12">
ab #Html.DisplayFor(modelItem => item.LowestUnitPrice)
</div>
</a>
}
}
</div>
<div id="productCatalogListPartialMenuSeparatorSection" class="separatorSection">
<hr id="productCatalogListPartialMenuSeparator" class="separator" />
</div>
#Html.ActionLink("zum Warenkorb", "ShowShoppingCart", "", htmlAttributes: new { #class = "formButton col-xs-offset-1 col-xs-10 col-sm-offset-1 col-sm-10 col-md-offset-3 col-md-6 col-lg-offset-3 col-lg-6" })
</section>
</div>
<!-- link back to menu -->
<div id="productCatalogReturnToMenuSection" class="linkSection">
#Html.ActionLink("zurück zum Menü", "Profile", "", htmlAttributes: new { #id = "productCatalogReturnToMenuButton", #class = "link" })
</div>
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<!-- Google Places -->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBYK8aBCsb1dFrzXqIgUq07ZwO3w3_fGCs&libraries=places&callback=initAutocomplete" async defer></script>
}
Controller:
// GET: /freshNclean/ProductCatalog
public ActionResult ProductCatalog()
{
// define variables
var userID = User.Identity.GetUserId();
DateTime nowUTC = DateTime.Now.ToUniversalTime();
DateTime nowLocal = DateTime.Now.ToLocalTime();
// pass first name to viewbag for personalization
//ViewBag.Personalization = UserManager.FindById(userID).FirstName.ToString();
// track user activity: get method is restricted to activity name and timestamp
var LOADED = new UserActivities
{
UserID = userID,
ActivityName = "ProductCatalog_Loaded",
ActivityTimeStampUTC = nowUTC,
ActivityLatitude = "n/a",
ActivityLongitude = "n/a",
ActivityLocation = "n/a"
};
DATADB.UserActivityList.Add(LOADED);
DATADB.SaveChanges();
return View(DATADB.ProductList.Where(x => x.InCatalog == true).OrderBy(x => x.ProductName).ToList());
}
This all works fine.. but now I wish to click on an individual product to display a new view with details of the product and the possibility to define order quantity.
New VM:
public class ProductViewModel
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public string ProductPicturePath { get; set; }
[RegularExpression(#"^\((\d{3}?)\)$", ErrorMessage = "Du brauchst die Anzahl nicht ausschreiben - verwende Ziffern.")]
[Display(Name = "Bestellmenge")]
public string SubscriptionQuantity { get; set; }
[Display(Name = "Lieferrhytmus")]
public string SubscriptionCadenceCategory { get; set; }
public string SubscriptionCadenceValue { get; set; }
[Display(Name = "Preis im Abonnement")]
public string SubscriptionPrice { get; set; }
public bool IsSingleOrder { get; set; }
[RegularExpression(#"^\((\d{3}?)\)$", ErrorMessage = "Du brauchst die Anzahl nicht ausschreiben - verwende Ziffern.")]
[Display(Name = "Bestellmenge")]
public string Quantity { get; set; }
[Display(Name = "Preis pro Einheit")]
public string UnitPrice { get; set; }
public DateTime ActivityDateTime { get; set; }
public string ActivityLatitude { get; set; }
public string ActivityLongitude { get; set; }
public string ActivityLocation { get; set; }
}
Now, where I got stuck is how I would display the new, enhanced model - the issue I run into is that with the standard approach, clicking a product in the product catalog is creating something like /ShowProduct/5 in the URL, but that would force me to use the same view model in the details view as in the catalog, which is not what I want/need. If anyone has an idea how to solve this, I'd highly appreciate your input. Also, please note that I am an absolute beginner, hence examples are highly appreciated. Thank you!

MVC Subitem list

I am trying to create an entity that has subitems and am having issues with passing the model back and forth.
I have an entity RiskAssessnent that contains a list of Risk entities.
public class RiskAssessment
{
public int Id { get; set; }
public DateTime Date { get; set; }
public ICollection<Risk> Risks { get; set; }
public int ResidentId { get; set; }
public Resident Resident { get; set; }
public int EmployeeId { get; set; }
public Employee Employee { get; set; }
}
public class Risk
{
public int Id { get; set; }
public string Description { get; set; }
public int RiskAssessmentId { get; set; }
public RiskAssessment RiskAssessment { get; set; }
}
here is my view for creating a RiskAssessment:
#model CareHomeMvc6.Models.RiskAssessmentViewModels.RiskAssessmentViewModel
#{
ViewData["Title"] = "Create";
}
<a class="btn btn-default" asp-action="Index" asp-route-residentId="#Model.ResidentId">Back to List</a>
<div class="page-header">
<h1>Create a Risk Assessment</h1>
</div>
<form asp-action="Create">
<div class="form-horizontal">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
#Html.HiddenFor(m => m.EmployeeId)
#Html.HiddenFor(m => m.ResidentId)
<div class="form-group">
<label asp-for="Date" class="col-md-2 control-label"></label>
<div class="col-md-10">
#Html.EditorFor(m => m.Date, new { #class = "form-control" })
<span asp-validation-for="Date" class="text-danger" />
</div>
</div>
#foreach(var risk in Model.Risks)
{
<h3>#risk.Description</h3>
}
<p>
<a class="btn btn-success" asp-action="CreateRisk">Create</a>
</p>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
</form>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
and here is the controller:
public IActionResult CreateRisk(RiskAssessmentViewModel riskAssessmentViewModel)
{
var vm = new CreateRiskViewModel
{
RiskAssessment = riskAssessmentViewModel,
Risk = new Risk()
};
return View(vm);
}
and the ViewModel:
public class RiskAssessmentViewModel
{
public RiskAssessmentViewModel()
{
this.Risks = new List<Risk>();
this.Risks.Add(new Risk
{
Id = 1,
Description = "blah",
PotentialRisk = "blah"
});
}
public int Id { get; set; }
[Display(Name = "Date")]
[DataType(DataType.Date)]
[Required]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime Date { get; set; }
public ICollection<Risk> Risks { get; set; }
public int ResidentId { get; set; }
public int EmployeeId { get; set; }
}
Sorry for all the code so far!
I was attempting to keep passing the ViewModel back and forth until all items have been created but within the CreateRisk action the ResidentId and EmployeeId are 0 therefore not being set, although I do get the collection of risks. If I click submit on the form which encapsulates everything then they are set. Is there any reason the hidden items are being sent to the form submit but not the link action?
I realise there are JS solutions to doing dynamic lists but I wanted to stay away from it as the page navigation is acceptable, the form will when finished require a lot of data entry for a Risk.
Any help with this would be greatly appreciated.
Thanks

Error in my upload page after i changed my model [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 6 years ago.
I added the code to show many checkboxes from my table (HairTags) and in my form CreationUpload.cshtml i got the following error :
An exception of type 'System.NullReferenceException' occurred in
App_Web eba142hb.dll but was not handled in user code Additional
information: Object reference not set to an instance of an object.
Object reference not set to an instance of an object.
<div class="col-md-12">
#for (int i = 0; i < Model.CreationHairTags.Count; i++)
{
#Html.CheckBoxFor(m => Model.CreationHairTags[i].IsChecked)
#Model.CreationHairTags[i].Text
#Html.HiddenFor(m => Model.CreationHairTags[i].Value)
#Html.HiddenFor(m => Model.CreationHairTags[i].Text)<br />
}
</div>
this is my model Creation.cs (in bold the added code)
namespace HairCollection3.Models
{
public class Creation
{
public string UserId { get; set; }
[Key]
public int CreationId { get; set; }
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ViewRes.ValidationStrings))]
[Display(Name = "Sex", ResourceType = typeof(ViewRes.Names))]
public string CreationSex { get; set; }
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ViewRes.ValidationStrings))]
[Display(Name = "CreationTitle", ResourceType = typeof(ViewRes.NamesCreation))]
[StringLength(2000)]
[AllowHtml]
public string CreationTitle { get; set; }
public string CreationPhotoBis { get; set; }
public string Creationtag { get; set; }
public virtual ICollection<CreationLike> CreationLikes { get; set; }
}
public class CreationLike
{
public int CreationId { get; set; }
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
[Key]
public int CreationLikeId { get; set; }
public virtual Creation ParentCreation { get; set; }
}
public class HairTag
{
[Key]
public int HairTagId { get; set; }
[Required]
public string HairTagTitle { get; set; }
[Required]
public string HairTagType { get; set; }
[Required]
public int HairTagOrder { get; set; }
}
***//CHECKBOXES
public class HairTagModel
{
[Key]
public int Value { get; set; }
public string Text { get; set; }
public bool IsChecked { get; set; }
}
public class HairTagList
{
private ApplicationDbContext creationdb = new ApplicationDbContext();
public HairTagList()
{
var HairTagList = creationdb.HairTags.ToList();
List<HairTagModel> obj = new List<HairTagModel>();
foreach (var tags in HairTagList)
{
obj.Add(new HairTagModel
{
Text = tags.HairTagTitle,
Value = tags.HairTagId,
IsChecked = false
});
}
this.CreationHairTags = obj;
}
public List<HairTagModel> CreationHairTags { get; set; }
//public List<HairTagModel> ListHairTags { get; set; }
}
public class CreationHairTagsModel
{
public Creation Creation { get; set; }
public List<HairTagModel> CreationHairTags { get; set; }
}
}***
My controller CreationController.cs
// GET: /Creation/CreationUpload
[Authorize]
public ActionResult CreationUpload()
{
CreationHairTagsModel creation = new CreationHairTagsModel();
return View(creation);
//return View();
}
// POST: /Creation/CreationUpload
// Afin de déjouer les attaques par sur-validation, activez les propriétés spécifiques que vous voulez lier. Pour
// plus de détails, voir http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public ActionResult CreationUpload([Bind(Include = "CreationId,CreationSex,CreationTitle,CreationPhotoBis,CreationHairTags")] CreationHairTagsModel creation, IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
// update each field manually
foreach (var file in files)
{
if (file != null)
{
if (file.ContentLength > 0)
{
....CODE UPLOAD HIDDEN....
//Avoid Script
var CreationTitletocheck = Regex.Replace(creation.Creation.CreationTitle, #"<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>", string.Empty);
CreationTitletocheck = Regex.Replace(CreationTitletocheck, #"(?></?\w+)(?>(?:[^>'""]+|'[^']*'|""[^""]*"")*)>", string.Empty);
creation.Creation.CreationTitle = CreationTitletocheck;
//Tags
StringBuilder sb = new StringBuilder();
foreach (var item in creation.CreationHairTags)
{
if (item.IsChecked)
{
sb.Append(item.Text + ",");
}
}
creation.Creation.Creationtag = sb.ToString();
creation.Creation.UserId = User.Identity.GetUserId();
db.Creations.Add(creation.Creation);
db.SaveChanges();
}
}
}
}
//UserId
return RedirectToAction("CreationList", "Creation", new { UserId = User.Identity.GetUserId() });
}
return View(creation);
}
My page of upload CreationUpload.cshtml
#model HairCollection3.Models.CreationHairTagsModel
#using Microsoft.AspNet.Identity
#{
ViewBag.Title = ViewRes.NamesCreation.CreationUploadTitle;
}
<div class="col-sm-12 col-md-12 chpagetop">
<h1>#ViewRes.Shared.PublishAPhoto</h1>
<hr />
#using (Html.BeginForm("CreationUpload", "Creation", FormMethod.Post, new { id = "CreationUpload", enctype = "multipart/form-data", onsubmit = "$('#creationloading').show(); $('#creationform').hide();" }))
{
#Html.AntiForgeryToken()
<div class="col-md-12" id="creationloading" style="display:none">
<div id="progress">
<p>#ViewRes.Shared.UploadPhotoProgress<strong>0%</strong></p>
<progress value="5" min="0" max="100"><span></span></progress>
</div>
</div>
<div class="col-md-12" id="creationform">
<div class="col-md-12">
#Html.ValidationMessageFor(m => m.Creation.CreationSex)
#Html.RadioButtonFor(m => m.Creation.CreationSex, "F", new { #checked = true }) #ViewRes.Shared.WomanHairstyle #Html.RadioButtonFor(m => m.Creation.CreationSex, "M") #ViewRes.Shared.ManHairstyle
</div>
<div class="col-md-12">
#Html.ValidationMessageFor(m => m.Creation.CreationTitle)
#Html.TextBoxFor(m => m.Creation.CreationTitle, new { #class = "inputplaceholderviolet wid100x100", placeholder = HttpUtility.HtmlDecode(Html.DisplayNameFor(m => m.Creation.CreationTitle).ToHtmlString()), onfocus = "this.placeholder = ''", onblur = "this.placeholder = '" + HttpUtility.HtmlDecode(Html.DisplayNameFor(m => m.Creation.CreationTitle).ToHtmlString()) + "'" })
</div>
<div class="col-md-12">
#for (int i = 0; i < Model.CreationHairTags.Count; i++)
{
#Html.CheckBoxFor(m => Model.CreationHairTags[i].IsChecked)
#Model.CreationHairTags[i].Text
#Html.HiddenFor(m => Model.CreationHairTags[i].Value)
#Html.HiddenFor(m => Model.CreationHairTags[i].Text)<br />
}
</div>
<div class="col-md-12" style="text-align: center">
<p style="display: inline-block">
<input type="file" accept="image/*" onchange="loadFile(event)" name="files" id="file1" translate="yes" data-val="true" data-val-required="A File is required." class="wid100x100" /><label for="file1"></label>
<img id="output" style="max-width:200px;"/>
</p>
</div>
<div class="col-sm-12 col-md-12 chpagetopdiv">
<button type="submit" title="#ViewRes.Shared.Publish"><span class="glyphicon glyphicon-share-alt"></span> #ViewRes.Shared.Publish</button>
</div>
</div>
}
</div>
What is wrong in my code please help and explain ?
Important: In C#, every collection must be initialized before being accessed
The error occurs when you are trying to access from the View to the collection CreationHairTags, which is not initialized. Replace your model to initialize collection in the class constructor:
public class CreationHairTagsModel
{
public Creation Creation { get; set; }
public List<HairTagModel> CreationHairTags { get; set; }
public CreationHairTagsModel()
{
CreationHairTags = new List<HairTagModel>();
}
}

Resources