When the button is pressed it states that the model is invalid as fields are empty.
when looking at the model all fields are empty or null. anyone know how to solve this issue, thanks
Home Controller
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> createOrderLine(Product models)
{
if (ModelState.IsValid)
{
db.OrderLines.Add(new OrderLine
{
productId = models.productId,
productColour = models.productColour,
productDescription = models.productDescription,
productName = models.productName,
productPrice = models.productPrice,
productStock = models.productStock,
//QuantityOrdered = quantityOrdered
});
db.SaveChanges();
return RedirectToAction("Index", "OrderLines");
}
else return RedirectToAction("Index", "Home");
}
Home Index - Displays the product information to the screen
#foreach (var product in Model)
{
using (Html.BeginForm("createOrderLine", "Home", FormMethod.Post, new {
#class = "form-horizontal", role = "form" }))
{
<div class="row">
<div class="blog col-md-6">
<div>
<h1>Product Name</h1>
<h2>#product.productName</h2>
<div>
<h3>Product Description</h3>
<h6><i>#product.productDescription</i></h6>
<br />
<h3>Product Price</h3>
<td>#product.productPrice </td>
<br />
<h1>Product colour</h1>
<td>#product.productColour</td>
<div></div>
<br />
<br />
#Html.AntiForgeryToken()
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-buy" value="Add to cart" onclick="btnbuy_Click" />
</div>
</div>
</div>
</div>
<br />
</div>
</div>
}
}
the problem is that none of your field are linked to the model they only display it so to fix this
you can simply add a hiddenfor field that links the product id in your page like so for each of your product :
#Html.HiddenFor(product.Id)
then fill the rest of the informations you need with the id that is gonna be passed to your controller as a parameter
exemple :
public ActionResult createorderline(Product ProductToAdd)
{
// add your product or do your treatment
}
I do not quite understand what are you trying to do, but Louis is right. If you are trying to pass values back, you have to #Html.EditorFor() or some other ways to pass back information to the server.
You could also use #Html.HiddenFor(product.Id) then inside your Actionmethod call the database to get the rest of the info regarding your product or you could use JQuery as well.
In this case I would only use the #Html.HiddenFor(product.Id) and have a static helper method that will map your orderline class from the DB.
public static Product GetProductById(int productId){
return db.Products.FirstOrDefault(x => x.Id == productId);
}
But again you could just add the FirstOrDefault() line inside your controller as you not mapping from a ViewModel to a business Model.
Related
I'm currently trying to find out what´s the MVC-way to solve the following problem:
I have a table (index view) based on a model and my first row has a button to change one cell of this row. When the button is pressed a popup is shown (via Ajax.ActionLink), which asks for an additional comment. The popup view is realised with a Partial View and a Html.BeginForm. After adding a comment and clicking the submit button the updated index view is shown.
At the moment I calculate the id of the first-row item before the updated index view is shown, because I don't know how to pass this id via the Ajax.ActionLink at first and the Html.BeginForm afterwards.
The whole process looks like this:
Ajax.ActionLink in Index View:
#Ajax.ActionLink("Update", "Update", null,
new AjaxOptions { HttpMethod = "GET", UpdateTargetId = "result", InsertionMode = InsertionMode.Replace, OnSuccess = "openPopup()" },
new { #class = "btn btn-info"})
Update Partial View:
#using (Html.BeginForm("Index"))
{
<div class="form-group">
<h4>Title</h4>
<p>Comment here:</p>
<textarea type="text" class="form-control" name="comment" id="comment" required></textarea>
</div>
<input type="submit" value="Update" class="btn btn-info" />
}
ActionResults in Controller
[HttpGet]
public PartialViewResult Update()
{
return PartialView();
}
[HttpPost]
public async Task<ActionResult> Index(string comment)
{
//Here I calculate the ID, which represents the first row
//I would like to have this ID as a paramter, additional to comment
int maxID = dbContext.db.Max(m => m.pmc_id);
db x= dbContext.db.Where(m => m.pmc_id == maxID).FirstOrDefault();
//...Update database etc.
return RedirectToAction("Index");
}
Any help is appreciated!
first pass the Id to view with for example viewbag or some view model in here I chose ViewBag
[HttpPost]
public async Task<ActionResult> Index(string comment)
{
//Here I calculate the ID, which represents the first row
//I would like to have this ID as a paramter, additional to comment
int maxID = dbContext.db.Max(m => m.pmc_id);
db x= dbContext.db.Where(m => m.pmc_id == maxID).FirstOrDefault();
//...Update database etc.
ViewBag.CurrentId = calculatedId;//saved Id to pass to View
return RedirectToAction("Index");
}
lets add into the view the Id
#using (Html.BeginForm("Index"))
{
<input type="hidden" value="#ViewBag.CurrentId" name="Id"/>
<div class="form-group">
<h4>Title</h4>
<p>Comment here:</p>
<textarea type="text" class="form-control" name="comment" id="comment" required></textarea>
</div>
<input type="submit" value="Update" class="btn btn-info" />
}
now lets get the Id parameter with mvc parser
[HttpGet]
public PartialViewResult Update(int Id)//here is your id
{
return PartialView();
}
I apologize if the heading is not very clear.
So, what I want to do is following.
I have a model class called "Class" that contains a list of "Students". I have a view that shows a checklist of Students. From that checklist I want to pass the selected students back to controller, where I will update the Database and my class will have new students and the added students will have a new class.
Here is what I have done so far but now I am stuck. Thanks in advance.
These are my controller actions
[HttpGet]
public ActionResult AddStudents(int? id)
{
List<Student> students = (from std in db.Students
where std.St_cl_fk_id == null select std).ToList();
//ViewBag.students = students;
return View("Add_Students",students);
}
[HttpPost, ActionName("AddStudents")]
public ActionResult AddStudentsPost(int? id,List<Student> students)
{
if(ModelState.IsValid)
{
var temp = id;
Class #class = db.Classes.Find(id);
foreach (var item in students)
{
if (Request.Form[item.St_id.ToString()] != null)
{
#class.Students.Add(item);
}
}
db.Entry(#class).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index", "Classes");
}
return View("Add_Student");
}
Here is my view
#model IEnumerable<GMASchoolProject.Models.Student>
#{
ViewBag.Title = "Add_Students";
}
<h4>Student List</h4>
#using (Html.BeginForm())
{
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<div class="panel panel-default">
<div class="panel-heading">
Check Students
</div>
<div class="form-group">
<div class="col-md-10">
<table>
#foreach (var std in Model)
{
<tr>
<td><input type="checkbox" name="#std.St_id" value="#std.IsSelected" /></td>
<td>#Html.Label((string)std.St_name)</td>
</tr>
}
</table>
</div>
</div>
<div class="form-group" style="margin:15px,0,15px,0;">
<div class="col-md-offset-5 col-md-2">
<input type="submit" value="Add Students" class="btn btn-primary" />
</div>
</div>
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index", null, new { #class = "btn btn-danger" })
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Please let me know if there is anything else that I am doing wrong, I am a newbie in this area. THanks
First, instead of binding the view to a list of students, bind the model to your Class object that has a list of students in it. That way, when you submit (post), you are sending the whole Model object into the Controller.
Change your AddStudentsPost method to take in Class object and do your logic there.
Finally, change the name of the "Class" object to something else, such as, "Course". Class should be reserved for actual classes so not to cause confusion.
You aren't far off, so keep going
This question already has answers here:
Send post data from html FORM with Javascript?
(5 answers)
Closed 4 years ago.
I am posting a selected value from Dropdown List. but after getting my value page goes refresh. How to post data without page refresh to controller?
Here is view:
<div class="container">
<div class="row">
#foreach (var item in Model)
{
using (Html.BeginForm("AddToCart", "Test", new { id = item.ProductId }, FormMethod.Post))
{
<div class="col-md-3 col-sm-4 col-xs-6">
<img id="ImageClick" onclick="location.href='#Url.Action("ViewProductOnClick", "Home", new { id = item.ProductId })'"
src="#Url.Content("~/Content/" + item.ImageURL)" height="200" width="200" alt="#item.ProductName" />
<div class="productDetails">
<div class="productName">
<h5 id="ProductName" class="bold name">Name: #item.ProductName</h5>
</div>
<div class="productPrice bold" id="ProductPrice">
Rs. <span class="unit"> #item.Price</span>
</div>
<div class="productCart">
<div class="col-lg-6 col-md-12 col-sm-12 col-xs-12 no-padding">
<input type="submit" class="btn btn-success" id="btnSubmit" value="Add to Cart" />
</div>
</div>
</div>
</div>
}
}
</div>
</div>
Here is my controller:
[HttpPost]
public ActionResult AddToCart(int id, FormCollection collection)
{
MyDBContext myDBContext = new MyDBContext();
if (ModelState.IsValid)
{
var cartFill = myDBContext.Products.Find(id);
int quantity = Convert.ToInt16(collection["Weight"]);
AddToCart addToCart = new AddToCart(cartFill, quantity);
if (Session["cart"] == null)
{
List<AddToCart> list = new List<AddToCart>();
list.Add(addToCart);
Session["cart"] = list;
}
else
{
List<AddToCart> list = (List<AddToCart>)Session["cart"];
list.Add(addToCart);
Session["cart"] = list;
}
}
return RedirectToAction("ViewCart", "Home");
}
You can do it like this;
1) You have to create partial view for your action (Action is you want to post)
2) Add Reference of jquery.unobtrusive-ajax.
Using NuGet package manager, you can install library and reference into the project.
here is the package link https://www.nuget.org/packages/Microsoft.jQuery.Unobtrusive.Ajax/
3)To work Ajax.BeginForm functionality properly don't forget to add the reference into page
After you do these, you can post data to controller without Page refresh in ASP.NET MVC using Ajax.BeginForm.
For detailed explanation you can read this link:
post-data-without-whole-postback
You should use a partial view if you want to update only portions of the page instead of refreshing it.
Here is a useful link to start with: http://www.tutorialsteacher.com/mvc/partial-view-in-asp.net-mvc.
I have a page which displays fields from 2 different models. To ensure this works I am using Tuple<> to display them both and have tested to ensure data shows which it does. The issue I had was when I submitted the form to update the database, nothing was passed and the record was wiped clean. Please advise me on how to proceed. I have shortened fields shown to make the post shorter.
View
#model Tuple<CommunityParkletDashboard.Models.COMMUNITY_PARKLET_APPLICATION, CommunityParkletDashboard.ViewModels.CPDashboardModel>
<input type="button" value="Back" onclick="location.href='#Url.Action("CPDashboard", "CPDashboard")'" />
#using (Html.BeginForm("EditCP", "CPDashboard", FormMethod.Post))
{
<p>
Reference Number:
#Html.DisplayFor(i => i.Item1.REF_NUMBER)
</p>
<p>
Name:
#Html.DisplayFor(i => i.Item1.NAME)
</p>
<p>
Notes:
#Html.TextAreaFor(i => i.Item1.NOTES)
</p>
foreach (var item in Model.Item2.lParkletApplicationDtos)
{
<p>
Title:
#Html.DisplayFor(i => item.ParkletTitle)
</p>
<br />
<input type="submit" value="Save" />
}
}
Controller
[HttpPost]
public ActionResult EditCP(COMMUNITY_PARKLET_APPLICATION cpa, int id)
{
_context.UpdateParkletApplication(cpa, id);
return RedirectToAction("CPDashboard");
}
UpdateParkletApplication() is just a method which runs some SQL script to update the data using the model and ID so associate the record with, all this was working fine before I introduced second model. Thanks in advance.
Because you create one form and use foreach form item2 it pass all item in item2.
You can use foreach and inside of it use begin form .
foreach (var item in Model.Item2.lParkletApplicationDtos)
{
#using (Html.BeginForm("EditCP", "CPDashboard", FormMethod.Post))
{
<p>
Reference Number:
#Html.DisplayFor(i => i.Item1.REF_NUMBER)
</p>
<p>
Name:
#Html.DisplayFor(i => i.Item1.NAME)
</p>
<p>
Notes:
#Html.TextAreaFor(i => i.Item1.NOTES)
</p>
<p>
Title:
#Html.DisplayFor(i => item.ParkletTitle)
</p>
<br />
<input type="submit" value="Save" />
}
}
Does it pass id ???
#Html.DisplayFor(i => item.ParkletTitle)
As your view contains model as
#model MyCustomModel
Following method should like this and then access cpa.Item1 just you did in view.
[HttpPost]
public ActionResult EditCP(MyCustomModel cpa, int id)
{
_context.UpdateParkletApplication(cpa, id);
return RedirectToAction("CPDashboard");
}
Your Model Class
public class MyCustomModel
{
public CommunityParkletDashboard.Models.COMMUNITY_PARKLET_APPLICATION Item1 {get;set;}
public CommunityParkletDashboard.ViewModels.CPDashboardModel Item2 {get;set;}
}
Ultimately you have to think like how is model constructed. Even if in View you keep Tuple then you can use above answer.
I work on one of my first ASP MVC-programs at the moment.
The program should show me a list of product, and with a link beneath the name of the product it should be possible to edit the product. No problem so far.
#model MVC3Demo.Product
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm("Save", "Product"))
{
<div>
<input type="hidden" id="ID" name="ID" value="#Model.ID" />
ProduktID #Model.ID
</div>
<div>
Produktname <input id="Name" name="Name" type="text" value=#Model.Name />
</div>
<div>
Preis <input id="Price" name="Price" type="text" value=#Model.Price />
</div>
<div>
<input type="submit" value="Speichern"/>
</div>
}
Now I have written a Save action method that should update my data:
public ActionResult Save(Product p)
{
ProductRepository rep = new ProductRepository();
rep.Update(p);
return RedirectToAction("List");
}
The "List"-View is where I can see all products with the edit-link.
The problem is, that if I press the save-button, it redirects me to the old list, not to the updated one. I debugged my project and I´m sure that the update-method works correct and updates the product.
My List action is:
#model IEnumerable<MVC3Demo.Product>
#{
ViewBag.Title = "List";
}
<h2>List</h2>
<ul>
#foreach (MVC3Demo.Product p in Model)
{
<li>#p.Name #Html.ActionLink("bearbeiten", "Edit", "Product", p, null)</li> //new{ ID = p.id}
}
</ul>
Because you asked, here is the List Action:
public ActionResult List()
{
ProductRepository rep = new ProductRepository();
return View(rep.GetAll());
}
So where could be my mistake?
It looks like you're calling the update, but you're not actually submitting the transaction itself, does your repository have a SubmitChanges, AcceptChanges or Commit or something similar? As with DataTables, your changes won't actually take effect (save to the database) until you call AcceptChanges.
Try include an HttpPost attribute at Save controller method.
[HttpPost]
public ActionResult Save(Product p)
{
ProductRepository rep = new ProductRepository();
rep.Update(p);
return RedirectToAction("List");
}