MVC IPagedList with model type error - asp.net-mvc-4

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

Related

How to pass all text of input selected row into action?

i have this view in my project.
I want to get the text of input in each row that is selected.
How to pass all text of input selected row into action
<table width="100%" class="table table-striped table-bordered table-hover" id="dataTables-example">
<thead>
<tr>
<th width="45%">Select</th>
<th width="45%">User Name</th>
<th width="5%">Description</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.TypeList)
{
<tr>
<td>
<input type="checkbox" name=checklist" id="checklist"/>
</td>
<td>
#Html.DisplayFor(modelItem => item.UserName)
</td>
<td>
<input type="text" name="Extradecription"/>
</td>
</tr>
}
</tbody>
my Actions. How can I have the corresponding values of text and checkbox for the Selected rows
public IActionResult Index()
{
return View(repository.GetUser());
}
public IActionResult Save(int[] checklist,string[] Extradecription)
{
repository.Save(checklist,Extradecription);
return View(repository.GetUser());
}
If you try to get two different arrays as you have showed in you controller-action code, there will be a trouble with text for non selected items, the array for check boxes will bind as expected but for descriptions will be different, just to be clear, check the following example:
Assuming We have a list with tree options:
100 - Foo
200 - Bar
300 - Zaz
If We set the following selection for items:
Foo, a
Zaz, c
If We take a look on the request, this is the raw request:
checklist = 100,300
Extradecription = a,null,c
So, the trouble is avoid to bind null descriptions for non selected options, this is complicated, in that case I recommend to you a clear solution:
Create a model to create entity process
Create a model for option
Add a list of option model in create entity model
Initialize the model to create a new entity
Render inputs in view using asp-for tag
Retrieve the request to create a new entity
I'll assume the name of models and properties to show how to bind a typed array in your request, change the names according to your scenario.
Create entity model:
public class CreateEntity
{
public CreateEntity()
{
Items = new List<SelectedItem>();
}
// Step 3
[BindProperty]
public List<SelectedItem> Items { get; set; }
// Another properties
}
Model for option:
public class SelectedItem
{
public bool IsSelected { get; set; }
public int Code { get; set; }
public string Name { get; set; }
public string Desc { get; set; }
}
Rendering the options list:
#for (var i = 0; i < Model.Items.Count; i++)
{
<input asp-for="#Model.Items[i].IsSelected" />#Model.Items[i].Name
<input asp-for="#Model.Items[i].Desc" />
<br/>
}
The GET and POST actions in controller:
[HttpGet]
public IActionResult CreateOption()
{
// Set the items list
var model = new CreateEntity
{
Items = new List<SelectedItem>
{
new SelectedItem{ Code = 100, Name = "Foo" },
new SelectedItem{ Code = 200, Name = "Bar" },
new SelectedItem{ Code = 300, Name = "Zaz" }
}
};
return View(model);
}
[HttpPost]
public IActionResult CreateOption(CreateEntity form)
{
// Retrieve only selected items
var query = form.Items.Where(item => item.IsSelected == true).ToList();
return View();
}
If you want to know more about check boxes in Razor pages, please check this link: Checkboxes in a Razor Pages Form
Please let me know if this answer is useful.

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)

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.

Binding JSON Data Back to the MVC View to dynamically insert data to a table

I am working on an MVC4 application. In the submit action of the button, i am making a call to a controller action, which will return data back to me as Json. Number of rows in the table is dependent on the number of rows returned by the service.
I have created a new View Model to support this.
public class DataResponse
{
public List<ALSResult> Result { get; set; }
public string ResponseText {get;set;}
}
public class ALSResult
{
public string Name {get;set;}
public string DataResult {get;set;}
}
Controller Action
[HttpPost]
public ActionResult Submit(CViewModel calcModel)
{
try
{
DataResponse response = cRepository.GetDetails(calcModel.SelectedPlan,calcModel.EquipmentPrice,calcModel.DownPayment);
return Json(response, JsonRequestBehavior.DenyGet);
}
}
js file
$("#Submit").click(function () {
other code here
Process("/DPPC/Submit", "POST", JSON.stringify(model), "json", "application/json;charset=utf-8", logError, InvokeSuccess);
}
function InvokeSuccess(result) {
i will get json result in result filed
}
index.cshtml
<table id="tblResults">
<tr>
<td id="tdResultEt"></td>
<td id="tdResultEtPrice"></td>
</tr>
<tr>
<td id="tdResultDt"></td>
<td id="tdResultDtPrice"></td>
</tr>
more rows depending on the number of items in the JSON response
</table>
How do i dynamically bind the response from the Service to create rows for the table and bind the results?
I don't test it, and it maybe contain syntax errors
function InvokeSuccess(result) {
var table = $("#tblResults");
for(var i = 0; i < result.Result.lenght; ++i)
{
var item = result.Result[i];
var newTr = $("<tr>");
var newTd1 = $("<td>");
var newTd2 = $("<td>");
newTd1.text(item.Name);
newTd2.text(item.DataResult);
newTr.append(newTd1);
newTr.append(newTd2);
table.append(newTr);
}
}

Why won't a List of complex types bound to TextBoxes in a table show changes to the model in MVC 4?

I have run into an issue that seems pretty simple, but I have not been able to find a solution. I have created a ReportModel object that is the model in the view. The ReportModel contains a list of FinancialHistory objects. I populate the objects and display them in a table of textboxes within a form in the view using default binding (This works correctly). The user can then submit the form to refresh the FinancialHistory objects from a different datasource, replacing what was previously in the list with the new results. When the new results are returned, I can see that the model contains the expected new values, but when the HTML is rendered, the original amounts still appear. If the new results contains more objects than the original list (as shown in the example code), the added rows do appear with the correct values. So, if the original had 2 objects and the refreshed list has 3, the resulting HTML shows the first 2 rows with the old values and a 3rd row with the new values.
Here are the models:
public class ReportModel
{
public string AccountNumber { get; set; }
public IList<FinancialHistory> FinancialHistories { get; set; }
}
public class FinancialHistory
{
public FinancialHistory()
{
Id = Guid.Empty;
}
public Guid Id { get; set; }
public DateTime TransactionDate { get; set; }
public decimal TotalAmount { get; set; }
}
In the Home/Index view, I use HTML.TextBoxFor() to bind the properties of each FianancialHistory object in the list to textboxes in a table. Here is the Index view:
#model SimpleExample.Models.ReportModel
<form id="FormSave" method="post" name="FormSave" action="/Home/Refresh">
#Html.LabelFor(model => model.AccountNumber) #Html.TextBoxFor(model => model.AccountNumber)
<table class="table" style="width: 95%">
<tr>
<td >Date</td>
<td >Amount</td>
</tr>
#{
if (Model.FinancialHistories != null)
{
for (int index = 0; index <= Model.FinancialHistories.Count - 1; index++)
{
<tr>
<td>#Html.TextBoxFor(model => model.FinancialHistories [index].TransactionDate, "{0:MM/dd/yyyy}", new { #readonly = "true" })</td>
<td>#Html.TextBoxFor(model => model.FinancialHistories[index].TotalAmount, "{0:#,#.00}", new { #readonly = "true" })</td>
<td>#Html.HiddenFor(model => model.FinancialHistories[index].Id)</td>
</tr>
}
}
}
</table>
<input type="submit" id="submit" value="Refresh" class="submit" />
</form>
For this example, my action methods in the controller are very simple. Initially, the Index method populates the list with 2 FinancialHistory Objects. The Refresh method replaces the original 2 objects with 3 new objects, with different amounts.
public class HomeController : Controller
{
public ActionResult Index()
{
ReportModel reportModel = new ReportModel();
reportModel.AccountNumber = "123456789";
IList<FinancialHistory> financialHistories = new List<FinancialHistory>();
financialHistories.Add(new FinancialHistory
{
Id = Guid.NewGuid(),
TransactionDate = DateTime.Parse("3/1/2010"),
TotalAmount = 1000.00M
});
financialHistories.Add(new FinancialHistory
{
Id = Guid.NewGuid(),
TransactionDate = DateTime.Parse("4/1/2011"),
TotalAmount = 2000.00M
});
reportModel.FinancialHistories = financialHistories;
return View(reportModel);
}
public ActionResult Refresh(ReportModel reportModel)
{
FinancialHistoryRepository financialHistoryRepository = new FinancialHistoryRepository();
IList<FinancialHistory> financialHistories = new List<FinancialHistory>();
financialHistories.Add(new FinancialHistory
{
Id = Guid.Empty,
TransactionDate = DateTime.Parse("3/1/2010"),
TotalAmount = 1111.11M
});
financialHistories.Add(new FinancialHistory
{
Id = Guid.Empty,
TransactionDate = DateTime.Parse("4/1/2011"),
TotalAmount = 2222.22M
});
financialHistories.Add(new FinancialHistory
{
Id = Guid.Empty,
TransactionDate = DateTime.Parse("5/1/2012"),
TotalAmount = 3333.33M
});
reportModel.FinancialHistories = financialHistories;
return View("Index",reportModel);
}
}
That's how HTML helpers work and is by design. When rendering they are first looking in the ModelState for values and after that in the model. You are modifying the values of your model in the POST controller action, but the ModelState values still contain the old values which will be used. If you want to modify values of your model in a POST action you should remove the original values from the ModelState if you intend to redisplay the same view:
public ActionResult Refresh(ReportModel reportModel)
{
// clear the original posted values so that they don't get picked up
// by the helpers
ModelState.Clear();
FinancialHistoryRepository financialHistoryRepository = new FinancialHistoryRepository();
...
return View("Index",reportModel);
}