How to pass [HttpGet] list variables to [HttpPost] in mvc4? - asp.net-mvc-4

My problem is list variables,when i add variable to list ,variable add to list properly in HttpGet,when i pass same variable in HttpPost,variable not passing,why variable not passing to HttpPost,Please help me to solve this problem,i am giving my code below please check.
List<tbl_Basket2> basket2 = new List<tbl_Basket2>();
[HttpPost]
public ActionResult Basket(tbl_Basket2 basket2)
{
int qty=basket.int_Qty ;
return View(basket2);
}
view page,
foreach (var item in Model)
{
#Html.DisplayFor(m => item.dec_Price)
#Html.EditorFor(m => item.int_Qty)
#Html.DisplayFor(m => item.TotalPrice)
}

In the controller: -
public ActionResult Basket(tbl_Basket2 basket2)
change to:
public ActionResult Basket(List<tbl_Basket2> basket2)
change the view model to use #model List<tbl_Basket2> instead of an Ienumerable as the Model.
change the view to use a for - next loop: -
#using (Html.BeginForm())
{
for (var i = 0; i < Model.Count(); i++)
{
#Html.DisplayFor(m => item[i].dec_Price)
#Html.EditorFor(m => item[i].int_Qty)
#Html.DisplayFor(m => item[i].TotalPrice)
}
}
That should play nicely with the MVC deserialiser model binder.

Related

How can I link a DropDown and Textbox to my Model's data?

Here is the code for my Model. ListBuilder.DropDown is part of a common class of functions, which simply returns a List when provided the string name of a stored procedure that will be called on the database.
There is some more shared common class code (stored procedure related) with in the try statement, but that implementation is irrelevant to the problem I'm having. The data is successfully retrieved and stored into the model.
public class PositionViewModel
{
[Display(Name = "Series")]
public string series { get; set; }
public int seriesID { get; set; }
public List<SelectListItem> list_Series { get; set; }
}
public PositionViewModel(string id)
{
Get(id);
this.list_Series = ListBuilder.DropDown(AppConstants.StoredProc_GetSeries);
}
public Position Get(string id)
{
ExecStoredProcedure sp = null;
DataTable dt = new DataTable();
try
{
sp = new ExecStoredProcedure(AppConstants.SP_POSITION_GET, new ConnectionManager().GetConnection(), AppConstants.SP_POSITION_GET);
sp.SPAddParm("#PD_ID", SqlDbType.Char, id, ParameterDirection.Input);
dt = sp.SPselect();
if (dt.Rows.Count > 0)
{
this.pd_id = dt.Rows[0]["PD_ID"].ToString();
this.official_title = dt.Rows[0]["label"].ToString();
this.series = dt.Rows[0]["Series"].ToString();
this.grade = dt.Rows[0]["Grade"].ToString();
this.PDType = dt.Rows[0]["PDType"].ToString();
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
sp.dbConnection.Close();
}
return this;
}
Here is the code for my Controller
[HttpGet]
public ActionResult PositionEdit(string id)
{
PositionViewModel model = new PositionViewModel(id);
return View("PositionEdit", model);
}
[HttpPost]
public ActionResult PositionEdit(PositionViewModel model)
{
if (ModelState.IsValid)
{
int rc = model.Update();
return RedirectToAction("PositionView");
}
else
{
return View("PositionEdit", model);
}
}
Here is the code for my view. What I'd like to have is a dropdownlist that contains the model.seriesID (a sequence number) but as the user selects an item, it will update the textbox with model.series (the name of the series)
#model Project.Models.PositionViewModel
#{
ViewBag.Title = "Edit Position Description";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="editor-label">
#Html.LabelFor(model => model.series)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => Model.seriesID, Model.list_Series, new { style = "width:550px" })
#Html.ValidationMessageFor(model => Model.seriesID)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.series, new { style = "width:250px;" })
#Html.ValidationMessageFor(model => model.series)
</div>
<div class="toppad20">
<input type="submit" value="Save" />
</div>
}
I am having trouble linking the dropdownlist with the textbox. Do I need some kind of onChange event? Thanks in advance for your help.
Your solution involves passing a string into your view model's constructor. However, on post, the model binder will be incapable of instantiating your view model with anything but the parameterless constructor. That's part of the reason, but not the only reason, that view models should not handle things like datastore access. That is the job of the controller.
On your view model, leave your list property as a auto-implemented property and then in your controller call ListBuilder.DropDown, which you can use data from your model to call, at that point.

MVC IPagedList with model type error

I get the error in my MVC 5 App:
CS1061: 'IPagedList' does not contain a definition for 'TargetContact' and no extension method 'TargetContact' accepting a first argument of type 'IPagedList' could be found (are you missing a using directive or an assembly reference?)
I saw the answers here but I still don’t get it done :(
It's probably pretty easy to solve.
public ActionResult Index(string searchTargetContact = null, int page = 1)
{
var model =
from r in db.Outreach
orderby r.TargetContact descending
where (r.TargetContact.StartsWith(searchTargetContact) || searchTargetContact == null)
select new Models.OutreachSetListViewModel
{
TargetContact = r.TargetContact,
NextOutreachStep = r.NextOutreachStep,
GoalOfOutreach = r.GoalOfOutreach,
};
model.ToPagedList(page, 10);
return View(model);
namespace WebApplication11.Models
{
public class OutreachSetListViewModel
{
public string NextOutreachStep { get; set; }
public string TargetContact { get; set; }
public string GoalOfOutreach { get; set; }
}
}
#model IPagedList<OutreachSetListViewModel>
<table class="table" id="networkingList">
<tr>
<th>#Html.DisplayNameFor(model => model.TargetContact)</th>
<th>#Html.DisplayNameFor(model => model.NextOutreachStep)</th>
<th>#Html.DisplayNameFor(model => model.GoalOfOutreach)</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(modelItem => item.TargetContact)</td>
<td>#Html.DisplayFor(modelItem => item.NextOutreachStep)</td>
<td>#Html.DisplayFor(modelItem => item.GoalOfOutreach)</td>
</tr>
}
The model in the view is IPagedList<OutreachSetListViewModel>, so when you are looping though the model, each item does have a TargetContact.
However, when you are displaying the header, the model for the DisplayNameFor is not the individual item, but the list. The list does not have the TargetContact property so we have to get it from one of the items in the list.
In this case, we check to see if there are any elements in the list, and if there are, get the TargetContact from the first element.
#if(Model.Any())
{
<tr>
<th>#Html.DisplayNameFor(model => model[0].TargetContact)</th>
<th>#Html.DisplayNameFor(model => model[0].NextOutreachStep)</th>
<th>#Html.DisplayNameFor(model => model[0].GoalOfOutreach)</th>
<th></th>
</tr>
}
Controller
You are not doing anything with the returned value from model.ToPagedList(page, 10);
Save it to a value and pass it in to the view:
var vm = model.ToPagedList(page, 10);
return View(vm);
I know i am a late, but then again I was phasing this problem today and solved by using the same methodology used when it's an IEnumerable all I did was replace IEnumerable with IPagedList and it worked like a charm.
public static string DisplayNameFor<TModelItem, TResult>(this IHtmlHelper<IEnumerable<TModelItem>> htmlHelper, Expression<Func<TModelItem, TResult>> expression)
{
if (htmlHelper == null)
throw new ArgumentNullException(nameof(htmlHelper));
if (expression == null)
throw new ArgumentNullException(nameof(expression));
return htmlHelper.DisplayNameForInnerType(expression);
}
public static string DisplayNameFor<TModelItem, TResult>(this IHtmlHelper<IPagedList<TModelItem>> htmlHelper, Expression<Func<TModelItem, TResult>> expression)
{
if (htmlHelper == null)
throw new ArgumentNullException(nameof(htmlHelper));
if (expression == null)
throw new ArgumentNullException(nameof(expression));
return htmlHelper.DisplayNameForInnerType(expression);
}

Model is Null in Httppost mvc

My Model is
public class IssueEntryModel
{
public IEnumerable<SelectListItem> OrderNumbers { get; set; }
public string SelectedWorkOrder { get; set; }
public string MaterialCode
{
get; set;
}
public List<GroupedIssueData> MaterialData { get; set; }
}
And the view is
#model InventoryEasy15.Models.IssueEntryModel
#{
var issueData = Model.MaterialData;
var workorders = Model.SelectedWorkOrder;
}
#using (Html.BeginForm("SaveIssueEntry", "IssueMaster", FormMethod.Post, new { id = "issueEntryForm" }))
{
#for (int i = 0; i < issueData.Count(); i++)
{
<tr>
<td>#issueData[i].MaterialCode</td>
<td>#issueData[i].MaterialDescription</td>
<td>#issueData[i].Unit</td>
<td>#issueData[i].ReqQty</td>
<td>#Html.TextBoxFor(m => issueData[i].IssueQty, new { style = "width:70px" })#Html.ValidationMessageFor(m => issueData[i].IssueQty)</td>
<td class="text-center">#Html.CheckBoxFor(m => issueData[i].isSavings)</td>
</tr>
}
And I have post method as
public ActionResult SaveIssueEntry(IssueEntryModel model)
{
var result = new Dictionary<string, string>();
And the get contains the details to fill the view as
//Method Get the material details based on the work order id
public async Task<ActionResult> GetWorkOrderMaterialDetails(IssueEntryModel m)
{
During post to a new method , the model is becomes null, Any thoughts?
Razor uses the expression passed to the HTML helpers in order to build the proper name for the inputs that will allow the modelbinder to bind them properly on post. That means the expression needs to match the access method of the property exactly. By saving Model.MaterialData to the issueData variable and utilizing that, you're disrupting this. In other words, you're ending up with inputs named like issueData[0].IssueQty, instead of MaterialData[0].IssueQty. The modelbinder doesn't know what to do with issueData on post, because nothing on your model matches that.
Long and short, your textbox needs to be declared like:
#Html.TextBoxFor(m => m.MaterialData[i].IssueQty, ...)
Similarly for your checkbox:
#Html.CheckBoxFor(m => m.MaterialData[i].isSavings)

Implementation of Kendo Listview control in MVC

I was trying to implement Listview control of Kendo UI for MVC. I am trying to bind the list view with my model but I am getting this error :
"CS1977: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type"
I have checked some other questions on stackoverflow with the same error but I am unable to know the cause for this error as this is kendo Syntax and there is nothing wrong with my code as far as I know.
The error is in this line::.DataSource(ds => ds
View Page:
#{
ViewBag.Title = "Courses";
}
#using Kendo.Mvc.UI
<h2>Courses</h2>
Back
<div class="bodywrap">
<div class="CommonClass">
#( Html.Kendo().ListView<K_SampleProject.Models.CourseModel>(Model)
.Name("listView")
.TagName("div")
.ClientTemplateId("template")
.DataSource(ds => ds
.Model(model =>
{
//The unique identifier (primary key) of the model is the ProductID property
model.Id(p => p.ProductID);
// Declare a model field and optionally specify its default value (used when a new model instance is created)
model.Field(p => p.ProductName).DefaultValue("N/A");
// Declare a model field and make it readonly
model.Field(p => p.UnitPrice).Editable(false);
})
)
.Pageable()
)
</div>
</div>
<script type="text/x-kendo-tmpl" id="template">
<div class="product">
<img src="#Url.Content("~/content/web/foods/")${ProductID}.jpg" alt="${ProductName} image" />
<h3>${ProductName}</h3>
<dl>
<dt>Price:</dt>
<dd>${kendo.toString(UnitPrice, "c")}</dd>
</dl>
</div>
</script>
Model
namespace K_SampleProject.Models
{
public class CourseModel
{
public List<tbl_Courses> CourseList { get; set; }
public string ProductID { get; set; }
public string ProductName { get; set; }
public string UnitPrice { get; set; }
}
}
Controller
public ActionResult Courses()
{
CourseModel Model = new CourseModel();
RegistrationService ObjService = new RegistrationService();
Model.CourseList = ObjService.GetCourses();
return View(Model);
}
The main error in your code is that you passing single CourseModel class to the list, when it expects the List of CourseModel.
So, your Controller should looks like:
public ActionResult Courses()
{
List<CourseModel> result;
CourseModel Model = new CourseModel();
RegistrationService ObjService = new RegistrationService();
Model.CourseList = ObjService.GetCourses();
result.Add(Model);
return View(result);
}
I also advise:
Add #model List<CourseModel> in top of the View
If it is a PartialView (not main view like index) change return for: return PartialView(result);

Model not populated on Post

I have this in a partial view
#using (Html.BeginForm(MVC.Inventory.ActionNames.AddVehicles, MVC.Inventory.Name, new { model = Model.Items }))
{
<div><button>#AuctionControllerResource.AddToBiddingProcess</button></div>
}
The post method is this
[HttpPost]
public virtual ActionResult AddVehicles(List<VehicleViewModel> model)
{
return null;
}
When I put a breakpoint in the view I can see that Model.Items has 1 item in it as it should. However, when I hit the Post action method on button click, there are no items in the model.
I have added this in the form
#Html.HiddenFor(m => m.Items)
but it doesn't help.
What am I doing wrong?
thanks,
Sachin
EDIT
Additional code
public class ListViewModel<T> : IQuery
where T : class
{
public List<T> Items { get; set; }
...
}
The following doesn't do what you think it does:
new { model = Model.Items }
You cannot pass complex objects like that. You will have to generate hidden fields in the form if you want this to work.
I have added this in the form
#Html.HiddenFor(m => m.Items)
No, it's normal that it doesn't help. The hidden field works only with simple types. You wil have to loop through the items in the collection and generate corresponding fields for each property of each element:
#using (Html.BeginForm(MVC.Inventory.ActionNames.AddVehicles, MVC.Inventory.Name))
{
for (var i = 0; i < Model.Items.Count; i++)
{
#Html.HiddenFor(x => x.Items[i].Prop1)
#Html.HiddenFor(x => x.Items[i].Prop2)
#Html.HiddenFor(x => x.Items[i].ComplexProp3.Prop1)
#Html.HiddenFor(x => x.Items[i].ComplexProp3.Prop2)
...
}
<div>
<button>#AuctionControllerResource.AddToBiddingProcess</button>
</div>
}
But this seems quite a waste. Since the user cannot modify those values anyway in the form, I would recommend you simply passing an id which will allow you to retrieve the corresponding items from your data store in the POST action:
#using (Html.BeginForm(MVC.Inventory.ActionNames.AddVehicles, MVC.Inventory.Name, new { id = Model.ItemsId }))
{
<div>
<button>#AuctionControllerResource.AddToBiddingProcess</button>
</div>
}
and then:
[HttpPost]
public virtual ActionResult AddVehicles(int id)
{
List<VehicleViewModel> model = GetItemsFromDataStore(id);
...
}