I have a Model that gets sent to a view. This model has List elements that are used to populate listboxes. In this view, I post to a controller action passing in my model as a parameter. On postback, I can see primitive types, but, can't seem to access the list. Here's my code:
Model:
public class ReportInfoViewModel
{
public int report_id { get; set; } = 0;
public string report_name { get; set; } = "";
public string report_path { get; set; } = "";
public string plaza_param { get; set; } = "y";
public List<FacilityViewModel> facilitieslist { get; set; } = new List<FacilityViewModel>();
}
public class FacilityViewModel
{
public string facility_id { get; set; }
public string facility_name { get; set; }
}
View:
#model CSC.ViewModels.ReportInfoViewModel
#using (Html.BeginForm("ViewReport", "Reports", Model, FormMethod.Post, new { target = "_blank" }))
{
if (#Model.plaza_param.ToString().ToLower().Equals("y"))
{
#Html.DevExpress().ListBox(
l =>
{
l.Name = "lstPlazaParam";
l.Width = Unit.Pixel(300);
l.Height = Unit.Pixel(120);
l.Properties.SelectionMode = ListEditSelectionMode.CheckColumn;
l.Properties.EnableSelectAll = true;
l.Properties.TextField = "facility_name";
l.Properties.ValueField = "facility_id";
l.SelectedIndex = 0;
l.Properties.ValueType = typeof(string);
l.Properties.ValidationSettings.RequiredField.IsRequired = true;
l.Properties.ValidationSettings.RequiredField.ErrorText = "Please select a Plaza";
l.Properties.ValidationSettings.ErrorText = l.Properties.ValidationSettings.RequiredField.ErrorText;
l.Properties.ValidationSettings.ErrorTextPosition = ErrorTextPosition.Bottom;
l.Properties.ValidationSettings.Display = Display.Dynamic;
l.Properties.ValidationSettings.ErrorDisplayMode = ErrorDisplayMode.ImageWithText;
}).BindList(Model.facilitieslist).GetHtml();
ViewContext.Writer.WriteLine("<br />");
}
Controller:
[HttpPost]
[Authorize]
public ActionResult ViewReport(ReportInfoViewModel _model)
{
string _parameterList = "";
ReportViewerViewModel _rptObj = new ReportViewerViewModel();
if (_model.plaza_param.ToLower().Equals("y"))
{
string[] _selected = DevExpress.Web.Mvc.ListBoxExtension.GetSelectedValues<string>("lstPlazaParam");
string subParam = "plazaparam=";
subParam += String.Join(",", _selected);
_parameterList = string.Concat(_parameterList, "#", subParam);
_parameterList = string.Concat(_parameterList, "#usrplazaparam=", getSelectedPlazaDisplayValues(_model.facilitieslist, _selected));**//here, _model.facilitieslist is null**
}
return View("AfterView", _rptObj);
}
What I am trying to do is on post back, send the model back to the controller. All primitive types are sent back, except the list types. How do I send back a list model on post? Any help is appreciated.
I was able to create a hidden field in my view serializing the list and storing it in the hidden field.
#using (Html.BeginForm("ViewReport", "Reports", Model, FormMethod.Post, new { target = "_blank" }))
{
string facilitiesListJson = Newtonsoft.Json.JsonConvert.SerializeObject(#Model.facilitieslist);
#Html.Hidden("FacilitiesList", facilitiesListJson);
//other form objects
}
In my controller action, I deserialized the hidden field(Request.Form) and access the list.
string _jsonString = Request.Form["FacilitiesList"];
List<FacilityViewModel> _objList = JsonConvert.DeserializeObject<List<FacilityViewModel>>(_jsonString);
Related
I am trying to implement a search panel with several checkbox to filter a table data, but i have a problem. I cant retain value of input checked after submit.
How can I solve?
My model :
public class OrdineView
{
public int anno { get; set; }
public Int32 nrOrdine { get; set; }
public string centro { get; set; }
[DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:d}")]
public DateTime? data { get; set; }
public String codice { get; set; }
public String ragsoc { get; set; }
[DisplayFormat(DataFormatString = "{0:C}")]
public Nullable<double> importo;
}
I have a Search model:
public class OrdiniSearchModel
{
public int? anno {get;set;}
public String[] Distinzione {get;set;}
}
public class OrdiniBusinessLogic
{
private NORTHWNDEntities1 db;
public OrdiniBusinessLogic()
{
db = new NORTHWNDEntities1();
}
public IQueryable<OrdineView> GetOrdini(OrdiniSearchModel ordiniSearch)
{
var queryOrdineView = (from ordine in db.ORDINI
join cliente in db.CLIENTI on ordine.Codcli equals cliente.Codana
select new OrdineView
{
anno = ordine.Anno,
nrOrdine = ordine.Numord,
centro = ordine.Codcen,
data = ordine.Datord,
codice = ordine.Codcli,
ragsoc = cliente.Ragso1,
importo = ordine.Totord
}).ToList().AsQueryable();
var model = queryOrdineView;
if (ordiniSearch.anno != null)
{
model = model.Where(o => o.anno == ordiniSearch.anno);
}
if (ordiniSearch.Distinzione != null && ordiniSearch.distinzione.Count() > 0)
{
List<string> distinzioniSelezionate = new List<string>();
foreach (var item in ordiniSearch.Distinzione)
{
distinzioniSelezionate.Add(item);
}
model = model.Where(o => distinzioniSelezionate.Contains(o.distinzione));
}
return model;
}
}
My Controller:
public ActionResult Index(OrdiniSearchModel searchModel, int? pageNumber )
{
ViewBag.Anno = db.ORDINI.Select(o => new { o.Anno }).Distinct().OrderByDescending(o => o.Anno).Select(o => o.Anno);
var searchLogic = new OrdiniBusinessLogic();
var model = searchLogic.GetOrdini(searchModel);
return View(model.OrderBy(i => i.codice).ToPagedList(pageNumber ?? 1, 10));
}
In my view I have
<input name="Distinzione" type="checkbox" value="001">001
<input name="Distinzione" type="checkbox" value="002">002
...and so on
After submit I get data correctly but lose checked state.
UPDATE: Based on the comments, I updated the view and adde more code.
If you mean that the checkboxes don't stay checked after the page is refreshed. It's because you don't tell them which should be checked. There is one possible solution for you. Create a simple helper method right in the view where you need the checkboxes. This method just checks the array of values and if it finds the value there, it will render a checkbox with checked state.
View.cshtml
#model OrdinePagedList
#MyCheckbox("001")
#MyCheckbox("002")
#helper MyCheckbox(string value)
{
if (Model.Distinzione.Contains(value))
{
<input type="checkbox" name="Distinzione" value="#value" checked="checked"/>
}
else
{
<input type="checkbox" name="Distinzione" value="#value" />
}
#value
}
I suggest to create a new view model class:
public class OrdinePagedList
{
public IEnumerable<OrdiniView> Pages { get; set; }
public IEnumerable<string> Distinzione { get; set;
}
And update either your business logic so that it returns this new class
// from
public IQueryable<OrdineView> GetOrdini(OrdiniSearchModel ordiniSearch)
// to
public OrdinePagedList GetOrdini(OrdiniSearchModel ordiniSearch)
or update the controller:
public ActionResult Index(OrdiniSearchModel searchModel, int? pageNumber )
{
ViewBag.Anno = db.ORDINI.Select(o => new { o.Anno }).Distinct().OrderByDescending(o => o.Anno).Select(o => o.Anno);
var searchLogic = new OrdiniBusinessLogic();
var pages = searchLogic.GetOrdini(searchModel);
OrdinePagedList model = new OrdiniPagedList {
Pages = pages.OrderBy(i => i.codice).ToPagedList(pageNumber ?? 1, 10),
Distinzione = searchModel.Distinzione
}
return View(model);
}
or if you don't want (or can't) create the new view model (but I strongly recommend to do so). You can use ViewBag to pass the additinal collection of checked values:
public ActionResult Index(OrdiniSearchModel searchModel, int? pageNumber)
{
ViewBag.Distinzione = searchModel.Distinzione;
// original code
}
and then you'll just have to update the helper method. For the sake of simplicity I don't check if the ViewBag.Distinzione exists. But you should.
#helper MyCheckbox(string value)
{
if (ViewBag.Distinzione.Contains(value))
{
<input type="checkbox" name="Distinzione" value="#value" checked="checked"/>
}
else
{
<input type="checkbox" name="Distinzione" value="#value" />
}
#value
}
In short. You need to make sure that the data (collection of checked values), you get in controller, are being sent back to the view.
List<string> distinzioniSelezionate = new List<string>();
if (searchModel.distinzione != null && searchModel.distinzione.Count() > 0)
{
foreach (var item in searchModel.distinzione)
{
distinzioniSelezionate.Add(item);
}
}
OrdinePagedList model = new OrdinePagedList
{
Pages = pages.OrderBy(i => i.Codice).ToPagedList(pageNumber ?? 1, 10),
Distinzione = distinzioniSelezionate
};
I had to modify the ActionResult because Distinzione is not empty
Here are my model classes:
public class SensorTest
{
public int SerialNo { get; set; }
public string SensorName { get; set; }
public string TestName { get; set; }
public List<string> ImpactSide { get; set; }
}
public class SensorTestsViewModel
{
public List<SensorTest> SensorTestList { get; set; }
}
Controller action methods:
GET:
[HttpGet]
public ActionResult SensorTests()
{
SensorTestsViewModel obj = new SensorTestsViewModel();
obj.SensorTestList = new List<SensorTest>();
SensorTest sensortest;
sensortest = new SensorTest();
sensortest.SerialNo = 1;
sensortest.SensorName = "FLAT 13 KMH";
sensortest.TestName = "";
obj.SensorTestList.Add(sensortest);
sensortest = new SensorTest();
sensortest.SerialNo = 1;
sensortest.SensorName = "CURB IMPACT 40KMH";
sensortest.TestName = "";
obj.SensorTestList.Add(sensortest);
return View(obj);
}
POST:
[HttpPost]
[ActionName("SensorTests")]
public ActionResult SensorTests_Post(SensorTestsViewModel sensortests)
{
//SensorTestsViewModel model = new SensorTestsViewModel();
//UpdateModel(model);
return View(sensortests);
}
View code:
#model Safety.Models.SensorTestsViewModel
#using (Html.BeginForm("SensorTests", "Safety"))
{
var grid = new WebGrid(Model.SensorTestList, canSort: false, canPage: false);
int rowNum = 0;
<div>
#grid.GetHtml(columns:
grid.Columns
(
grid.Column("SerialNo", format: item => rowNum = rowNum + 1),
grid.Column("SensorName"),
grid.Column("TestName", format: (item) => Html.TextBox("TestName[" + (rowNum - 1).ToString() + "].TestName", (object)item.TestName))
), mode: WebGridPagerModes.Numeric)
</div>
<input type="submit" value="Submit" />
}
See the Viewmodel is null during POST. I have tried UpdateModel as well. My requirement is I need to post whole viewmodel data to controller and do the necessary actions from there. Not sure what I am missing? Can someone Please suggest?
First, take a look at this example: post items of webgrid asp.net mvc3
Try making the textbox name like this: "SensorTestList[someIndexHere].SensorName"
I have two dropdown lists and two textboxes
Search By: ByHtml.DropDownList("Search1", "Please Select...")
Html.TextBox("searchString1")
Search By: Html.DropDownList("Search2", "Please Select...")
#Html.TextBox("searchString2")
<input type="submit" value="Filter" />
When I make my selection from whichever DDL and type text into the textbox and hit filter my search returns, however after the search the text remains in the textbox, is there a way of clearing it after the search so that the textbox is empty again? I tried
ModelState.Remove("");
but it didn't work.
A sample from My controller code is
public class MainController : Controller
{
private DBEntities db = new DBEntities();
// GET: /Main/
public ActionResult Index(string searchString1, string searchString2, string Search1, string Search2)
{
//Create a Dropdown list
var SearchOptionList = new List<string>();
SearchOptionList.Add("LandLord");
SearchOptionList.Add("Postcode");
SearchOptionList.Add("Street Address");
ViewBag.Search1 = new SelectList(SearchOptionList);
ViewBag.Search2 = new SelectList(SearchOptionList);
var mylist = from m in "mydatabase" select m;
//This statement runs if the user selects a parameter from Search2 and leaves Search1 empty
if (String.IsNullOrEmpty(Search1) && !String.IsNullOrEmpty(Search2))
{
if (Search2 == "Postcode")
{
mylist = mylist.Where(s => s.Postcode.Contains(searchString2));
}
if (Search2 == "LandLord")
{
mylist = mylist.Where(s => s.Name.Contains(searchString2));
}
if (Search2 == "Street Address")
{
mylist = mylist.Where(s => s.StreetAddress.Contains(searchString2));
}
}
return View(mylist.ToList());
}
Your should have a view model containing properties searchString1 and searchString2 and the select lists
public class SearchVM
{
public string searchString1 { get; set; }
public string searchString2 { get; set; }
public SelectList SearchList1 { get; set; }
public SelectList SearchList2 { get; set; }
}
Controller
public ActionResult Search()
{
SearchVM model = new SearchVM();
model.SearchList1 = new SelctList(...);
model.SearchList2 = new SelctList(...);
return View(model);
}
View
#model SearchVM
#using(Html.BeginForm())
{
....
#Html.DropDownListFor(m => m.searchString1, Model.SearchList1, "--Please select--")
#Html.DropDownListFor(m => m.searchString2, Model.SearchList2, "--Please select--")
....
}
Post
[HttpPost]
public ActionResult Search(SearchVM model)
{
// to clear all modelstate and reset values
ModelState.Clear();
model.searchString1 = null;
model.searchString2 = null;
// or to clear just one property and reset it
ModelState.Remove("searchString1");
model.searchString1 = null;
// repopulate select lists if your returning the view
return View(model);
}
At the end of my public ActionResult Index method but before return View() I placed the following code which worked perfectly
ModelState.Remove("searchString1");
ModelState.Remove("searchString2");
ModelState.Remove("Search1");
ModelState.Remove("Search2");
I know is an old question, but I fall in the same issue. So I put my solution.
View:
#Html.TextBox("Search", null, new { #autofocus = "autofocus" })
Controller:
ViewBag.Search= null;
ModelState.Remove("Search");
return View(list.ToList());
Hope to help someone
I am developing MVC application.
I am trying to pass the data from one method to another method in same controller.
But data doesn't pass properly...
Please check below code... I am trying to pass the Product list from Create to Save data method.
namespace StockWatchScreen.Controllers
{
public class OrderController : Controller
{
public class OrderProduct
{
public string SectionCode { get; set; }
public double Size { get; set; }
public double Thickness { get; set; }
public double Length { get; set; }
public double Quantity { get; set; }
}
public ActionResult Create()
{
List<OrderProduct> oProductList = new List<OrderProduct>();
OrderProduct oProduct = new OrderProduct();
oProduct.SectionCode = "123";
oProduct.Length = "123";
oProduct.Size = "123";
oProduct.Thickness = "123";
oProduct.Quantity = "123";
oProductList.Add(oProduct);
}
return RedirectToAction("SaveData", oProductList);
}
public ActionResult SaveData(List<OrderProduct> oProductList)
{
ViewBag.ProductList = oProductList;
ViewBag.OrderNo = "12321#";
return View();
}
}
}
}
In SaveData method, oProductList list shows always null.
What is reason ?
You need to return :return SaveData( oProductList); .You don't need to return RedirectToAction , and try to avoid using TempData["oProduct"] using TempData in mvc is not good practice.
Using AjaxBeginForm you on succes you can get result return SaveData( oProductList);and put it where you want .also you can use UpdateTargetId.
You can't send model like this in RedirectToAction, you should use tempdata for this communicating between actions like this
public ActionResult Create()
{
List<OrderProduct> oProductList = new List<OrderProduct>();
OrderProduct oProduct = new OrderProduct();
oProduct.SectionCode = "123";
oProduct.Length = "123";
oProduct.Size = "123";
oProduct.Thickness = "123";
oProduct.Quantity = "123";
oProductList.Add(oProduct);
}
TempData["oProduct"] = oProductList;
return RedirectToAction("SaveData");
}
And in the recieving controller
public ActionResult SaveData(List<OrderProduct> oProductList)
{
ViewBag.ProductList = TempData["oProduct"] as List<OrderProduct> ;
ViewBag.OrderNo = "12321#";
return View();
}
This is because RedirectToAction is doing a 301 redirection, and it is actually the client initiating a Get request to the /SaveData action.
I'm using jqGrid to display some data on a page. Within the controller action, we're using an anonymous object to represent the data that the jqGrid needs. My question is, is there a way we can create a strongly typed object to represent the jqGrid data that we are sending with Json()?
Main reason for this is so that we can do unit testing with the objects that are being sent to it.
Thanks!
EDIT:
[AcceptVerbs(HttpVerbs.Post)]
public JsonResult GridData(FormCollection form, string alias, string location, string state)
{
int pageSize = Convert.ToInt32(form["rows"]);
int pageIndex = Convert.ToInt32(form["page"]) - 1;
var deviceList = this._device.GetList(CreateFilter(location,alias,state),this._securityCache.GetSecurityContext(),pageSize,pageIndex);
int totalResults = deviceList.TotalRecords;
int totalPages = (int)Math.Ceiling((float)totalResults / (float)pageSize);
var jsonData = new {
total = totalPages,
page = pageIndex + 1,
records = totalResults,
rows = (from device in deviceList.Data
select new {i = device.Alias,cell = new string[]{device.Alias,device.Location,device.RatePlan,device.State,device.DateCreated.ToString()}}).ToArray()
};
return Json(jsonData);
This above here works, but we can't unit test the data that is being passed into the Json() method.
var newJsonData = new JsonJQGridReturnData();
newJsonData.total = totalPages;
newJsonData.page = pageIndex + 1;
newJsonData.records = totalResults;
List<JsonJQGridRow> list = new List<JsonJQGridRow>();
foreach (var device in deviceList.Data)
{
list.Add(new JsonJQGridRow(device.Alias, new string[] { device.Alias, device.Location, device.RatePlan, device.State, device.DateCreated.ToString() }));
}
newJsonData.rows = list.ToArray();
_cookieHelper.SaveCookie("DeviceListIndex", this._securityCache.GetSecurityContext().UserID.ToString(), COOKIE_PAGE_SIZE_KEY, pageSize.ToString());
return Json(newJsonData);
}
Here is my poor attempt at trying to wrap these into strongly typed objects. Unfortunately, running this gives me a "u is undefined" in the jqGrid file. I suspect that this is because the json being passed in is not correctly formatted. Here are the classes....
[DataContract]
public class JsonJQGridReturnData
{
[DataMember]
public int total { get; set; }
[DataMember]
public int page { get; set; }
[DataMember]
public int records { get; set; }
[DataMember]
public JsonJQGridRow[] rows { get; set; }
}
[DataContract]
public class JsonJQGridRow
{
public JsonJQGridRow(string i, string[] columns)
{
this.i = i;
this.cells = columns;
}
[DataMember]
public string i { get; set; }
[DataMember]
public string[] cells { get; set; }
}
If I understand your question you can use Generics to do this:
Model:
// represents one row in the JQGrid
class Customer
{
public string firstname { get; set; }
public string lastname { get; set; }
}
JQGrid class:
class JQGridData<TModel>
{
// add in whatever other properties you want for JQGrid
public int responseTime {get; set; };
public List<TModel> rows = new List<TModel>();
}
Controller Action :
public JsonResult GridData(int page)
{
var gridData = new JQGridData<Customer>();
// Populate your data here, this is just an example:
gridData.rows.Add(new Customer()
{
firstname = "fred", lastname = "pharkas"
});
// return the result
return Json(gridData, JsonRequestBehavior.AllowGet);
}
Result:
{
responseTime: 0
rows: [
{
firstname: "fred"
lastname: "pharkas"
}
]
}
Is that what you were asking?
David,
Here's the kinda thing i use in an app i'm working on at the moment for this type of thing. I know it doesn't provide a strongly typed object as such, but the 'list' could be a part of the model that is then sent ToArray() at the end of the piece.
public JsonResult GridData(int id)
{
// get our messages based on id
var bookingmessagesList = _repository.Find(x => x.ID == id);
var list = new ArrayList();
foreach (var bookingmessage in bookingmessagesList) //populate data containers with read data
{
list.Add(new
{
bookingmessage.ClassRowVersionDate,
bookingmessage.ID,
bookingmessage.BookingID,
bookingmessage.AssignedFrom,
bookingmessage.AssignedTo,
bookingmessage.AssignedDate,
bookingmessage.CompletedDate,
bookingmessage.MessageType,
bookingmessage.Notes
});
}
int totalOjectCount = list.Count;
return Json(new { dataitems = list.ToArray(), totalItems = totalOjectCount });
}
hope it gives you some ideas.. Will be interested to see the suggestions made.
Here's a quick take on a strongly-typed JQGridResult.
public class JQGridResult<T> : JsonResult where T : class
{
public T Model
{
get { return (T)this.Data; }
set { this.Data = value; }
}
}
Used as...
return new JQGridResult<JsonModel> {
Model = new GridModel { ... initialize model here ... }
});
where GridModel is basically a container class holding the strongly typed properties for the grid.
I feel really silly. I had a misspelling in the GridRow that was causing jqGrid to blow up. After I fixed that, I was able to get the jqGrid to work with my strongly typed object...
Now in my unit tests, I can just do...
var result = controllerToTest.GridData(form, null, null, null) as JsonResult;
var data = result.Data as JsonJQGridReturnData;
and now I can access the fields :D