Data not populating in form upon clicking edit - asp.net-mvc

I am working on this ASP.NET MVC project where I am performing simple CRUD operations. On clicking Edit button, I want to get the data from the database and populate it in the Create View (same view with the help of which I entered the data).
The issue that I have is that, though I am able to enter the data into the database using the Create.cshtml view, I am not able to populate the data back into the fields to the same View upon clicking Edit. On checking, I see that I am able to get the data from the database from the Controller and I am sending it to the View - Create. But, the fields are not getting populated in the View.
Where am I going wrong?
View - Create.cshtml
<form method="post" action="/Books/Create" id="formBooks">
<div class="form-group">
<div class="form-row">
<div class="form-group col-md-6">
<div>
<label asp-for="Title" class="label">Title</label>
<input asp-for="Title" class="form-control" id="title" name="title" required />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div>
<label asp-for="Author" class="label">Author</label>
<input asp-for="Author" class="form-control" id="author" name="author" required />
<span asp-validation-for="Author" class="text-danger"></span>
</div>
...
</div>
<div class="form-group col-md-6">
<button type="submit" value="Save" class="btn bgm-orange waves-effect mybtn">SAVE</button>
</div>
</div>
</div>
</form>
Controller - BooksController.cs
public ActionResult Create(int? Id)
{
if(Id == null)
{
return View();
}
else
{
var bookData = _context.Books
.Where(b => b.ID == Id)
.FirstOrDefault();
return View(bookData);
}
}

public ActionResult Create(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Books books= db.Books.Find(id);
if (books== null)
{
return HttpNotFound();
}
return View(books);
}
//Try this i hope this will work

The name attribute plays a vital role in binding the data to the <input></input> field. Also, value attribute gets the value to display in the Edit view.
<input asp-for="Title" class="form-control" id="title" name="title" placeholder="Enter title..." value="#(Model != null ? Model.Title : "")" required />

Related

ASP.NET MVC Show message before redirects if success

Here's my web api on account controller using identity that can change the password wit validation using data annotations
[HttpGet]
[AllowAnonymous]
public IActionResult ChangePassword(string email, string returnUrl)
{
return email == null || returnUrl == null ? View("Error") : View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ChangePassword(ChangePasswordViewModel model)
{
if (model == null)
{
return BadRequest();
}
if (ModelState.IsValid)
{
var result = await _changePasswordCommand.ChangePassword(model);
if (result.Succeeded)
{
ViewBag.IsSuccess = true;
ModelState.Clear();
return Redirect(model.returnUrl);
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
return View(model) ;
}
then in my div razor views
<form class="change-password-form" asp-controller="Account" asp-action="ChangePassword" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input id="email-hidden" asp-for="Email" type="hidden" />
<input id="return-url" asp-for="ReturnUrl" type="hidden" />
<div class="form-group change-password">
#if (ViewBag.IsSuccess == true)
{
<div class="alert alert-success alert-dismissible fade show text-center">Successfully Changed Password!</div>
}
<label asp-for="CurrentPassword" class="control-label"></label>
<input class="form-control" type="password" asp-for="CurrentPassword">
<span asp-validation-for="CurrentPassword" class="text-danger"></span>
</div>
<div class="form-group change-password">
<label asp-for="NewPassword" class="control-label">New password</label>
<input id="password" class="form-control" type="password" name="newPassword" asp-for="NewPassword" onkeyup="isGood(this.value)">
<span asp-validation-for="NewPassword" class="text-danger"></span>
</div>
<div class="form-group change-password">
<label asp-for="ConfirmNewPassword" class="control-label"></label>
<input asp-for="ConfirmNewPassword" class="form-control" type="password" />
<span asp-validation-for="ConfirmNewPassword" class="text-danger"></span>
</div>
<div class="change-password-footer">
<button id="btn-cancel" type="button" class="btn btn-primary cancel">
CANCEL
</button>
<button id="btn-save" type="submit" class="btn btn-secondary save" disabled>
SAVE
</button>
</div>
</form>
I want to be able to show the successfully changed password message before it redirects problem is it always redirect to account/changepassword after submit
You can write if condition outside the form tag, like this
#if (ViewBag.IsSuccess == true)
{
<div class="alert alert-success alert-dismissible fade show text-center">Successfully
Changed Password!
</div>
}
<form class="change-password-form" asp-controller="Account" asp-action="ChangePassword" method="post">
#*your code*#
</form>
Or remove method="post" then try
look at this place in your account controller.
...
if (result.Succeeded)
{
ViewBag.IsSuccess = true;
ModelState.Clear();
return Redirect(model.returnUrl);
}
...
Instead of the re-direct, use "return View(model);". then you can redirect the page ajax, (testing if the ViewBag.IsSuccess == true and model.returnUrl != null) you in the account controller, you will instead have.
...
if (result.Succeeded)
{
ViewBag.IsSuccess = true;
ModelState.Clear();
//return Redirect(model.returnUrl);
return View(model);
}
...
With this, the success alert would show. Then have a javascript method onload, test if success is true and the the return is not null. something like this (in the view)
...
#{
bool isSuccess = ViewBag.IsSuccess;
string rUrl = model.returnUrl;
}
...
<script>
function redirect(isSuccess, returnUrl)
{
//use ajax to redirect;
}
redirect(#isSuccess, #rUrl);
</script>

Edit action in controller not updating

When I edit an item and return to the index view the item doesn't show what I updated it to.
I think I know what the problem is but not sure how to fix it. In my service class I have a CreateEditItem method and when I step thru the code it hits the if condition <=0. So it acts like there is an id of 0 when I click the submit button to submit my update. I'm not sure what to do to fix this. Do I need to have a separate method for Edit? And if so what should that look like?
public bool CreateEditItem(Item item)
{
if (item.ItemId <= 0)
{
var maxId = _mockList.Max(p => p.ItemId);
item.ItemId = maxId + 1;
_mockList.Add(item);
return true;
}
var itemToEdit = _mockList.FirstOrDefault(p => p.ItemId ==
item.ItemId);
itemToEdit = item;
return true;
}
Action in Controller
[HttpPost]
public IActionResult EditItem(Item itemToEdit)
{
_itemService.CreateEditItem(itemToEdit);
return RedirectToAction(nameof(Index), new { id =
itemToEdit.ItemId });
}
View:
<div class="row">
<form asp-action="EditItem">
<div asp-validation-summary="ModelOnly" class="text-
danger"></div>
<div class="container form-group">
<div class="row">
<div class="col-md-2">As Of : <label
for="AsOf" /></div>
<div class="col-md-4"><input id="AsOf"
value="#Model.ItemToEdit.AsOf" name="AsOf" type="date" /></div>
</div>
<br />
<div class="row">
<div class="col-md-2">Title Summary : <label
for="TitleSummary" /></div>
<div class="col-md-2"><input id="TitleSummary"
value="#Model.ItemToEdit.Title" name="Title" type="text" /></div>
</div>
<br />
<br />
<div class="row">
<div class="col-md-2"><input type="submit"
value="Submit" class="btn btn-primary" /></div>
</div>
</div>
</form>
</div>
I expect when I click the submit button to submit my update it will show the updated Title and/or AsOf date.
change your method from HTTPut to HttpPost
it will work.

MVC foreach set item.ID to model.ID

I have a form that shows all the available hotel rooms, each room has a button that does a HttpPost if clicked, I have made a property in the BookingViewModel called 'RoomID'. I would like to assign the item.RoomID to Model.RoomID so I can use it in my controller to get the id from the selected room but i'm not sure how to achieve this.
ChooseRoom View
#foreach (var item in Model.AvailableRooms)
{
<li class="room-item clearfix">
<h5>#item.Name</h5>
<div class="room-list-left">
<img src="#item.Image" alt="" />
</div>
<div class="room-list-right">
<div class="room-meta">
<ul>
<li><span>Occupancy:</span> #item.Adults Adults #item.Childs Children</li>
#if (item.SmokingRoom)
{
<li><span>Smoking Allowed:</span> Yes</li>
}
else
{
<li><span>Smoking Allowed:</span> No</li>
}
</ul>
</div>
<div class="room-price">
<p class="price">From: <span>$#item.Price</span> / Night</p>
</div>
<div class="clearboth"></div>
#using (Html.BeginForm("chooseroom", "booking", FormMethod.Post))
{
<input class="button2" type="submit" value="Select Room" />
}
BookingController
[HttpPost]
public ActionResult ChooseRoom(BookingViewModel vm)
{
BookingViewModel bookingObj = GetBooking();
bookingObj.SelectedRoom = Repository.GetRoomByID(vm.RoomID);
return View("reservation", bookingObj);
}
Thank you for your time!
update your begin form as below
#using (Html.BeginForm("chooseroom", "booking", FormMethod.Post))
{
<input type="hidden" name="RoomId" value="#item.RoomID" />
<input class="button2" type="submit" value="Select Room" />
}
Just need to provide input tags having the same name as your ViewModel property.
You could add inputs in foreach loop , it should be inside form. Something like this <input name="Model.AvailableRooms[index].RoomID" value="Id Here"/>
Or if you want to select one Room you should use ajax and post id.
If I'm not wrong you form is in loop,so you could add hidden input with id
#Html.HiddenFor(c => c.AvailableRooms[index].RoomID)

MVC Razor, How to keep Model object between Actions

I'm trying to display a product stock list.
I would like to let the user an option to edit the quantity's and the ability to remove a product from this list. the problem is, the Model object disappear after the submit action. i would like to preserve it, in order to update the stock in DB later on.
Controllers:
public ActionResult EditProducts()
{
//! Pulling DATA from db using DbContext
ProductDAL proDAL = new ProductDAL();
List<Products> pl = proDAL.Products.ToList<Products>();
ProductModel productModel = new ProductModel();
productModel.oneProduct = new Products();
productModel.ProductsCollection = new List<Products>();
productModel.ProductsCollection = pl;
TempData["pM"] = productModel;
return View("EditProducts", TempData["pM"]);
}
public ActionResult SubmitProductsValues(ProductModel productModel)
{
//! Some farther work to do...
return View("EditProducts", TempData["pM"]);
}
My View:
#using (Html.BeginForm("SubmitProductsValues", "Admin", FormMethod.Post))
{
<div class="col-xs-12 hclearfix edit">
<div class="col-xs-2 eRow et"><b>Product SKU</b></div>
<div class="col-xs-2 eRow et"><b>Product Name</b></div>
<div class="col-xs-2 eRow et"><b>Product Price</b></div>
<div class="col-xs-2 eRow et"><b>Product Quantity</b></div>
<div class="col-xs-2 eRow et"><b>Product Picture</b></div>
<div class="col-xs-1 eRow et"><b>pId</b></div>
<div class="col-xs-1 eRow et"><b>Remove?</b></div>
#{ int i = 0; }
#foreach (Products obj in Model.ProductsCollection)
{
<div class="col-xs-2 eRow">#Html.Raw(obj.SKU)</div>
<div class="col-xs-2 eRow">#Html.Raw(obj.Name)</div>
<div class="col-xs-2 eRow">#Html.Raw(obj.Price)</div>
<div class="col-xs-2 eRow">#Html.EditorFor(m=>m.ProductsCollection[i].Quantity)</div>
<div class="col-xs-2 eRow">#Html.Raw(obj.PicURL)</div>
<div class="col-xs-1 eRow">#Html.Raw(obj.Id)</div>
<div class="col-xs-1 eRow">#Html.CheckBox("remove")</div>
i++;
}
<div class="col-xs-12 eRow">
<p class="left">
<input type="submit" id="btnSubmit" value="Save Changes" />
</p>
<p class="alert-danger right">
#Html.ValidationSummary()
</p>
</div>
</div>
BTW, only this raw: #Html.EditorFor keeps the values of the returned data.
but i would like to avoid using #Html.EditorFor for the other fields, while
keeping those fields data.
Thank you so much for your help (:
You are getting null because the other field values are not in the form fields. Model binding will map the data from your form fields ( with names matching to your view model property name). Currently you are displaying Name, Price etc in just a div, not an input field.
But since you do not want to update any other fields, you should not worry about getting other field value as null. What you need is the unique Id of your record and the Quantity field value which has the updated value from form.
Als you do not need TempData. You can pass your model to the View method.
public ActionResult EditProducts()
{
var proDAL = new ProductDAL();
List<Products> pl = proDAL.Products.ToList<Products>();
ProductModel productModel = new ProductModel();
productModel.ProductsCollection = new List<Products>();
productModel.ProductsCollection = pl;
return View("EditProducts",productModel);
}
And in your view, you need to create input fields with names which matches the property name so that model binding will work when you post the form.
#model ProductModel
#using (Html.BeginForm("SubmitProductsValues", "Admin", FormMethod.Post))
{
<h2>Items</h2>
int i = 0;
foreach(var p in Model.Products)
{
<div>#p.Name</div>
<input type="hidden" name="ProductsCollection[#i].Id" value="#p.Id" />
<input type="text" name="ProductsCollection[#i].Quantity" value="#p.Quantity" />
}
<input type="submit" value="Update" />
}
Now in your HttpPost, you will have the ProductsCollection available withe updated data from the form user submitted.
[HttpPost]
public ActionResult SubmitProductsValues(ProductModel model)
{
// loop through model.ProductsCollection
foreach(var p in Model.ProductsCollection)
{
var q=p.Quantity;
var id=q.Id;
// to do : update quantity of the record for the value in Id variable.
}
// to do : Save and redirect
}
<input type="hidden" name="ProductsCollection[#i].SKU" value="#p.SKU" />
<input type="hidden" name="ProductsCollection[#i].Name" value="#p.Name" />
<input type="hidden" name="ProductsCollection[#i].Price" value="#p.Price" />
<input type="hidden" name="ProductsCollection[#i].PicURL" value="#p.PicURL" />
<input type="hidden" name="ProductsCollection[#i].Id" value="#p.Id" />
Thanks to #Shyju (:

Posting Textarea to Controller (currently null is being passed) - MVC

I'm creating a website where the user will fill in a textarea (in response to a question) and then press next. When they press next, the textarea will be submitted to the controller and the next question will be retrieved (I'll also store the answer in a cookie). Unfortunately, when I run the code in debug I've realized that the textarea is not being submitted b/c the parameter is null. I've tried to figure it out and I've looked around and I seem to be doing it properly. Hopefully it's an easy fix. Thanks so much for your time!
Controller:
// POST: /Question/1
[HttpPost]
public ActionResult q(string textAnswer) {
if (textAnswer != null)
ViewBag.current++;
Question q = db.Questions.Find(ViewBag.current);
if (q == null) {
return RedirectToAction("submit");
}
return View(q);
}
View:
<form class="form-horizontal" id="myForm" method="post" enctype="text/plain" name="input">
<p>
<h3>Question <span id="integer">#ViewBag.current</span></h3>
#Html.DisplayFor(model => model.Ques)
</p>
<div class="control-group">
<label class="control-label">Answer</label>
<div class="controls">
<textarea rows="20" style="width:600px" id="textAnswer"></textarea>
</div>
</div>
<div class="control-group">
<div class="controls" >
<button onclick="history.back()" type="button" class="btn">Back</button>
<input type="submit" class="btn" value="Next" />
</div>
</div>
</form>
Your textarea needs a name in order to be posted.
<textarea rows="20" style="width:600px" id="textAnswer" name="textAnswer"></textarea>
Also remove the enctype attribute from your form.
Text areas don't post strings, they post string arrays.
Your controller should have this signature:
public ActionResult q(string[] textAnswer)

Resources