I'm trying to get a value from each dropdownlist in the view model. I'm doing with a foreach but that doesn't seem to work. Can anyone help me here please?
I'm doing in the controller the foreach. I'm using Entity Framework and repository methods to this. Any help is helpful.
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(int? id, AddSaidasServicoViewModel model, string command)
{
if (ModelState.IsValid)
{
//TODO: adicionar Userhelper para ver quem cria a saida. Criar campo na tabela BD. Ver apontamento Notepad
if (command.Equals("submit1"))
{
await _saidaservicoRepository.AddSaidaServicoAsync(model);
return RedirectToAction(nameof(Create));
}
else
{
foreach(var elementoId in model.Elementos )
{
await _elementoRepository.UpdateElementoSaidaServicosAsync(model);
}
}
return RedirectToAction(nameof(Index));
}
return View(model);
}
View markup:
#model FireHouseGest.web.Models.AddSaidasServicoViewModel
#{
ViewData["Title"] = "Create";
}
<h2>Criar</h2>
<h4>Saída Serviço</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="container">
<div class="row">
<div class="text-center">
<div class="col-md-3 text-center">
<div class="form-group">
<label asp-for="ServicoId" class="control-label"></label>
<select asp-for="ServicoId" asp-items="Model.Servicos" class="form-control"></select>
<span asp-validation-for="ServicoId" class="text-danger"></span>
</div>
</div>
<div class="col-md-3 text-center">
<div class="form-group">
<label asp-for="ViaturaId" class="control-label"></label>
<select asp-for="ViaturaId" asp-items="Model.Viaturas" class="form-control"></select>
<span asp-validation-for="ViaturaId" class="text-danger"></span>
</div>
</div>
</div>
</div>
<div class="form-group">
<input type="submit" name="command" value="submit1" class="btn btn-default" />
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-2 text-center">
<div class="form-group">
<label asp-for="ElementoId" class="control-label"></label>
<select asp-for="ElementoId" asp-items="Model.Elementos" class="form-control"></select>
<span asp-validation-for="ElementoId" class="text-danger"></span>
</div>
</div>
<div class="col-lg-2 text-center">
<div class="form-group">
<label asp-for="ElementoId" class="control-label"></label>
<select asp-for="ElementoId" asp-items="Model.Elementos" class="form-control"></select>
<span asp-validation-for="ElementoId" class="text-danger"></span>
</div>
</div>
<div class="col-lg-2 text-center">
<div class="form-group">
<label asp-for="ElementoId" class="control-label"></label>
<select asp-for="ElementoId" asp-items="Model.Elementos" class="form-control"></select>
<span asp-validation-for="ElementoId" class="text-danger"></span>
</div>
</div>
<div class="col-lg-2 text-center">
<div class="form-group">
<label asp-for="ElementoId" class="control-label"></label>
<select asp-for="ElementoId" asp-items="Model.Elementos" class="form-control"></select>
<span asp-validation-for="ElementoId" class="text-danger"></span>
</div>
</div>
<div class="col-lg-2 text-center">
<div class="form-group">
<label asp-for="ElementoId" class="control-label"></label>
<select asp-for="ElementoId" asp-items="Model.Elementos" class="form-control"></select>
<span asp-validation-for="ElementoId" class="text-danger"></span>
</div>
</div>
</div>
<div class="form-group">
<input type="submit" name="command" value="submit2" class="btn btn-default" />
</div>
</div>
<div class="form-group">
<label asp-for="Adecorrer" class="control-label"></label>
<input asp-for="Adecorrer" class="form-control" />
<span asp-validation-for="Adecorrer" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Inicio" class="control-label"></label>
<input asp-for="Inicio" class="form-control" />
<span asp-validation-for="Inicio" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Fim" class="control-label"></label>
<input asp-for="Fim" class="form-control" />
<span asp-validation-for="Fim" class="text-danger"></span>
</div>
</form>
</div>
</div>
ViewModel
namespace FireHouseGest.web.Models
{
public class AddSaidasServicoViewModel
{
public int SaidaServicoId { get; set; }
[Display(Name = "Elementos")]
public int ElementoId { get; set; }
public IEnumerable<SelectListItem> Elementos { get; set; }
[Display(Name = "Viatura")]
public int ViaturaId { get; set; }
public IEnumerable<SelectListItem> Viaturas { get; set; }
[Display(Name = "Serviço")]
public int ServicoId { get; set; }
public IEnumerable<SelectListItem> Servicos { get; set; }
[Display(Name = "Estado")]
public int Adecorrer { get; set; }
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy hh:mm }", ApplyFormatInEditMode = false)]
public DateTime Inicio { get { return DateTime.Now; } }
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy hh:mm }", ApplyFormatInEditMode = false)]
public DateTime? Fim { get; set; }
public User user { get; set; }
}
}
This is what I have. Open to suggestions.
Before coding, you need know the following things:
1.Model Binding find and bind the property by matching the name of the input.
2.If you have multiple inputs with the same name, you need set a List<T> type parameter to receive all the values.
3.Dropdownlist gets the selected option value(not text),be sure the type of the value is the same with the type of matched property. (e.g. ElementoId is int type,so the value of each SelectListItem in Elementos should be int or it could be converted to int):
var model = new AddSaidasServicoViewModel()
{
Elementos = new List<SelectListItem>() {
new SelectListItem() { Value = "1", Text = "Elementos1" },
new SelectListItem() { Value = "2", Text = "Elementos2" },
new SelectListItem() { Value = "3", Text = "Elementos3" }
},
//....
};
4.Dropdownlist selected value will match the property by searching the same name of the asp-for="xxx". (e.g. asp-for="ElementoId" will generate html:id="ElementoId" name="ElementoId",so this input value will match the property ElementoId in your model)
5.Although you have two submit button, but the submit button will always submit all the input values which they are in the same form.
Change your code like below and you will receive all the selected ElementoId values in List<string> ElementoId:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(int? id, AddSaidasServicoViewModel model,
List<string> ElementoId, string command)
{
if (ModelState.IsValid)
{
//TODO: adicionar Userhelper para ver quem cria a saida. Criar campo na tabela BD. Ver apontamento Notepad
if (command.Equals("submit1"))
{
//...
}
else
{
foreach (var elementoId in ElementoId)
{
//....
}
}
return RedirectToAction(nameof(Index));
}
return View(model);
}
Thanks Rena for answer. this was what i did.
public async Task UpdateElementosSaidasAsync(AddSaidasServicoViewModel model, List<string> Elementos)
{
int SaidaServicos = _context.SaidaServicos.Max(item => item.Id);
var Saida = await _context.SaidaServicos.FindAsync(SaidaServicos);
if (Elementos == null)
{
return;
}
else
{
foreach (var elementoId in Elementos)
{
var updateElementoSaida = _context.Elementos.Where(e => e.Id == Convert.ToInt32(elementoId)).FirstOrDefault();
updateElementoSaida.saidaServico = Saida;
await _context.SaveChangesAsync();
}
}
return;
}
Related
I have a page that is supposed to submit data for a patient evaluation. The page to submit the evaluation comes up fine. It is based on a ViewModel. Here is the ViewModel:
public class SPEPatientEvalVM
{
public int Id { get; set; }
public int ApptId { get; set; }
public int ActivityID { get; set; }
public int VendorID { get; set; }
public int PatientID { get; set; }
[Required(ErrorMessage ="A selection is required.")]
public int OverallRating { get; set; }
[Required(ErrorMessage = "A selection is required.")]
public int AppearProfessComp { get; set; }
[Required(ErrorMessage = "A selection is required.")]
public int EffGatheredInfo { get; set; }
[Required(ErrorMessage = "A selection is required.")]
public int ListenActively { get; set; }
[Required(ErrorMessage = "A selection is required.")]
public int EstabPersRapport { get; set; }
[Required(ErrorMessage = "A selection is required.")]
public int AppropExploreMyFeelings { get; set; }
[Required(ErrorMessage = "A selection is required.")]
public int AddressedMyFeelings { get; set; }
[Required(ErrorMessage = "A selection is required.")]
public int MetMyNeeds { get; set; }
public string PatientComments { get; set; } = String.Empty;
public DateTime DateSubmitted { get; set; }
}
This is mapped and reverse mapped to the model using IMapper.
Anyway this is my controller code:
[HttpGet("[controller]/[action]/{IDAppt}/{ActivityID}/{VendorID}/{PatientID}")]
public async Task<IActionResult> AddSPEPatientEval(int IDAppt, int ActivityID, int VendorID, int PatientID)
{
var patientChoice = GetPatientChoiceList();
patientChoice[0].Selected = true;
ViewBag.PatientChoice = patientChoice;
var evalParams = await _speRepo.GetOpenPatientEval(IDAppt);
ViewBag.Patient = evalParams.SPEPatient;
var speEval = new SPEPatientEvalVM
{
ApptId = IDAppt,
ActivityID = ActivityID,
VendorID = VendorID,
PatientID = PatientID
};
return View(speEval);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddSPEPatientEval(SPEPatientEvalVM model)
{
var patientChoice = GetPatientChoiceList();
patientChoice[0].Selected = true;
ViewBag.PatientChoice = patientChoice;
model.DateSubmitted = DateTime.Now;
if (ModelState.IsValid)
{
var spePatientEval = _mapper.Map<SPEPatientEval>(model);
var success = await _speRepo.AddSPEPatientEval(spePatientEval);
if (!success)
{
return View(model);
}
return View("Index");
}
return View(model);
}
This is all for the form AddSPEPatientEval.cshtml
#model SPEPatientEvalVM
#{
ViewData["Title"] = "AddSPEPatientEval";
}
<div class="col-md-8 m-auto">
<h1 class="text-center">Patient SPE Evaluation</h1>
<hr />
</div>
<div class="col-md-8 m-auto">
<div class="row">
<div class="col-md-12">
<form asp-controller="SPE" asp-action="AddSPEPatientEval" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="ApptId" />
<input type="hidden" asp-for="ActivityID" />
<input type="hidden" asp-for="VendorID" />
<input type="hidden" asp-for="PatientID" />
<input type="hidden" asp-for="DateSubmitted" value="#String.Format("{0:MM/dd/yyyy}", DateTime.Now)" />
<div class="row">
<div class="col-md-8 m-auto">
<div class="form-group">
<label asp-for="OverallRating" class="control-label">As #ViewBag.Patient, rate your overall level of satisfaction with this encounter.</label>
<select asp-for="OverallRating" class="form-control"
asp-items="#(new SelectList(ViewBag.PatientChoice, "Value", "Text"))"></select>
<span asp-validation-for="OverallRating" class="text-danger"></span>
</div>
<br />
<hr />
</div>
</div>
<br />
<div class="row">
<div class="col-md-8 m-auto">
<div class="form-group">
<label asp-for="AppearProfessComp" class="control-label">Appeared professional competent - seemed to know what s/he was
doing; inspired my comfidence; appeared to have my interests at heart.
</b></label>
<select asp-for="AppearProfessComp" class="form-control"
asp-items="#(new SelectList(ViewBag.PatientChoice, "Value", "Text"))"></select>
<span asp-validation-for="AppearProfessComp" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8 m-auto">
<div class="form-group">
<label asp-for="EffGatheredInfo" class="control-label">Effectively gathered information - collected information in a way that
seemed organized; began with several open-ended questions and progressed through interview using a balanced ratio of open-
to closed-ended questions; summarized periodically.
</label>
<select asp-for="EffGatheredInfo" class="form-control"
asp-items="#(new SelectList(ViewBag.PatientChoice, "Value", "Text"))"></select>
<span asp-validation-for="EffGatheredInfo" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8 m-auto">
<div class="form-group">
<label asp-for="ListenActively" class="control-label">Listened actively - paid attention to both my verbal and non-verbal
cues; used facial expressions/body language to express encouragement; avoided interruptions; asked questions to make sure
s/he understood what I said.
</label>
<select asp-for="ListenActively" class="form-control"
asp-items="#(new SelectList(ViewBag.PatientChoice, "Value", "Text"))"></select>
<span asp-validation-for="ListenActively" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8 m-auto">
<div class="form-group">
<label class="control-label">Established personal rapport - introduced self warmly; verbally/non-verbally showed interest
in me as a person, not just my condition; avoided technical jargon.
</label>
<select asp-for="EstabPersRapport" class="form-control"
asp-items="#(new SelectList(ViewBag.PatientChoice, "Value", "Text"))"></select>
<span asp-validation-for="EstabPersRapport" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8 m-auto">
<div class="form-group">
<label asp-for="AppropExploreMyFeelings" class="control-label">Appropriately explored my perspective - encouraged me to
identify everything that I needed to say.
</label>
<select asp-for="AppropExploreMyFeelings" class="form-control"
asp-items="#(new SelectList(ViewBag.PatientChoice, "Value", "Text"))"></select>
<span asp-validation-for="AppropExploreMyFeelings" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8 m-auto">
<div class="form-group">
<label asp-for="AddressedMyFeelings" class="control-label">Addressed my feelings - acknowledged and demonstrated interest in my
expressed and/orunexpressed feelings and experience.
</label>
<select asp-for="AddressedMyFeelings" class="form-control"
asp-items="#(new SelectList(ViewBag.PatientChoice, "Value", "Text"))"></select>
<span asp-validation-for="AddressedMyFeelings" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8 m-auto">
<div class="form-group">
<label asp-for="MetMyNeeds" class="control-label">Met my needs - worked toward a plan which addressed both the diagnosis and
my concerns about my illness.
</label>
<select asp-for="MetMyNeeds" class="form-control"
asp-items="#(new SelectList(ViewBag.PatientChoice, "Value", "Text"))"></select>
<span asp-validation-for="MetMyNeeds" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8 m-auto">
<div class="form-group">
<label asp-for="PatientComments" class="control-label"></label>
<textarea asp-for="PatientComments" class="form-control"
placeholder="Please add any additional comments you would like to express about this examination."></textarea>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8 m-auto">
<div class="form-group">
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8 m-auto">
<div class="text-center">
<a asp-action="Index">Back to List</a>
</div>
</div>
</div>
#section Scripts {
#{
await Html.RenderPartialAsync("_ValidationScriptsPartial");
}
}
Once the form is completed and all required fields are entered, if I hit the "Submit" button, I get:
This localhost page can’t be found
No webpage was found for the web
address:
https://localhost:5001/SPE/AddSPEPatientEval/18659/15129/235/4
HTTP ERROR 404
What am I missing guys? I am sure it is something that is in plain site. I am just have looked at it too long and cannot find what is going on.
What have I tried... I feel like everything. I have tried adding a route to the HttpPost statement. I have tried making sure all the model fields are not null. I do not know what else to try.
Thanks in advance for any help.
Your POST route should match the GET route:
[HttpPost("[controller]/[action]/{IDAppt}/{ActivityID}/{VendorID}/{PatientID}")]
Add [FromRoute] to the action parameters:
[HttpGet("[controller]/[action]/{IDAppt}/{ActivityID}/{VendorID}/{PatientID}")]
public async Task<IActionResult> AddSPEPatientEval([FromRoute]int IDAppt, [FromRoute] int ActivityID, [FromRoute] int VendorID, [FromRoute] int PatientID)
You should also change HttpGet to HttpPost.
I have a simple MVC app that is consuming a web api via REST. The controller in the MVC app makes http calls to the web api to populate views within the MVC app with razor syntax.
I am trying to figure out how to populate a drop down list on one of the 'create' actions. I'm currently just using the scaffolded page:
#model ComicBookInventory.Shared.ComicBookWithAuthorsAndCharactersViewModel
#{
ViewData["Title"] = "CreateComicBook";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>CreateComicBook</h1>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="CreateComicBook">
<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="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");
}
}
Which gets populated from this action in the controller:
public async Task<IActionResult> CreateComicBook(ComicBookWithAuthorsAndCharactersViewModel model)
{
string uri = $"https://localhost:5001/api/comicbook/add-book/";
HttpClient client = _httpClientFactory.CreateClient(
name: "ComicBookInventory.Api");
var postTask = await client.PostAsJsonAsync<ComicBookWithAuthorsAndCharactersViewModel>(uri, model);
if (postTask.IsSuccessStatusCode)
{
return RedirectToAction("GetAllComics");
}
else
{
return View(model);
}
}
Here is the view model definition:
namespace ComicBookInventory.Shared
{
public class ComicBookWithAuthorsAndCharactersViewModel
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public bool IsRead { get; set; }
public DateTime? DateRead { get; set; }
public int? Rating { get; set; }
public string Genre { get; set; }
public string? CoverUrl { get; set; }
/// <summary>
/// Navigation properties
/// </summary>
/// a book can have many authors
public ICollection<string>? AuthorNames { get; set; }
public ICollection<string>? CharacterNames { get; set; }
}
}
My question is, I want to add a drop down checklist to the view, so that when I am creating a comic book, I can select Authors that currently exist in the database. The same for characters.
Here is the entire code base in case anyone is interested: https://github.com/rnemeth90/ComicBookInventoryApp
I normally try and figure things out on my own (I'm relatively new to EF Core, and have very little experience with many-to-many relationships in EF core). I have tried various things and struggled with this for most of my weekend. I feel like this should be relatively simple but cannot figure it out. Please help.
In your Code, I noticed that you used #Html.DropDownList to realzie the selector element, and using form submit to handle the data. So I did a test in my side:
#{
List<SelectListItem> listItems= new List<SelectListItem>();
listItems.Add(new SelectListItem
{
Text = "Exemplo1",
Value = "Exemplo1_v"
});
listItems.Add(new SelectListItem
{
Text = "Exemplo2",
Value = "Exemplo2_v",
Selected = true
});
listItems.Add(new SelectListItem
{
Text = "Exemplo3",
Value = "Exemplo3_v"
});
}
<form asp-action="Create">
<div class="form-group">
AuthorNames
<div class="col-md-10">
#Html.DropDownListFor(model => model.Author, listItems, "-- Select author --")
</div>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
My model contains a public string? Author { get; set; } property, and when I click the submit button, the select value will be submitted, so when you want to pass the FullName to your controller, you need to set it as the Value of the SelectListItem.
I have an application which simulates a clothing site.I try to build my C# object with the data that the user writes in the form and the products they bought on the site.The products are represented by a JSON object.I use 2 classes: one for the shopping cart and one for the product.
public class Product
{
[Key]
public int id { get; set; }
public string productName { get; set; }
public string productPrice { get; set; }
public string quantity { get; set; }
}
public class ShoppingCart
{
[Key]
public int? id { get; set; }
public List<Product> productList { get; set; }
public string clientName { get; set; }
public string clientAddress { get; set; }
public string clientMail { get; set; }
}
I use a controller which has the method "Save" which uses the [FromForm] attribute.After the objects is binded from the client side I add it to my database.The problem is that I get "null" values for every property in my ShoppingCart object that is sent to the method.Moreover in my browser, the data is sent correctly to the server:
screenshot from network tab in chrome
The controller that I use looks like this:
[Route("SendItems/Save")]
[ApiController]
public class SendItemsController : Controller
{
private AppDbContext _db;
public SendItemsController(AppDbContext db)
{
_db = db;
}
[HttpPost]
[Consumes("application/json")]
public async Task<IActionResult> Save([FromForm] ShoppingCart s)
{
await _db.ShoppingCarts.AddAsync(s);
await _db.SaveChangesAsync();
return RedirectToAction("Index");
}
[HttpGet("~/ThankYou/Index")]
public IActionResult Index()
{
return View();
}
}
My html for the form is written like this:
#model ShoppingCart
<div class="form-group row">
<div class="col-4">
<label id="clienId"></label>
</div>
<div class="col-6">
<input asp-for="id" id="idClient" type="hidden" />
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label id="clientProds"></label>
</div>
<div class="col-6">
<input asp-for="productList" id="inputProducts" type="hidden" />
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label id="clientName"></label>
</div>
<div class="col-6">
<input asp-for="clientName" id="inputName" type="text" />
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label id="clientAddress"></label>
</div>
<div class="col-6">
<input asp-for="clientAddress" id="inputAddress" type="text" />
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label id="clientMail"></label>
</div>
<div class="col-6">
<input asp-for="clientMail" id="inputMail" type="text" />
</div>
</div>
<div class="form-group row">
<div class="col-3 offset-4">
<button class="btn btn-primary" id="orderB" asp-controller="SendItems" action="Save" type="submit">ORDER</button>
</div>
</div>
</form>
Also another issue is that if I don't use this piece of javascript the client is not redirected anymore to the "ThankYou" page :
var orderB = document.getElementById("orderB");
orderB.addEventListener("click", function () {
var inputName = document.getElementById("inputName").value;
var inputAddress = document.getElementById("inputAddress").value;
var inputMail = document.getElementById("inputMail").value;
var auxArray = [];
for (var i = 0; i < productsAux.length; i++) {
if (productsAux[i]!="") {
auxArray[i-1] = { "productName": productsAux[i].titlu, "productPrice": productsAux[i].pret, "quantity": localStorage.getItem(productsAux[i].titlu) };
}
}
document.getElementById("inputProducts").value = JSON.stringify(auxArray);
var shoppingCart = {
productList: auxArray,
clientName: inputName,
clientAddress: inputAddress,
clientMail: inputMail
};
$.ajax({
type: "POST",
data: JSON.stringify(shoppingCart),
url: "senditems/save",
contentType: "application/json;charset=utf-8",
})
})
Here is a demo worked:
Cart.cshtml(You need to change the bind of `productList,and then you don't need to use ajax to pass data to controller):
<form method="post" asp-controller="SendItems" asp-action="Save">
<div class="form-group row">
<div class="col-4">
<label id="clienId"></label>
</div>
<div class="col-6">
<input asp-for="id" id="idClient" type="hidden" />
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label id="clientProds"></label>
</div>
<div class="col-6">
#for (var i = 0; i < Model.productList.Count(); i++)
{
<input type="hidden" asp-for="#Model.productList[i].id" />
<input type="hidden" asp-for="#Model.productList[i].productName" />
<input type="hidden" asp-for="#Model.productList[i].productPrice" />
<input type="hidden" asp-for="#Model.productList[i].quantity" />
}
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label id="clientName"></label>
</div>
<div class="col-6">
<input asp-for="clientName" id="inputName" type="text" />
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label id="clientAddress"></label>
</div>
<div class="col-6">
<input asp-for="clientAddress" id="inputAddress" type="text" />
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label id="clientMail"></label>
</div>
<div class="col-6">
<input asp-for="clientMail" id="inputMail" type="text" />
</div>
</div>
<div class="form-group row">
<div class="col-3 offset-4">
<button class="btn btn-primary" id="orderB" type="submit" >ORDER</button>
</div>
</div>
</form>
Controller(SendItems):
[HttpPost]
public async Task<IActionResult> Save(ShoppingCart s)
{
return RedirectToAction("Index");
}
[HttpGet("~/ThankYou/Index")]
public IActionResult Index()
{
return View();
}
public IActionResult Cart()
{
ShoppingCart s = new ShoppingCart { id = 1, clientAddress = "address", clientName = "name1", clientMail = "123#123", productList = new List<Product> { new Product { id = 1, productName = "p1", productPrice = "10", quantity = "1" }, new Product { id = 2, productName = "p12", productPrice = "12", quantity = "3" } } };
return View(s);
}
result:
Is my ViewModel flow right? The 'SubObjectViewModel' class usage is a bad or a good practice? Or should I try other option, like creating a ViewModel only to this class?
And also, how should I return the ViewModel 'ObjectViewModel' to the controller with all its values, change them and refresh values from page view?
My ViewModel
Public class ObjectViewModel{
public string name { get; set; }
public int value { get; set; }
public bool IsCameraPermited { get; set; }
public List<SubObjectViewModel> choosenSubObjects{ get; set; } // need to get it back on controller;
public class SubObjectViewModel
{
public int IdObject { get; set; }
public string Name { get; set; }
public string Config { get; set; }
}
public List<Object> listSub{ get; set; } //list that will be filled on 'Create' Controller
}
My Controller
public IActionResult Create(int id)
{
List<Object> listSubObject = new List<Object>();
listSubObject = _getAllSubObjectsDAO.ListByID(id);
List<Object> choosenObjects= new List<Object>();
choosenObjects = _getChoosenObjectsDAO.ListByID(id);
List<SubObjectViewModel> listSubObject = new List<SubObjectViewModel>();
foreach (Object item in choosenObjects )
{
string config = _configurationDAO.GetConfigurationById(item.configId);
ObjectViewModel .SubObjectViewModel SubObject = new ObjectViewModel .SubObjectViewModel { IdObject = item.Id, Name = item.Name , Config = config };
listSubObject.Add(setorVM);
}
ObjectViewModel objVM = ObjectViewModel{
name ="test",
value = 2,
IsCameraPermited =true,
listSub = listSubObject,
choosenSubObjects = listSubObject
};
return View(objVM);
}
My View
#model Project.Models.ViewModels.ObjectViewModel
... more code
<form asp-action="Create">
<div class="row">
<div class="col-sm-6 ctnFullHeight">
<div class="shadowBoxForm formCreateLeft position-absolute col-sm-11 ctnFullHeight">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<input asp-for="name " class="form-control" />
<span asp-validation-for="name " class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="IsCameraPermited" class="control-label"></label>
<input asp-for="IsCameraPermited" type="checkbox" />
</div>
<div class="form-group float-right position-relative">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
<div class="col-sm-6">
<div class="shadowBoxForm formCreateLeft position-absolute col-sm-11 ">
#foreach (var item in listSub)
{
<div class="txt">
#item
</div>
}
</div>
</div>
</div>
</form>
Thanks in advance.
how should I return the ViewModel 'ObjectViewModel' to the controller with all its values
To achieve above requirement, you can refer to the following code snippet.
#model ObjectViewModel
#{
ViewData["Title"] = "Create";
var choosenSubObjects = Model.choosenSubObjects;
}
<form method="post">
<div class="row">
<div class="col-sm-6 ctnFullHeight">
<div class="shadowBoxForm formCreateLeft position-absolute col-sm-11 ctnFullHeight">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<input asp-for="name " class="form-control" />
<span asp-validation-for="name " class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="IsCameraPermited" class="control-label"></label>
<input asp-for="IsCameraPermited" type="checkbox" />
</div>
<div class="form-group float-right position-relative">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
<div class="col-sm-6">
<div class="shadowBoxForm formCreateLeft position-absolute col-sm-11 ">
#for (var i = 0; i < Model.choosenSubObjects.Count; i++)
{
<div class="txt">
<div class="form-group">
<label asp-for="#choosenSubObjects[i].IdObject" class="control-label"></label>
<input asp-for="#choosenSubObjects[i].IdObject" type="text" />
</div>
<div class="form-group">
<label asp-for="#choosenSubObjects[i].Name" class="control-label"></label>
<input asp-for="#choosenSubObjects[i].Name" type="text" />
</div>
<div class="form-group">
<label asp-for="#choosenSubObjects[i].Config" class="control-label"></label>
<input asp-for="#choosenSubObjects[i].Config" type="text" />
</div>
</div>
}
</div>
</div>
</div>
</form>
Controller Actions
[HttpGet]
public IActionResult Create(int id)
{
//code logic here
//...
return View(objVM);
}
[HttpPost]
public IActionResult Create(ObjectViewModel objectViewModel)
{
//code logic here
//...
Test Result
I have a bool value that I'm using to distinguish between the first item in a series of other items being saved to a link table in my DB. The constructor for the ViewModel sets this to true by default. When my ViewModel is posted to the controller my controller action changes this value to false and passes the edited ViewModel back to the View where this value is saved in a hidden field.
The issue I have is that after the value has been changed, my View is still displaying this value as true. Does anyone have any idea where I'm going wrong?
I also have an issue where I reset the values back to default but these are being retained when the view is reloaded after the post action in executed.
ViewModel
public class NewScriptViewModel
{
public Patient Patient { get; set; }
public int PatientId { get; set; }
public int PrescriberId { get; set; }
public int DrugId { get; set; }
public int Qty { get; set; }
public string Directions { get; set; }
public bool FirstItem { get; set; }
public bool NextItem { get; set; }
public int ScriptId { get; set; }
public NewScriptViewModel()
{
FirstItem = true;
NextItem = false;
}
}
View
#model DispensingApp.Models.ViewModels.NewScriptViewModel
#{
ViewData["Title"] = "New Script";
}
<h1>#Model.Patient.FullName</h1>
<h3>HCN : #Model.Patient.HCN</h3>
<hr />
<div class="row">
<br />
<div class="col-12" onload="newScriptItemForm.reset()">
<form id="newScriptItemForm" asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input asp-for="ScriptId" type="hidden" value="#ViewData["ScriptId"]" />
<input asp-for="DrugId" type="hidden" />
<table id="drugSelectionTable" class="table table-hover">
<thead>
<tr class="table-secondary">
<th></th>
<th>Name</th>
<th>Pack Size</th>
<th>Generic Ingredients</th>
<th>Stock</th>
</tr>
</thead>
</table>
<div class="form-group">
<div><input asp-for="PatientId" type="hidden" /></div>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Patient.Prescriber.FullName" class="control-label"></label>
</div>
<div class="col-4">
#if (Model.FirstItem)
{
<select asp-for="PrescriberId" class="form-control" asp-items="ViewBag.PrescriberId"></select>
}
else
{
<input asp-for="PrescriberId" type="hidden" />
<input type="text" placeholder="#Model.PrescriberId" class="disabled" />
}
</div>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Qty" class="control-label"></label>
</div>
<div class="col-4">
<input asp-for="Qty" class="form-control" />
</div>
<span asp-validation-for="Qty" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Directions" class="control-label"></label>
</div>
<div class="col-4">
<textarea asp-for="Directions" rows="3" class="form-control"></textarea>
</div>
<span asp-validation-for="Directions" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<input asp-for="FirstItem" type="hidden" />
<input id="nextItem" asp-for="NextItem" type="hidden" />
<button id="nextItemBtn" #*type="submit" value="Next Item"*# class="btn btn-primary form-control">Next Item</button>
</div>
<div class="col-2">
<button asp-action="NewScript" class="btn btn-success form-control">Next Script</button>
</div>
<div class="col-2">
<a asp-controller="Patients" asp-action="Details" asp-route-id="#Model.PatientId" class="btn btn-danger form-control">Cancel</a>
</div>
</div>
</form>
</div>
</div>
Controller Post
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(NewScriptViewModel viewModel,
[Bind("PatientId, PrescriberId")] Script script,
[Bind("DrugId, Qty, Directions")] ScriptDrug scriptDrug)
{
if (ModelState.IsValid)
{
//if first item of script -- create script entry
if (viewModel.FirstItem)
{
_context.Script.Add(script);
await _context.SaveChangesAsync();
viewModel.ScriptId = script.Id;
viewModel.FirstItem = false;
}
scriptDrug.ScriptId = (int)viewModel.ScriptId;
var drug = _context.Drug.Find(scriptDrug.DrugId);
drug.StockQty -= scriptDrug.Qty;
_context.ScriptDrug.Add(scriptDrug);
await _context.SaveChangesAsync();
return await Create(script.PatientId, viewModel);
}
viewModel.NextItem = false;
return await Create(script.PatientId, viewModel);
}
Controller Get
public async Task<IActionResult> Create(int id, NewScriptViewModel viewModel)
{
var patient = await _context.Patient.FindAsync(id);
var vm = new NewScriptViewModel();
//if not first item, reset view model but retain script id
if (!viewModel.FirstItem)
{
vm = viewModel;
}
vm.Patient = patient;
vm.PatientId = patient.Id;
return View(vm);
}
The HTML that is rendered to the browser after all of this looks like:
<div class="col-2">
<input type="hidden" data-val="true" data-val-required="The FirstItem field is required." id="FirstItem" name="FirstItem" value="True">
<input id="nextItem" type="hidden" data-val="true" data-val-required="The NextItem field is required." name="NextItem" value="True">
<button id="nextItemBtn" class="btn btn-primary form-control">Next Item</button>
</div>