MVC partial view wtih different model - asp.net-mvc-4

I have model as
public class MainDataViewModel
{
[Required]
[Display(Name = "Select Work Orders")]
public string[] SelectedWorkOrdersValues { get; set; }
public MultiSelectList WorkOrderIds { get; set; }
public IEnumerable<ORDERMASTER> ordersDetails;
}
And Main View as
#model InventoryEasy15.Models.MainDataViewModel
<div class="box-body">
<div class="col-md-6">
<div class="form-group">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<label for="fileToUpload">Select the Work Orders</label>
#Html.ValidationMessageFor(m => m.WorkOrderIds, "", new { #class = "text-danger" })
#Html.ListBoxFor(m => m.SelectedWorkOrdersValues, Model.WorkOrderIds as MultiSelectList, new { id = "WorkOrders", #class = "form-control", data_placeholder = "Choose Work Orders..." })
</div>
</div>
</div>
<!-- /.box-body -->
<div class="box-footer">
<input type="submit" value="Get WorkOrder Details" id="btnSubmit" class="btn btn-primary">
</div>
</div>
</div>
</div>
#Html.Partial("MainDataWorkOrderDetails", Model.ordersDetails)
And the Partial view as
#model IEnumerable<InventoryEasy15.ORDERMASTER>
<div id="myDisplayID"><div>
Now I am getting error as
The model item passed into the dictionary is of type 'InventoryEasy15.Models.MainDataViewModel', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[InventoryEasy15.ORDERMASTER]'.
Any thoughts.
The controller here is
public async Task<ActionResult> MainDataWorkOrderDetails(MainDataViewModel m)
{
var model = new MainDataViewModel();
var result = await db.ORDERMASTERs.Where(x => x.WOID == "WO7446708").ToListAsync();
if (result != null)
{
model.ordersDetails = result;
}
return PartialView(model);
}

You are passing model to the PartialView. Now, the model is of type MainDataViewModel, and your partial view expects the model of type IEnumerable<InventoryEasy15.ORDERMASTER>
return PartialView(model);
I think you should consider passing model.orderDetails to the partial view from your action.
return PartialView(model.orderDetails);
Or else, simply return the View containing the partial view if you want to pass the whole model

Related

How to solve empty model trouble using both Ajax.BeginForm and Html.BeginForm in MVC

I am new to MVC and stuck in passing modal to controller.
I have read many similar threads in SO, to no avail.
Here, I have a view for entering order details.
User will enter order item details (using ajax.BeginForm) and when he clicks save, whole order will be saved in backend (using Html.BeginForm). Ajax.BeginForm is working properly and passing + displaying records properly. But Html.BeginForm is passing model as nothing.
Here is my code ...
My Models
public class OrderItemsModel
{
public string SrNo { get; set; }
public int? ItemCode { get; set; }
public string ItemName { get; set; }
public Decimal? Qty { get; set; }
public Decimal? Rate { get; set; }
public Decimal? Amount { get; set; }
}
public class OrderModel
{
public string OrderNumber { get; set; }
public string OrderDate { get; set; }
public int? CustomerCode { get; set; }
public string CustomerName { get; set; }
public string Note { get; set; }
//List of items selected in Order
public List<OrderItemsModel> ItemsSelected { get; set; }
}
Extract from My View
#model OrderApplication.Models.OrderModel
#{
ViewBag.Title = "Index";
Model.ItemsSelected = ViewBag.getlist;
}
#using (Ajax.BeginForm("UpdateItemList", "Order", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "selectedtable" }))
{
<h2 style="margin-left:5%;">Order Entry</h2>
//Order No & Date
<div class="row">
<div class="col-sm-6">
<div class="col-sm-3">
#Html.LabelFor(model => model.OrderNumber, "OrderNo"):
</div>
<div class="col-sm-3">
#Html.TextBoxFor(model => model.OrderNumber, new { #class = "form-control", #readonly = "readonly" })
</div>
</div>
<div class="col-sm-6">
<div class="col-sm-3">
#Html.LabelFor(model => model.OrderDate, "Date"):
</div>
<div class="col-sm-3">
#Html.TextBoxFor(model => model.OrderDate, new { #class = "form-control" })
</div>
</div>
</div>
<br />
//Table of entries
<div id="selectedtable">
#Html.Partial("_selectTable", Model);
</div>
<br />
}
#*Main Save*#
<div class="row">
<div class="col-sm-12">
<div class="col-sm-3">
#using (Html.BeginForm("SaveData", "Order", new { order = Model, id = "loginform", #class = "justify-content-center" }))
{
<input type="submit" value="Save Order" class="btn btn-success" />
}
</div>
<div class="col-sm-3">
<input type="button" class="btn btn-success" value="Clear Form" onclick="location.href='#Url.Action("Clear", "Order")'" />
</div>
</div>
</div>
My Controller
public class OrderController : Controller
{
public List<OrderItemsModel> dd = new List<OrderItemsModel>() ;
[HttpPost]
public ActionResult SaveData(OrderModel order, string id)
{
if (order == null) //order is always Nothing
{
return View(order);
}
if (order.CustomerCode == 0)
{
return View(order);
}
return View(order);
}
}
}
You shouldn't use both Ajax.BeginForm and Html.BeginForm, as it won't work. Please, check this post as might be of help to decide which one you wish to choose:
https://forums.asp.net/t/1757936.aspx?When+to+use+Html+BeginForm+vs+ajax+BeginForm
If you still want to use Html.BeginForm, just move the using sentence to replace your Ajax.BeginForm at the top of the page, so the form covers all fields, and the model won't be empty.

mvc model fileupadload does not send model data

I have a mvc 5 asp.net file upload that upload pictures and create path for them.
File uploaded successfully, but model data does comes in null.
This is my model:
[Table("Slider")]
public partial class Slider
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Slider()
{
Slider1 = new HashSet<Slider>();
}
public int ID { get; set; }
public string Path { get; set; }
public int? Slider_ID { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Slider> Slider1 { get; set; }
}
This is Controller part:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,Path")] Slider slider, List<HttpPostedFileBase> FileContent)
{
if (ModelState.IsValid)
{
byte[] imageData = null;
if (Request.Files.Count > 0)
{
HttpPostedFileBase poImgFile = Request.Files["Path"];
using (var binary = new BinaryReader(poImgFile.InputStream))
{
imageData = binary.ReadBytes(poImgFile.ContentLength);
}
}
string picturePath = string.Format(Server.MapPath("~/content/slider/{0}.jpg"), slider.ID);
CreateDirectory(picturePath);
using (FileStream writer = new FileStream(picturePath, FileMode.Create))
{
writer.Write(imageData, 0, imageData.Length);
}
db.Sliders.Add(slider);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(slider);
}
And this is the view:
#using (Html.BeginForm("Create", "Sliders", FormMethod.Post, new { #class = "form-horizontal", role = "form", enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="col-12 form-group">
<div class="row">
#Html.LabelFor(model => model.Path, "Picture", htmlAttributes: new { #class = "control-label col-12 col-md-2" })
<div class="col-12 col-md-10">
<input type="file" name="Path" id="fileUpload" accept=".png,.jpg,.jpeg,.gif" />
#Html.ValidationMessageFor(model => model.Path, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
<div class="col-12 text-left">
<input type="submit" value="create" class="btn btn-success" /> | #Html.ActionLink("back to list", "Index", null, new { #class = "btn btn-primary" })
</div>
</div>
</div>
}
When I check my database I see that Path is :
System.Web.HttpPostedFileWrapper
and Slider_ID is null and Slider_ID1 is null too.
Any suggestions?
After searching my previous codes, I've found that, when saving changes to db in controller class, db.SaveChanges(); slider argument which had been sent to Create method, will get new ID.
I've added these 2 lines after if:
if (ModelState.IsValid)
{
db.Sliders.Add(slider);
db.SaveChanges();
and done my other business logic in lines after that.

ASP.Net MVC: When form post then one view model property getting null

i have simple form where one dropdown and one submit button. i have two index function one for get and one for form post. when i select a product from dropdown and click on submit button then my index action getting invoke but there i notice my products property getting null. see my code please and tell me where i made the mistake.
view code
#model AuthTest.Models.SampleViewModel
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>DateValTest</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Products, htmlAttributes: new { #class = "control-label col-md-2", style = "padding-top:0px;" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SelectedProductId, new SelectList(Model.Products, "ID", "Name"), "-- Select Product--")
#Html.ValidationMessageFor(model => model.SelectedProductId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Submit" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
model code
public class Product
{
public int ID { set; get; }
public string Name { set; get; }
}
public class SampleViewModel
{
[Display(Name = "Products")]
public List<Product> Products { set; get; }
[Required(ErrorMessage = "Select any one")]
public int SelectedProductId { set; get; }
}
controller code
public class TestValController : Controller
{
// GET: TestVal
public ActionResult Index()
{
var SampleVM = new SampleViewModel();
SampleVM.Products = new List<Product>
{
new Product{ ID=1, Name="IPhone" },
new Product{ ID=2, Name="MacBook Pro" },
new Product{ ID=3, Name="iPod" }
};
return View(SampleVM);
}
[HttpPost]
public ActionResult Index(SampleViewModel vm)
{
var SampleVM = new SampleViewModel();
SampleVM.Products = new List<Product>
{
new Product{ ID=1, Name="IPhone" },
new Product{ ID=2, Name="MacBook Pro" },
new Product{ ID=3, Name="iPod" }
};
if (ModelState.IsValid)
return View(vm);
else
return View(SampleVM);
}
}
when i debug second action then i saw vm products property getting null
please tell me where i made the mistake?
thanks
You are not making any mistake, You are not getting the list of products back because you are not including them in the HTML input form.
If you want to include the list of products you can add the following inside the input form
#for (int i = 0; i < Model.Products.Count(); i++)
{
<div>
#Html.HiddenFor(model => Model.Products[i].Name)
#Html.HiddenFor(model => Model.Products[i].ID)
</div>
}
#Mou,
Please modify your razor view and try this.
In Razor View nowhere you have specified the Http verb(Get,Post).
#using (Html.BeginForm("Index", "TestVal", FormMethod.Post)

ajax beginform mvc callback

I have a single page with multiple partials set up. I want to be able to validate and update each partial seperatly. The validation works BUT when I type in a correct value and press save the page goes to the partial view instead of staying on the single page. What am I doing wrong here?
This is my main page :
#for (var i = 0; i < 10; i++)
{
var idTest = "Test_" + i;
<div id="#idTest">
#Html.Action("Detail", new { id = i })
</div>
}
The partial is created like this:
#{
var idTest = "Test_" + Model.Id;
var ajaxOptions = new AjaxOptions
{
UpdateTargetId = #idTest,
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace
};}
#using (Ajax.BeginForm("Detail", ajaxOptions))
{ #Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Test</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Gemeente, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.Gemeente, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Gemeente, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
This is the simple model:
public class Test
{
public int Id { get; set; }
[Required(ErrorMessage = "Gelieve een gemeente op te geven")]
public string Gemeente { get; set; }
}
These are the actions:
[HttpGet]
public ActionResult Detail(int id)
{
Models.Test model = new Models.Test();
model.Id = id;
return View(model);
}
[HttpPost]
public ActionResult Detail(Models.Test model)
{
if(ModelState.IsValid)
{
return PartialView(model);
}
return PartialView(model);
}
Add these lines to your view and also use #Html.Partial as shown below
<script src="~/Scripts/jquery-1.8.2.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
so that your main view is
<script src="~/Scripts/jquery-1.8.2.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
#for (var i = 0; i < 10; i++)
{
var idTest = "Test_" + i;
<div id="#idTest">
#Html.Partial("Detail", new Test { Id = i })}
</div>
}
Scripts would be for unobtrusive ajax so that your ajax button works and Html.Partial so that first time when you load your page in foreach only partial view is rendered (not the full view)

Return selected objects for MultiSelect DropDownList

I have this DropDownListFor added to my (partial) View _CreateUser.cshtml as:
<div class="modal fade bs-example-modal-lg" id="createUserModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Create A User</h4>
</div>
#using (Html.BeginForm("Create", "Users", FormMethod.Post))
{
<div class="modal-body">
#Html.LabelFor(model => model.Departments)
<div>
#Html.DropDownListFor(
model => model.SelectedDepartmentIds,
new SelectList(Model.DepartmentSelectList, "Value", "Text"),
new {#class = "multiselect departments", multiple = "multiple"})
</div>
...
Above partial view is declared in main View Index.cshtml and is shown as modal popup on click of 'Create' button
#Html.ActionLink("Create user", "Create", "Users", new { #class = "btn btn-primary", #href = "#createUserModal", #data_toggle="modal" })
...
#Html.Partial("_CreateUser", new UserViewModel()
{ //Populating SelectList required for loading dropdownlist
DepartmentSelectList = modelFactory != null ?
modelFactory.Departments.Select(dept => new SelectListItem{Value = dept.Id.ToString(),Text = dept.Name}).ToList()
: null
})
UserViewModel.cs
public IEnumerable<String> Departments { get; set; }
//Used purely for binding DropDownList
public IEnumerable<SelectListItem> DepartmentSelectList { get; set; }
public string SelectedDepartmentIds { get; set; }
//Ideally, I want to populate selected items in this list
public IEnumerable<DepartmentModel> DepartmentModels { get; set; }
UserController.cs
[HttpPost]
public ActionResult Create(UserViewModel postedModel)
{
if (ModelState.IsValid)
{
//Incorrect - returns only first selected Id
string selectedIds = postedModel.SelectedDepartmentIds;
//Correct - returns correct selected Ids
string selectedIds1 = ModelState["SelectedDepartmentId"].Value.AttemptedValue;
...
...
Two questions:
How can I retrieve all selected items from DropDownList as part of model property "SelectedDepartmentId"? Do I need to use jQuery to update the ModalProperty at run-time?
Can I setup my View so as to bind Modal property "DepartmentModels" with DropDownList - It will help me to retrieve complete objects for selected items?
Currently, if I try to do that, I get this error:
{"The parameter conversion from type 'System.String' to type '...DepartmentModel' failed because no type converter can convert between these types."}
Thank you!
Resolved after looking through various Google searches :-)
Below is the code that loads and returns selected objects correctly -
Model:
public class UserGroupViewModel
{
public IEnumerable<SelectListItem> GroupSelectList
{
get
{
List<Group> groups = new List<Group>
{
new Group() {Id = 1, Name = "AA"},
new Group() {Id = 2, Name = "BB"},
new Group() {Id = 3, Name = "CC"}
};
IEnumerable<SelectListItem> groupsSelectList = groups.Select(group => new SelectListItem { Text = group.Name, Value = group.Id.ToString(), Selected = group.Id == 2}).ToList();
return groupsSelectList;
}
}
[Required]
[Display(Name = "Group")]
public int[] SelectedGroupIds { get; set; }
}
View:
<div class="form-group">
#Html.LabelFor(model => model.SelectedGroupIds, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SelectedGroupIds,
Model.GroupSelectList,
new { #class = "multiselect", multiple = "multiple" })
#Html.ValidationMessageFor(model => model.SelectedGroupIds)
</div>
</div>
For showing some of the items as 'Selected' on form load, simply set the SelectListItem's 'Selected' property to true.
HTH.