List is not persisting through updatemodel - asp.net-mvc

My generic list of products won't persist on the Post if I use UpdateModel but if I pass the ViewModel in as a parameter to my post action method it works? How can I get it to work through UpdateModel way?
I'm using asp.net fx3.5 mvc 1.0
Model
namespace PostingGenericListAndUpdateModel.ViewModels
{
public class Product
{
public string Name { get; set; }
public bool IsSelected { get; set; }
}
public class ProductViewModel
{
public int OrderId { get; set; }
public List<Product> Products { get; set; }
public ProductViewModel()
{
Products = new List<Product>();
Products.Add(new Product() { Name = "Widget 1", IsSelected = false });
Products.Add(new Product() { Name = "Widget 2", IsSelected = false });
}
}
}
View
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Index</h2>
<% using (Html.BeginForm())
{ %>
<% for (int i = 0; i < 2; i++)
{ %>
<%= Model.Products[i].Name %> <%= Html.CheckBox("Model.Products[" + i + "].IsSelected") %>
<% } %>
<input id="Submit1" type="submit" value="submit" />
<% } %>
</asp:Content>
Controller
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
ProductViewModel model = new ProductViewModel();
return View(model, new string[] { "OrderId", "Products" });
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection form) //It will work if i accept the view model
{
ProductViewModel model = new ProductViewModel();
UpdateModel(model);
return View(model);
}

I see no reason for this parameter 'string sender'. Why do you need it?
The usual way to do this is indeed, by accepting the view model as a parameter to your Post method.
This is the way MVC passes the information from the view to your controller.
Your Post method line should be:
public ActionResult Index(ProductViewModel model)

Related

How to update list withing viewmodel in view? Passing data from view to controller

I am passing viewmodel to create view where I select few properties from dropdown list and then I create new model in database. The problem is that I have to select a product from dropdown list and after button click add product to list(which is defined in model). You can see the code bellow, I am having the problem of passing id of product as it is always null
SellsViewModel:
public class SellsViewModel
{
public List<Center> center { get; set; }
public List<Leader> leader { get; set; }
public List<Member> member { get; set; }
public List<Group> group { get; set; }
public Sell sell { get; set; }
public Guid productSelection { get; set; }
public IEnumerable<Product> product { get; set; }
public IEnumerable<Product> selectedProducts { get; set; }
}
Create.cshtml
#model Medical.ViewModels.SellsViewModel
#{
var addproduct = Model.product.Select(product => new SelectListItem
{
Text = product.Name,
Value = product.Id.ToString()
});
}
...
<div class="form-group">
<div align="right" class="col-md-2">
<b>Delivery</b>
</div>
<div align="center" class="col-md-2">
#Html.DropDownListFor(m => m.productSelection, addproduct, "-- Choose product --")
</div>
<div class="col-md-2">
<a asp-action="AddProducttoSell" method="post" asp-route-id="#Model.productSelection" class="btn btn-primary">Add</a>
</div>
</div>
Controller:
[HttpGet]
public IActionResult AddProducttoSell(Guid id)
{
var sProduct = _context.Products.FirstOrDefault(p => p.Id == id);
svm.selectedProducts.ToList().Add(sProduct);
return RedirectToAction(nameof(Create));
}
Basically, I want that when I choose product in view, I add it to selectedProducts list in viewmodel, and than return it to view. Afterwards, I will submit new model to database.
I got your example to work in Core.
First, I followed this tutorial, making appropriate changes:
https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/intro?view=aspnetcore-2.2
This is the code, starting with my Model-codeFirst and my ViewModel:
namespace SOPassDataViewToController.Models
{
public class Sell
{
public int ID { get; set; }
public string Name { get; set; }
}
}
namespace SOPassDataViewToController.Models
{
public class Product
{
public int Value { get; set; }
public string Text { get; set; }
}
public class SellsViewModel
{
public List<Product> Products { get; set; }
public int productSelection { get; set; }
}
}
Here is my Controller code:
[HttpPost]
public IActionResult AddProducttoSell(SellsViewModel sellsviewmodel)
{
//put breakpoint here to interrogate sellsviewmodel-productSelection
var viewModel = PrepViewModel();
return View(viewModel);
}
// GET: Sells
// I'm using this method instead of AddProducttoSell
//public async Task<IActionResult> Index()
public IActionResult Index()
{
var viewModel = PrepViewModel();
//return View(await _context.Sells.ToListAsync());
return View(viewModel);
}
public SellsViewModel PrepViewModel()
{
//prepping view model
//sending view model to view
SellsViewModel viewModel = new SellsViewModel();
viewModel.Products = new List<Product>();
var products = _context.Sells.ToList();
foreach (Sell product in products)
{
var eachProduct = new Product();
eachProduct.Value = product.ID;
eachProduct.Text = product.Name;
viewModel.Products.Add(eachProduct);
}
return viewModel;
}
Here is my view Index.cshtml:
#model SOPassDataViewToController.Models.SellsViewModel
#*need the form tag*#
<form asp-action="AddProducttoSell">
<div class="form-group">
<div align="right" class="col-md-2">
<b>Delivery</b>
</div>
<div align="center" class="col-md-2">
#*#Html.DropDownListFor(m => m.productSelection, addproduct, "-- Choose product --")*#
#Html.DropDownListFor(m => m.productSelection, new SelectList(Model.Products, "Value", "Text"))
</div>
<div class="col-md-2">
#*took out will need to put back asp-route-id="#Model.productSelection"*#
#*<a asp-action="AddProducttoSell" method="post" asp-route-id="#Model.productSelection" class="btn btn-primary">Add</a>*#
<div class="form-group">
<input type="submit" value="AddProducttoSell" class="btn btn-primary" />
</div>
</div>
</div>
</form>
#section scripts
{
#*//the natural progression for what you are doing is to change the href not the asp-route-id, because
//href is what gets rendered. So you can do the following--and tighten it up--
//you can also use FormCollection, or even possibly window.location, but the best way from Microsoft's
//tutorial is to use a model like my previous post*#
<script>
$(document).ready(function () {
$("#DropDownElement").change(function () {
$("#PostingElement").attr("href", "/Sells/Edit/" + $("#DropDownElement").val());
})
});
</script>
}
My Action looks like the following. I use Edit instead of AddProducttoSell
// GET: Sells/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var sell = await _context.Sells.FindAsync(id);
if (sell == null)
{
return NotFound();
}
return View(sell);
}

How do I get a strongly typed DropDownList to bind to a control Action

I've just started a new MVC project and I'm having trouble getting the post result from a form.
This is my Model Class :
public class User
{
public int id { get; set; }
public string name { get; set; }
}
public class TestModel
{
public List<User> users { get; set; }
public User user { get; set; }
public SelectList listSelection { get; set; }
public TestModel()
{
users = new List<User>()
{
new User() {id = 0, name = "Steven"},
new User() {id = 1, name = "Ian"},
new User() {id = 2, name = "Rich"}
};
listSelection = new SelectList(users, "name", "name");
}
}
This is my view class
#model MvcTestApplicaiton.Models.TestModel
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
#Html.DropDownListFor(x => x.user, #Model.listSelection)
<p>
<input type="submit" value="Submit" />
</p>
}
#if (#Model.user != null)
{
<p>#Model.user.name</p>
}
And this is my controller :
public class TestModelController : Controller
{
public TestModel model;
//
// GET: /TestModel/
public ActionResult Index()
{
if(model ==null)
model = new TestModel();
return View(model);
}
[HttpPost]
public ActionResult Test(TestModel test)
{
model.user = test.user;
return RedirectToAction("index", "TestModel");
}
}
The drop down list appears just fine but I can't see to get the ActionResult Test function to run. I thought it would just bind itself with reflection but whatever is wrong, I can't see it.
You have two main errors in your code.
As Brett said you're posting to the Index method, but you don't have Index method that supports POST verb. The easiest way to fix is to change Html.BeginForm() with Html.BeginForm("Test", "TestModel")
You're using Html.DropDownListFor in a wrong way. You could pass only a value types there, because don't forget that the View will generate an HTML page. So instead of User in your Model you should have an UserID and in your View you should have #Html.DropDownListFor(x => x.UserID, #Model.listSelection). And finally in your Action you should query your data source to get the details for the user with this ID.
Hope this helps.
Looks like you're posting back to index. Either use a GET Test() action method, or specify the ACTION parameter in BeginForm().
For example,
#using (Html.BeginForm("Test", "TestModel"))
{
#Html.DropDownListFor(x => x.user, #Model.listSelection)
<p>
<input type="submit" value="Submit" />
</p>
}
Or use a view named Test (rename index.cshtml to test.cshtml):
public ActionResult Test()
{
if(model ==null)
model = new TestModel();
return View(model);
}

MVC display foreign key from another table

Controller:
public ActionResult Details(int id)
{
ViewBag.AccountType = new BusinessLayer.AccountTypeManager().GetAccountTypes();
return View(new BusinessLayer.AccountManager().getAccount(id));
}
View:
<div class="display-label">Account Type</div>
<div class="display-field">#Html.DisplayFor(modelItem => modelItem.AccountType)</div><br />
This current view displays the AccountType ID. How can I display the AccountType Name which is being passed by the ViewBag.AccountType (IEnumerable)
something like following
<div class="display-label">Account Type</div>
<div class="display-field">#Html.DisplayFor(modelItem => modelItem.AccountType)</div>
#{
var TypeNames = ViewBag.AccountType as IEnumerable<string>;
foreach(var item in TypeNames)
{
<div>item</div>
}
}
Mode elegant way
public class AccountTypeVewModel
{
public IEnumerable<string> typeNames { get; set; }
public Account account { get; set; }
}
controller
public ActionResult Details(int id)
{
AccountTypeVewModel model = new AccountTypeVewModel();
model.typeNames = new BusinessLayer.AccountTypeManager().GetAccountTypes();
model.account = new BusinessLayer.AccountManager().getAccount(id);
return View(model);
}
view
<div class="display-label">Account Type</div>
<div class="display-field">#Html.DisplayFor(modelItem => modelItem.account.AccountType)</div>
#{
foreach(var item in Model.typeNames)
{
<div>item</div>
}
}

MVC checkbox comeing back null

I have a checkbox, but the form is being submitted the value ticked are not being submited...
Html:
#foreach (var radiobutton in Model.InterestedIn)
{
<span > #Html.CheckBox("selected", radiobutton)
<label>#radiobutton</label></span>
<br />
}
Model:
[Display(Name = "Would you be interested in receiving *")]
public IList<string> InterestedIn { get; set; }
Controller:
IList<string> lists = new List<string>();
lists.Insert(0, "Latest News");
lists.Insert(1, "Special Offers");
lists.Insert(1, "New Products");
model.InterestedIn = lists;
PostMethod:
[HttpPost]
public ActionResult Index(Competition model)
{
if (ModelState.IsValid)
{
I don't that your code will compile at all. The CheckBox helper expects a boolean as second argument whereas you are passing it a string.
Try like this:
#model MyViewModel
#using (Html.BeginForm())
{
foreach (var value in Model.InterestedIn)
{
<span>
<input type="checkbox" name="interestedin" value="#Html.AttributeEncode(value)" />
<label>#value</label>
</span>
<br />
}
<button type="submit">OK</button>
}
This assumes that you have the following view model:
public class MyViewModel
{
[Display(Name = "Would you be interested in receiving *")]
public IList<string> InterestedIn { get; set; }
}
and the following controller:
public class HomeController : Controller
{
public ActionResult Index()
{
IList<string> lists = new List<string>();
lists.Insert(0, "Latest News");
lists.Insert(1, "Special Offers");
lists.Insert(1, "New Products");
var model = new MyViewModel();
model.InterestedIn = lists;
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
If you want to use the CheckBox or even better the CheckBoxFor helper you will have to adapt your view model so that it no longer has an IList<string> property but an IList<CheckBoxItemViewModel> property where CheckBoxItemViewModel is another view model that will contain the label and a boolean property indicating whether this value has been selected or not.

I am new to MVC getting exception when i try to render the textbox dynamically with the following code. Please help

"Object reference not set to an instance of an object" Exception occurs with the following code
VIEW Code
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Hello_World_MVC.Models.ModelProperty>" %>
<asp:Content ID="aboutContent" ContentPlaceHolderID="MainContent" runat="server">.
<%using (Html.BeginForm())
{ %>
<%foreach (var cbName in Model.Obj)//Exception throws here NullreferenceException
{%>
<input id="cbID" type="checkbox" name="SelectedObject" value="<%=cbName.OptionID%>"/>
<%} %>
<%} %>
</asp:Content>
Control page
public ActionResult About()
{
AboutModels ObjAM = new AboutModels();//model class name
ModelProperty ObjMP = new ModelProperty();
ObjMP.Obj = ObjAM.dbValue();
return View();
}
Model Page
#region ModelsDTO
public class ModelProperty
{
private List<double> cbvalues = new List<double>();
public List<double> cbValues { get; set; }
private List<Option> obj = new List<Option>();
public List<Option> Obj { get; set; }
}
#endregion
public class AboutModels
{
DataClasses1DataContext dbObj = new DataClasses1DataContext();
public List<PollOption> dbValue()
{
List<Option> opValue = new List<Option>();
opValue = (from Value in dbObj.Options
select Value).ToList<Option>();
return opValue;
}
}
Please help..Thanks in advance
Change return View(); in AboutAction with return View(ObjMP);. Your mistake is that you forget to pass generated model to view, and it is null.
you should enter the model/object as paramter for returning the view
so in your case it is
return View(ObjMP);
hth
You need to pass the model to the view. Try this..
public ActionResult About()
{
AboutModels ObjAM = new AboutModels();//model class name
ModelProperty ObjMP = new ModelProperty();
ObjMP.Obj = ObjAM.dbValue();
return View(ObjAM);
}

Resources