Model not populated on Post - asp.net-mvc-4

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);
...
}

Related

How to send data from view back to controller in ASP.NET Core MVC application?

I can not figure out how can I pass data from view back to controller. I have a list of ChildViewModels that are shown on screen. User can add data to this list and after everything is done, press 'Submit' and send these items back to controller.
Here are my view models:
public class ParentViewModel
{
public int Id { get; set; }
public IList<ChildViewModel> Children { get; set; }
}
public class ChildViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
Here is how I display them in main view:
<div id="editorRows">
#foreach (var item in Model.Children)
{
<partial name="_myPartial" model="item" />
}
</div>
<a id="addItem" asp-action="BlankSentence" asp-controller="Home">Add Row...</a> <br />
<input type="submit" id="submit" value="Finished" onclick="SaveUser()" />
Here is partial view definition:
<div class="editorRow">
#using (Html.BeginCollectionItem("Children"))
{
#Html.HiddenFor(m => m.Id)
<span>Name: </span> #Html.EditorFor(m => m.Name);
}
delete
Then I have such script which adds new row:
$("#addItem").click(function () {
$.ajax({
url:'#Url.Action("BlankSentence", "Home")',
cache: false,
success: function (html) {
$("#editorRows").append(html);
}
});
return false;
});
User can add rows, all this works fine. Then I would like to have a button that sends info back to controller. I would create object that holds necessary data, including information that is 'inside' added objects (partialViews?) and send it back with help of ajax. This would be done with function like this:
function SaveUser() {
var products = [];
$("#editorRows").each(function(index, value) {
pr.push(value);
});
var model =
{
Name: "SomeDataFromTextBox",
Products : pr,
};
$.ajax({
type: "POST",
data: JSON.stringify(model),
url: "/Home/Save",
contentType: "application/json"
}).done(function(res) {
console.log('res', res);
});
}
Here is receiver:
public JsonResult Save([FromBody] SomeViewModel model)
{
return Json(model);
}
My question is this - how do I populate this collection to be sent back to controller?
var products = [];
$("#editorRows").each(function(index, value) {
pr.push(value);
});
I have tried many things, it either sends null or does not even call the Save method. Sorry for the lengthy post, I am totally new to ASP.NET Core and did not know which parts of code could be omitted without losing general idea.
Also, if my approach is flawed in some other way, I would like to hear your comments.
jQuery .each() function gives you the index as first parameter and the whole html Element as second parameter. You need to use this element to select the inner input element and get its value. Also $("#editorRows") gives you the wrapper div element, you can use $(".editorRow") to get the collection of <div class="editorRow"> elements.
var products = [];
$(".editorRow").each(function(index, element) {
// select the element that was created with #Html.EditorFor(m => m.Name)
let inputEl = element.querySelector("input[name='Name']");
// get the input element value
products.push(inputEl.value);
});
jQuery .each() documentation

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.

How to pass [HttpGet] list variables to [HttpPost] in mvc4?

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.

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);

ASP.NET MVC 4 - ListBoxFor, send selectedValue in ActionLink

I have a list of model. I want to retrieve the listBoxSelectedValue to send it in my actionLink to edit it.
This is my view :
#using (Html.BeginForm())
{
#Html.ListBoxFor(a => a.SelectedApplis, new SelectList(ViewBag.Applis,"ID","Name", Model.SelectedApplis))<br/>
#Html.ActionLink("Add","Create","Application")<br/>
#Html.ActionLink("Edit","Edit","Application", null, new { listAppId = Model.SelectedApplis})<br/>
#Html.ActionLink("Delete","Delete","Application")<br/>
}
I created a class "ListBoxApplication" with the List which will contain the selectedValue of the ListBox.
public class ListBoxApplication
{
public IEnumerable<int> SelectedApplis { get; set; }
public ListBoxApplication()
{
SelectedApplis = new List<int>();
}
}
I have 2 controllers : Application and Home
In HomeController, I created the model ListBoxApplication which contain the List. In my ViewBag.Applis, i have all my ApplicationModel.
public ActionResult Index()
{
ListBoxApplication listeApplis = new ListBoxApplication();
ViewBag.Applis = ApplicationModels.GetListApplications();
return View(listeApplis);
}
In my ApplicationController :
public ActionResult Edit(ListBoxApplication listAppId)
{
// I WANT TO RETRIEVE MY listAppId HERE, but it is always 'null'
return View();
}
So I think my problem is in the actionLink :
#Html.ActionLink("Edit","Edit","Application", null, new { listAppId = Model.SelectedApplis})
Me Edit Method is not is the actual controller (Home/Index). I need to send the selectedValue of my ListBox in my actionLink to (Application/Edit).
The listAppId is always 'null'. It doesn't retrieve the value... Is there a mistake in my actionLink ?
Thanks for advance
I don't believe that action links will trigger a postback to the server. Try this instead:
#Html.ActionLink("Delete","Delete","Application")<br/>
#Html.ActionLink("Add","Create","Application")<br/>
#using (Html.BeginForm("Detail","Application"))
{
#Html.ListBoxFor(a => a.SelectedApplis, new SelectList(ViewBag.Applis)) //not sure what the other params you had here were for, but it should work like this
<br/>
<input type="submit" name="Edit" value = "Edit"/>
#*added in response to comment*#
<input type="submit" name="Delete" value = "Delete"/>
<input type="submit" name="Add" value = "Add"/>
}
If you plan on having all of those buttons post back to the server, you could also use ajax (and javascript) to accomplish this same goal, without needing to write out a form for each individual button. Both ways would work just fine, multiple forms is technically easier though.
public ActionResult Detail(ListBoxApplication listAppId, bool Edit, bool Add, bool Delete)
{
if(//check your bools here){
}
return View();
}