MVC4 pass model values from view (for-each) to controller - asp.net-mvc-4

Hello dear i am trying to pass my model values from view to controller. when i am trying to do that i receive only null value in controller my view is given below
I also have used #html.hadden but still received only null value in contoller after button click. please someone help me and tell me the solution of this problem.
My VIEW IS THIS WHERE I AM TRYING TO PASS VALUE TO CONTOLLER:
#model IEnumerable<onlinebookstore.entityframwork.book>
#using (Html.BeginForm("AddToCart", "ShopingCart", FormMethod.Post))
{
foreach (var item in Model)
{
<img src="#Url.Content(item.book_img)" alt="Image" width="170px"; height="230px" />
<br />
#Html.DisplayFor(modelItem => item.book_name)
<br />
<label>Author:</label>
#Html.DisplayFor(modelItem => item.author)
<br />
<label>Pk.</label>#Html.DisplayFor(modelItem => item.price, new { id = "price" })&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp
#Html.ActionLink("For Detail..", "Detail", "Book", new { id = item.inventory_id }, null)
<br />
<input type="submit" class="btnreg" id="btnaddcart" value="Add to Basket"/>
<br />
}
}
My Controller where i am trying to receive values from view and here i received only null values
[HttpPost]
public ActionResult AddToCart(book model)
{
var cartitem =
db.shoping_cart_item
.FirstOrDefault(u => u.inventory_id == model.inventory_id);
if (cartitem == null && Session["userid"] != null)
{
cartitem = new shoping_cart_item();
cartitem.inventory_id = model.inventory_id;
cartitem.price = Convert.ToDecimal(model.price.ToString());
db.shoping_cart_item.Add(cartitem);
}
return View();
}
My Model (BOOK)
public string inventory_id { get; set; }
public string book_name { get; set; }
public string author { get; set; }
public string book_type { get; set; }
public Nullable<int> no_book { get; set; }
public Nullable<decimal> price { get; set; }
public string book_img { get; set; }
public string book_description { get; set; }
Please help me how we will pass model value using for-each loop in view to Controller

You have no inputs for your form. You aren't submitting anything. Try #Html.TexboxFor() or some other helper.

So what will be the remedy of this problem where i can display my all values in view and on button click all the values of model will be pass on to controller.
I think you are doing it wrong.
Your view is looping through the list of onlinebookstore.entityframwork.book to display the details AND one button for EACH of them inside one big form. When you submit that, all inputs that can be submitted will be posted (a collection of books at best). But on your controller, you are just receiving one instance of onlinebookstore.entityframwork.book
You might want to rethink your view by creating the loop first then inside it, have the #using (Html.BeginForm("AddToCart", "ShopingCart", FormMethod.Post)) markup inside. This creates a form for each onlinebookstore.entityframwork.book. Just make the necessary adjustments for multi-form on a single page to work.

Related

why checkbox wont check on page load?

i have the following database table for the Compounds table (chemical compounds/elements in the periodic table) there are typos in table data so ignore them
the data is :
the controller :
public class CheckboxController : Controller
{
//
// GET: /Checkbox/
testdbEntities db = new testdbEntities();
[HttpGet]
public ActionResult Index()
{
var comps = db.Compounds.Select(c => new CompoundModel { Id=c.Id, CompoundName=c.Name, IsSelected=c.IsSelected}).ToList();
CheckboxVM cvm = new CheckboxVM { checkboxData=comps};
return View(cvm);
}
[HttpPost]
public string Index(IEnumerable<CheckboxVM> collection)
{
return "";
}
}
Model class CompoundModel is:
public class CompoundModel
{
public int Id { get; set; }
public string Code { get; set; }
public string CompoundName { get; set; }
public bool IsSelected { get; set; }
}
and the ViewModel CheckBoxVM:
public class CheckboxVM
{
public string Id { get; set; }
public string CompoundNmae { get; set; }
public bool IsSelected { get; set; }
public IEnumerable<CompoundModel> checkboxData { get; set; }
}
When the page loads it should display check boxes with names and if db table has checked on them (IsSelected=1) then they should be checked.In the post back i need to receive the id, of the user checked checkboxes. At the moment my code does meet the first requirement to check the checked checkboxes based on IsSelected on page load. Is there a way to fix this?
If you need a video with debugging please ask i will be happy to post : )
THE VIEW: (UPDATE)
#model recitejs1.Models.CheckboxVM
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
foreach (var item in Model.checkboxData)
{
#Html.CheckBoxFor(x=>x.IsSelected, (item.IsSelected)?new{#checked="check"}:null)#item.CompoundName
#Html.HiddenFor(x=>x.Id, item.Id)
#Html.HiddenFor(x=>x.CompoundNmae, item.CompoundName)
}
<br><br>
<input type="submit" name="name" value="Send" />
}
You cannot use a foreach loop to generate form controls. It generates duplicate name attributes (that have no relationship to your model) and duplicate id attributes (invalid html).
Create a custom `EditorTemplate for your model
In /Views/Shared/EditorTemplates/CompoundModel.cshtml
#model recitejs1.Models.CompoundModel
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.CompoundName)
#Html.CheckBoxFor(m => m.IsSelected)
#Html.LabelFor(m => m.CompoundName)
Then in the main view
#model recitejs1.Models.CheckboxVM
....
#using (Html.BeginForm())
{
#Html.EditorFor(m => m.checkboxData)
<input type="submit" name="name" value="Send" />
}
The EditorFor() method will generate the correct html for each item in your collection
Note: You should inspect the html before and after you make this change to better understand how model binding works.
Note also that your POST method parameter needs to be
public string Index(CheckboxVM model)
since that's what the view is based on. However the only property of CheckboxVM that you use in the view is IEnumerable<CompoundModel> checkboxData in which case your view should be
#model IEnumerable<CompoundModel>
...
#Html.EditorFor(m => m)
and keep the POST method as it is (but change the GET method)

Passing Model via dropDownListFor() from view to controller

I am trying to pass a Model from my view to my controller using dropDownListFor.
After choosing something from the list it sends the model to my controller but it's content NULL.
This is what i have for the Model
public class Model
{
public int ModelId { get; set; }
[Required]
public string Name { get; set; }
}
This is what my ViewModel looks like
public class ModelVM
{
public List<Model> Models;
public Model SelectModel { get; set; }
public IEnumerable<SelectListItem> ModelItems
{
get { return new SelectList(Models, "ModelId", "Name"); }
}
}
The controller when i put data in the ViewModel looks like this
public ActionResult Index()
{
ModelVM modelVM= new ModelVM()
{
Models = manager.GetAllModels().ToList()
};
return View(modelVM);
}
Finally this is what i have in the View for the dropDownList
#using (Html.BeginForm("Home", "Home", FormMethod.Post))
{
#Html.DropDownListFor(model => model.SelectModel, Model.ModelItems)
<input type="submit" value="Go" />
}
So this is supposed to send Model to my controller.
But when i check the content of the passed Model in the controller, everything is NULL which isn't supposed to be because when i debug the view and check for the content of ModelItems, everything in the ModelItems is there.
Here is when i check the content of the passed Model
public ActionResult Home(Model model) <<<<<<<<<< Content == NULL
{
return View();
}
A <select> element on posts back a single value. Html has no concept of what your c# Model class is so you cannot bind to a complex object. You need to bind to the ModelId property of Model. Your view model should be
public class ModelVM
{
[Display(Name = "Model")]
public int SelectedModel { get; set; }
public SelectList ModelItems { get; set ;}
}
and in the controller
public ActionResult Index()
{
ModelVM modelVM = new ModelVM()
{
ModelItems = new SelectList(manager.GetAllModels(), "ModelId", "Name")
// SelectedModel = ? if you want to preselect an item
};
return View(modelVM);
}
and in the view
#Html.LabelFor(m => m.SelectedModel)
#Html.DropDownListFor(m => m.SelectedModel, Model.ModelItems)
and in the post method your model will be correctly bound with the ID of the selected model
Trying passing in type ModelVM to the Home action as that is the type being passed to Index view.
Instead of model.SelectModel in the drop-down declaration, you only need an int ID to capture which ID is selected.

Delete value by updating field

I have this:
View:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Bycicle</h4>
<hr />
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.id)
<div class="form-group">
<label class="control-label col-md-2" for="BycicleID">Mark</label>
<div class="col-md-10">
#Html.DropDownList("BycicleID", String.Empty)
#Html.ValidationMessageFor(model => model.id)
</div>
</div>
The controller:
public async Task<ActionResult> Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Bycicle bycicle = await db.Bycicles.FindAsync(id);
if (bycicle == null)
{
return HttpNotFound();
}
ViewBag.id = new SelectList(db.Bycicles, "BycicleID", "Mark", bycicle.id);
//ViewBag.Color = new SelectList(db.Bycicles, "Color", "Color", bycicle.Color);
//ViewBag.Weight = new SelectList(db.Bycicles, "Weight", "Weight", bycicle.Weight);
//ViewBag.Height = new SelectList(db.Bycicles, "Height", "Height", bycicle.Height);
return View(bycicle);
}
// POST: Bycicle/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(
[Bind(Include = "id, Mark, Color, Weight,Height")]
Bycicle bycicle)
{
if (ModelState.IsValid )
{
db.Entry(bycicle).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
ViewBag.id = new SelectList(db.Bycicles, "id", "Mark", bycicle.id);
return View(bycicle);
}
and the Model:
public class Bycicle
{
public int id { get; set; }
// [Column("Mark")]
public string Mark { get; set; }
public string Color { get; set; }
public string Weight { get; set; }
public string Height { get; set; }
public DateTime? LastTimeChecked { get; set; }
}
But so I can update the other values(Color, Weight, Height) But the Mark name will be deleted if I press save in the Update view. I also checked the db and the Mark value is gone after Update. But If I just press on Edit(update) Then first I see the value(Mark) in the dropdownlist, but after save the mark value is gone. Even if I didnt changed the Mark value in the Update view.
I just cant figure what is wrong.
Thank you!!
Oke,
I did understand it was a type mistake,
But what do you mean with the dropdonlists are not correct? Because you dont have a infinite mark list of bycicles. So that Is why I choose to make a dropdownlist with all the marks and the colors and the sizes. Because an admin fill in the marks, sizes, etc and then the user can select a mark, color, etc. But how will you design the different properties?
I dont have seperate tables for color, mark, etc. But is that necessary?
Thank you
Your not binding anything to the property Mark (what you have shown is bound to the ID property). Preferably the names of your select lists should not be the same as your properties.
In the controller
ViewBag.MarkList = new SelectList(db.Bycicles, "BycicleID", "Mark");
and in the view
#model YourAssembly.Bycicle
....
<div class="form-group">
#Html.LabelFor(m => m.Mark)
<div class="col-md-10">
#Html.DropDownListFor(m => m.Mark, (SelectList)ViewBag.MarkList)
#Html.ValidationMessageFor(m => m.Mark)
</div>
</div>
Note, since you binding all properties, you do not need [Bind(Include = "id, Mark, Color, Weight,Height")]
Edit
While passing values by ViewBag works, I recommend you use view models and strongly typed helpers so you have intellisense support as well as all the other benefits of using view models.
public class BycicleVM
{
public int id { get; set; }
// other properties of Bycicle that you want to edit
public SelectList MarkList { get; set; }
// other select lists
}
then assign the select lists to the view model rather than ViewBag

post complex viewmodels using ajax.beginForm MVC4 only getting null

im very new to mvc, lest say i have a viewmodel that cotains objects like
public class vm_set_rol
{
public IEnumerable<SelectListItem> roles { get; set; }
public Rol_User rol { get; set; }
}
rol is an object like:
public class Rol_User
{
public int idUser { get; set; }
public int Role { get; set; }
public int GrantedBy { get; set; }
public bool canGrant { get; set; }
public DateTime ExpirationDate { get; set; }
}
so i have a form on a view to let the user select 1 role from a roles dropdown and select a date and a checkbox somthing like:
<div class="ModalContainer">
#using (Ajax.BeginForm(new AjaxOptions
{
UpdateTargetId = "gestionRolContainer",
Url = "Permiso/Test",
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
}
)
)
{
<fieldset>
<legend>#Res_String.RolLabel</legend>
<span>ROL:</span><br />#Html.DropDownListFor(m => m.rol, Model.roles, new {#id="AdmPermUserRolesDropDown" })
<br />
#Html.CheckBoxFor(m => m.rol.conceder ,Model.rol.conceder) <span>Delegate?</span>
<br />
<input type="submit" class="buttonClass" value="OK" />
</fieldset>
}
</div>
the problem is that i only get null values, if i create some other property on the model like a string or int, those are posted back ok,
i kind of understad why objects are not posted back, bust is there any workaround??? or put a object on the modes is just wrong and i shuld declare the propertis on the viewmodel instead of an object???
Your dropdown is incorrectly bound. It should be bound to a scalar property to hold the selected value:
#Html.DropDownListFor(
m => m.rol.Role,
Model.roles,
new { id = "AdmPermUserRolesDropDown" }
)
As far as the Roles collection property is concerned, it will always be null in your controller action because this list is never sent to the server when you submit a form. Only the selected value is sent. So if you need to redisplay this view once again you will have to populate the Roles collection property in your HttpPost action the same way you did in your GET action.
Also your checkbox is bound to some m => m.rol.conceder property which doesn't exist in the view model you have shown. I guess you meant using the canGrant boolean property. Also you don't need to provide as second parameter to the CheckBoxFor helper the value. It will be inferred from the lambda expression:
#Html.CheckBoxFor(m => m.rol.canGrant) <span>Delegate?</span>
Last but not least, since you are using an Ajax.BeginForm make sure that you have referenced the jquery.unobtrusive-ajax.js script in your view.

Passing extra data to a post controller - MVC

Let's say I have the model
public class ViewModel
{
[Required]
[Display(Name = "Email address")]
public string Email { get; set; }
public string ExtraData{ get; set; }
}
Where ExtraData is simply some extra text that gets added in the GET action:
[HttpGet]
public ActionResult ActionMethod()
{
ViewModel modelWithExtraData= new ViewModel{ ExtraData = "Some extra data." };
return PartialView("MyView", modelWithExtraData);
}
And gets rendered inside the view as such:
<form>
#Html.TextBoxFor(m => m.Email)
<div>#Model.ExtraData</div>
<form>
When this form gets posted the the controller, I'd like the extra data "Some extra data" to be intact and posted with the model but this does not happen.
[HttpPost]
public ActionResult ActionMethod(ViewModel model)
{
//model.ExtraData = null ... Not good
}
I looked through all the #Html helper methods but can't seem to find the right one to simply display the text (non-editable) and send it back.
You could include the extra data as a hidden field inside the form alongside with the textbox:
<form>
#Html.TextBoxFor(m => m.Email)
#Html.HiddenFor(m => m.ExtraData)
<div>#Model.ExtraData</div>
<form>