Refreshing MVC PartialView with new Model on DropDownList Change - c#

I have a budgeting application, I have 3 models I am pulling into 1 view.
Budget - get the users budgeting information details (i.e, name of budget, date, etc.)
BillBudgetTotal - Allows the user to add a cumulative total for that budget (i.d., budgetid, total amount)
BudgetTotalBreakdown - Allows the user to break their budget down into futher details (i.e., break the total amount down by bill name (water, gas, electric, misc, etc.)
The UI will give the user the option to select a budget (via dropdown) they want to work in and then allow them to enter in their dollar amounts based on which bill they selected.
Problem: I am trying to figure out a way to allow the partial view (the area under the dropdown) to refresh based on the dropdown selection. I can't seem to get the partial to refresh with the updated model (it needs to be reset based on the value of the dropdownlist selection). I have exhausted multiple options on stack overflow.
Something like this:
Model:
public class MyBudgets : Financials
{
public Budgets Budget{ get; set; }
public BillBudgetTotal BudgetTotals { get; set; }
public BillBudgetTotalBreakdown BudgetTotalBreakdown { get; set; }
}
Html:
<div class="col-md-3"></div>
<div class="row col-md-6">
#Html.DropDownListFor(model => model.Budget.SelectedBills, Model.Budget.SelectedBills.Select(b => new SelectListItem() { Value = b.Bill_Id.ToString(), Text = b.Bill}), "Select A Bill...", new { #class = "form-control"})
</div>
<div class="col-md-3"></div>
<br /><br />
<hr />
<div id="billBudgetPartial">
#Html.Partial("Budgeting/_BillTotalAmount", Model);
</div>
Controller:
[HttpGet]
public ActionResult Budgets(int budgetId)
{
MyBudgets model = new MyBudgets
{
Budgets = _executionRepository.RetrieveBudgets(budgetId)
};
model.Budget.SelectedBills = _executionRepository.SetSelectedBudgets(budgetId);
return View(model);
}
[HttpPost]
public ActionResult Budgets()
{
return Json(new { success = "false" });
}
public ActionResult BillTotalAmount(int id)
{
var model = new MyBudgets
{
Budgets = _executionRepository.RetrieveBudgetsByBillBudget(id),
BillBudgetTotal = _executionRepository.RetrieveBillBudgetByBillId(id),
BillBudgetTotalBreakdown = _executionRepository.RetrieveBillBudgetTotalBreakdown (id)
};
return PartialView("Execution/_BillTotalAmount", model);
}

You can use ajax to do partial update to your page. when razor render your page, it will generate a SELECT element with the id "Budget_SelectedBills". So listen to the change event on this dropdown, get the selected value and send that to your server(an action method) and let it return the partial view for the markup you want below. You may use jQuery load method to update the DOM with the new markup coming from server.
#section Scripts
{
<script>
$(function(){
$("#Budget_SelectedBills").change(function(e){
var val=$(this).val();
$("#billBudgetPartial").load("/Budgeting/BillDetails/"+val);
});
});
</script>
}
Assuming you have BillDetails action method in BudgetingController which accpets the billId an return the partial view for the bottom portion of screen.
public ActionResult BillDetails(int id)
{
var model = ReplaceYourModelForBillTotalAmountViewHere();
return PartialView("Budgeting/_BillTotalAmount", model);
}
EDIT: As per the comment
How can I pass 2 parameters in this? like not just the id from the
drop but something else the list the #Model.BudgetId
If your javascript code is in the same razor view, you can simply use Model.BudgetId as the second querystring param value.
Assuming BudgetId is an int type
#secion Scripts
{
<script>
$(function(){
$("#Budget_SelectedBills").change(function(e){
var val=$(this).val();
$("#billBudgetPartial").load("/Budgeting/BillDetails/"+val
+"?budgetId="+#Model.BudgetId);
});
});
</script>
}
Now make sure that your action method has this second parameter
public ActionResult BillDetails(int id,int budgetId)
{
var model = ReplaceYourModelForBillTotalAmountViewHere();
return PartialView("Budgeting/_BillTotalAmount", model);
}
If your javascript code is in an external js file, you may keep Model.BudgetId to somewhere in the DOM and read that. Either a hidden field or keep it in html 5 data attributes of the select element.

Related

Get Query Parameter from URL into MVC View

I have an a href link to a page which adds a parameter to the link for example:
tsw/register-your-interest?Course=979
What I am trying to do is to extract the value in Course i.e 979 and display it in the view. When attempting with the below code, I only return with 0 rather than the course value expected. ideally I'd like to avoid using routes.
Here is the view:
<div class="contact" data-component="components/checkout">
#using (Html.BeginUmbracoForm<CourseEnquiryPageSurfaceController>("PostCourseEnquiryForm", FormMethod.Post, new { id = "checkout__form" }))
{
//#Html.ValidationSummary(false)
#Model.Course;
}
And my controller:
public ActionResult CourseEnquiry(string Course)
{
var model = Mapper.Map<CourseEnquiryVM>(CurrentContent);
model.Course = Request.QueryString["Course"];
return model
}
This is the View Model:
public class CourseEnquiryVM : PageContentVM
{
public List<OfficeLocation> OfficeLocations { get; set; }
public string Test { get; set; }
public string Course { get; set; }
public List<Source> SourceTypes { get; set; }
}
SOLUTION:
After some research and comments I've adjusted the code to the below which now retrieves the value as expected
#Html.HiddenFor(m => m.Course, new { Value = #HttpContext.Current.Request.QueryString["Course"]});
Thanks all
Based on the form code you provided you need to use #Html.HiddenFor(m => m.Course) instead of just #Model.Course. #Model.Course just displays the value as text instead of building a input element that will be sent back to your controller.
If your problem is with a link prior to the view you referenced above, here's what I'd expect to work:
View with link:
#model CourseEnquiryVM
#Html.ActionLink("MyLink","CourseEnquiry","CourseController", new {course = #Model.Course}, null)
CourseController:
public ActionResult CourseEnquiry(string course)
{
// course should have a value at this point
}
In your view, you are only displaying the value of Course.. which isn't able to be submitted. You need to incorporate the value of course with a form input element (textbox, checkbox, textarea, hidden, etc.).
I would highly suggest using EditorFor or Textboxfor, but because your controller action is expecting just a string parameter you could just use Editor or TextBox.
#using (Html.BeginUmbracoForm<CourseEnquiryPageSurfaceController>("PostCourseEnquiryForm", FormMethod.Post, new { id = "checkout__form" }))
{
//#Html.ValidationSummary(false)
#Html.TextBox(Model.Course, null, new { #class = "form-control"});
<input type="submit" value="Submit" />
}
Then you should just be able to do this in your controller:
public ActionResult CourseEnquiry(string course) // parameter variables are camel-case
{
var model = Mapper.Map<CourseEnquiryVM>(CurrentContent);
if(!string.IsNullOrWhiteSpace(course))
model.Course = course;
return model;
}
Let me know if this helps.

Remember search params

I'm new in mvc and I try to create a simple page with table and ajax search.
For example, I have a search model, which pass parameters from form to controller.
Model:
public class OrderSearchViewModel
{
[Display(ResourceType = typeof(Lang), Name = "OrderID")]
public int? OrderID { get; set; }
[Display(ResourceType = typeof(Lang), Name = "DeliveryType")]
public int? DeliveryTypeID { get; set; }
[Display(ResourceType = typeof(Lang), Name = "Partner")]
public string CustomerName { get; set; }
public SelectList DeliveryTypes { get; set; }
}
In controller I have an action witch return View with form:
public ActionResult Index()
{
var ordersSearchModel = // default init;
return View(model);
}
In my Index.cshtml I have a form
#model Models.Order.OrderSearchViewModel
<div class="row">
#using (Ajax.BeginForm("Orders", "Order", new AjaxOptions {UpdateTargetId = "ordersList"}, new {#id = "searchForm", #class = "form-horizontal"}))
{
// Editors templates for each params
}
</div>
<div id="ordersList" class="row">
</div>
}
In my Controller I have a method, witch take search model and return a partial view
[HttpPost]
public async Task<ActionResult> Orders(OrderSearchViewModel model, int page = 1, int pageSize = 50)
{
var models = // connect to db and get data filtered by model params
return PartilaView("_View", models);
}
In result partial I have a table with order num and link to edit view.
In edit view I have a link back to search:
#Html.ActionLink("Back", "Index", "Order", new { #class = "btn btn-default" })
And by click this link I get the Index view in default (without search parameters) and user must fill it once again.
What will be the best practice to remember user search parameters?
Thanks for any advice.
As devqon said, the preferred approach is to use query parameters, but it does sound like your usage might make this a bit difficult to manage
TempData/SessionData may solve your issue, but using this approach will cause problems if the user decides to use your application in multiple tabs/windows (they will all share the same search params)
Something that might be worth looking into is SessionStorage.(Link below)
This type of storage persists as long as the browser stays open
And importantly
Opening a page in a new tab or window will cause a new session to be initiated
So your pages shouldn't share state.
More details here:
https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage

How to pass view data to typed controller object?

I'm moving from WPF development to Asp MVC and have started doing an Asp MVC app. So far I've set up my:
model
controller
and
view(with the relevant fields.)
The next step involves sending the data entered in my form to the controller on the Submit button click.
I know in WPF I can bind the control properties to a property in the viewmodel, also there would be a click event on the button which I don't see in MVC.
This is my pseudo understanding of how to do that in MVC but correct me if I' wrong (Model is of type Case):
1.Set button click event to send form data to controller.
2.Pass data into controller constructor and assign to typed Case object.
Question:
How can you pass view values on button submit to a typed object in a controller?
Code:
View -
<form action="" method="post">
<div class="form-horizontal">
<div class="col-lg-6">
<!-- SELECT STATUS STATIC-->
<div class="form-group">
<label class="col-md-3 control-label" for="Current Status">Status</label>
<div class="col-md-8">
<select id="Status" name="Status" onchange="" class=" form-control">
<option value="Down">Down</option>
<option value="Up">Up</option>
</select>
</div>
</div>
<!-- SELECT APP STATIC-->
<div class="form-group">
<label class="col-md-3 control-label" for="App">App</label>
<div class="col-md-8" >
<select id="App" name="App" onchange="" class=" form-control">
<option value="SAP">SAP</option>
<option value="JAP">JAP</option>
</select>
</div>
</div>
<asp:Button id="b1" Text="Submit" runat="server" />
</div>
</div>
</form> <!--
Controller -
public class CaseController : Controller
{
public ActionResult Index()
{
return View();
}
}
Model -
Public class Case
{
public string Status { get; set; }
public string App { get; set; }
}
I hope that I understand your scenario well? You have a form with two drop down lists and a submit button? When you click the submit button you want to extract the selected values? This is how I understand it and this is how I will try to explain my answer with examples.
I would suggest that you bind your view/page to a view model. A view model is a kind of model that will represent your data in the view, whether it be textboxes, drop down lists, textareas, radio buttons, checkboxes, etc. It can also display static text on your view. I wrote a detailed answer as to what a view model is, if you have the time please go and read it:
What is ViewModel in MVC?
Go and create your view model. It will contain two lists that will represent your two drop down lists. Each list has an id associated with it that will contain the value of the selected drop down list item:
public class CaseViewModel
{
public int StatusId { get; set; }
public List<Status> Statuses { get; set; }
public int AppId { get; set; }
public List<App> Apps { get; set; }
}
Your domain models, namely Status and App, for the above mentioned lists:
public class Status
{
public int Id { get; set; }
public string Name { get; set; }
}
public class App
{
public int Id { get; set; }
public string Name { get; set; }
}
Now that you have this setup your next step is to populate these lists in your controller's action method. Ideally you would populate it with values from a database, but in your case I guess it is ok to hard code these values:
public ActionResult Index()
{
CaseViewModel model = new CaseViewModel();
model.Statuses = new List<Status>();
model.Statuses.Add(new Status { Id = 1, Name = "Down" });
model.Statuses.Add(new Status { Id = 2, Name = "Up" });
model.Apps = new List<App>();
model.Apps.Add(new App { Id = 1, Name = "SAP" });
model.Apps.Add(new App { Id = 2, Name = "JAP" });
return View(model);
}
As soon as you have populated your two lists, you pass the view model directly to the view. The view will receive a strongly type model and will do with it what it needs to do with it. In your case, a form will be created with two drop down lists and a submit button. I have left out all your CSS for clarity (just go and add it):
#model WebApplication_Test.Models.CaseViewModel
#using (Html.BeginForm())
{
<div>
#Html.DropDownListFor(
m => m.StatusId,
new SelectList(Model.Statuses, "Id", "Name", Model.StatusId),
"-- Select --"
)
#Html.ValidationMessageFor(m => m.StatusId)
</div>
<div>
#Html.DropDownListFor(
m => m.AppId,
new SelectList(Model.Apps, "Id", "Name", Model.AppId),
"-- Select --"
)
#Html.ValidationMessageFor(m => m.AppId)
</div>
<div>
<button type="submit">Submit</button>
</div>
}
So now you have two drop down lists populated with data. Select a value in each and press the submit button. Your view is bound to a view model and will retain values on form submission. Values in lists are not kept on form submission and will need to be populated again:
[HttpPost]
public ActionResult Index(CaseViewModel model)
{
// Check form validation
if (!ModelState.IsValid)
{
// If validation fails, rebind the lists and send the current view model back
model.Statuses = new List<Status>();
model.Statuses.Add(new Status { Id = 1, Name = "Down" });
model.Statuses.Add(new Status { Id = 2, Name = "Up" });
model.Apps = new List<App>();
model.Apps.Add(new App { Id = 1, Name = "SAP" });
model.Apps.Add(new App { Id = 2, Name = "JAP" });
return View(model);
}
// Form validation succeeds, do whatever you need to do here
return RedirectToAction("Index");
}
I hope this helps.
In the view just add a button in the form like
<button id="b1" Text="Submit"/>
In the controller add an action method to handle the post.
public class CaseController : Controller
{
[HttpPost]
public ActionResult Index(Case case)
{
//Do Something
return View();
}
public ActionResult Index()
{
return View();
}
}
You may also want to look into using Razor and strongly typed views. Makes things much simpler.
another approach is to use mvc ajax call, by doing these you also can pass parameter to controller from simple parameter to a selected row in gridview.
On the view in the button control add onclick property that point to a javascript function and passing parameter. In these sample will get selected row on the gridview
<input id="GenerateData" type="button" value="GenerateData" onclick="generateData(App.grdNameOfGridview.getRowsValues({selectedOnly:true}) [0]);" />
On the view create a javascript function that use ajax to call the controller, note the paramater that can be passing from click button event to the javascript function that will use ajax to call the controller. In this sample i use extjs framework, if you want you can also use jquery as well
generateData= function (recordData) {
var jsonStringContractUnit = JSON.stringify(recordData);
Ext.Ajax.request({
url: '../ControllerName/GenerateData',
method: 'POST',
params: {
SelectedContractUnit: jsonStringContractUnit
},
On the controller the parameter will be pass from view and will be store on SelectedData
public ActionResult GenerateData(string SelectedData)
{
}

MVC Pagination in both the main and partial view

My app shows two tabulated set of data: the main table with the primary data and a sub-table with related records in a rendered partial view.
For the main table, I have implemented a simple paging functionality. I use PageInfo class to store information on actual page, maximum page, number of all pages etc. All this is returned to View in a ViewModel. I also use hidden control and POST form method to send an altered page back to a Controller.
First I store the current page in a hidden control and then use jQuery to alter the page (+1, -1, frist, l;ast) and send such updated value of a control to the Controller. I struggled to send the page info to the Controller so added a hidden form field and retrieve its value in Action using ModelBinder.
The problem is that I render partial View which is also tabulated data. I would like to apply independent inner page navigation in this subtable. However, I don't know how to use second form if it's possible. It looks like POST method is not the best option.
How can I send separated page information to a partial view. Then how to control whether user clicked inner version of next, previous buttons etc. How can I send this info to controller of the Partial View?
EDIT.
In edit, I have added
A copy of class representing pagination information
Controller with specific actions.
View
This is the way I have done it. The first time Index() is requested, I set default values for SortingPagingFilteringInfo (currently it holds only info on pagination). Everything is put into ViewModel and sent to View. I use Ajax to replace html in <div id="listOfRecordings"></div> with code generated by a partial view and also to navigate around pages. As can be seen, I also use a Form Control in this little code
#using (Html.BeginForm())
{
#Html.Hidden("page", Model.SPFInfo.CurrentPage)
}
to return updated page info. I replace its values in JavaScript code below. At the moment it's just a page number. I find it difficult to apply this technique to added pagination to the partial view which also shows tabulated data. They are related to main table by foreign key. It's 1 to many relationship. I tried to add extra Form with another Form Control to PartialView but then I'd have to have two Forms. I don't know how to POST to two different actions / controllers. I haven't played with multi forms in one View. Perhaps there's a better way to solve this.
Pagination model:
public class SortingPagingFilteringInfo
{
public int CurrentPage { get; set; }
public int MaxPage { get; set; }
public int PageSize { get; set; }
public int PageCount { get; set; }
}
public class StudentViewModelWithFeatures
{
public IEnumerable<StudentViewModel> Students { get; set; }
public SortingPagingFilteringInfo SPFInfo { get; set; }
}
Controller and GET and POST Index() actions:
#region Index
[HttpGet]
public ActionResult Index()
{
StudentViewModelWithFeatures ViewModel =
new StudentViewModelWithFeatures();
ViewModel.SPFInfo = new SortingPagingFilteringInfo();
using (MyDBContext dbContext = new MyDBContext())
{
ViewModel.Students = getViewModel(dbContext).OrderBy(x => x.patient);
ViewModel.SPFInfo.CurrentPage = 1;
ViewModel.SPFInfo.MaxPage =
Convert
.ToInt32(Math.Ceiling((double)getViewModel(dbContext)
.Count() / ViewModel.SPFInfo.PageSize));
int skipRecords =
(ViewModel.SPFInfo.CurrentPage - 1) * ViewModel.SPFInfo.PageSize;
ViewModel.Students = ViewModel.Students
.Skip(skipRecords)
.Take(ViewModel.SPFInfo.PageSize)
.ToList();
}
return View(ViewModel);
}
[HttpPost, ActionName("Index")]
public ActionResult IndexPost(int? page)
{
StudentViewModelWithFeatures ViewModel = new StudentViewModelWithFeatures();
ViewModel.SPFInfo = new SortingPagingFilteringInfo();
using (MyDBContext dbContext = new MyDBContext())
{
ViewModel.Students = getViewModel(dbContext).OrderBy(x => x.patient);
// paging
ViewModel.SPFInfo.MaxPage =
Convert
.ToInt32(Math.Ceiling((double)getViewModel(dbContext)
.Count() / GlobalPageSize.Value));
page = page ?? 1;
page = page < 1 ? 1 : page;
page = page > ViewModel.SPFInfo.MaxPage ? ViewModel.SPFInfo.MaxPage : page;
ViewModel.SPFInfo.CurrentPage = page.Value;
int skipRecords =
(ViewModel.SPFInfo.CurrentPage - 1) * ViewModel.SPFInfo.PageSize;
ViewModel.Students = ViewModel.Students
.Skip(skipRecords)
.Take(ViewModel.SPFInfo.PageSize)
.ToList();
}
return View(ViewModel);
}
#endregion
View with JavaScript, div for a PartialView:
#model Program.ViewModels.StudentViewModelWithFeatures
#{
ViewBag.Title = "Students";
}
#using (Html.BeginForm())
{
#Html.Hidden("page", Model.SPFInfo.CurrentPage)
}
<div>
<!-- ... -->
<div class="navigation-block">
<span class="navigation-link" data-id="first"><<< First </span>   
<span class="navigation-link" data-id="previous">< Previous</span>  
#Model.SPFInfo.CurrentPage / #Model.SPFInfo.MaxPage
  <span class="navigation-link" data-id="next">Next ></span>   
<span class="navigation-link" data-id="last">Last >>></span>
</div>
</div>
<div id="listOfRecordings"></div> <!-- Partial view is placed here -->
<script>
// for better readability I put this java code below!
</script>
JavaScript code in the View
$('.navigation-link').click(function (evt) {
var id = $(this).data('id');
var url = '#Url.Action("Index", "Students")';
var MaxPage = "#Model.SPFInfo.MaxPage";
var CurPage = "#Model.SPFInfo.CurrentPage";
if (id == 'first') {
$('#page').val(1);
}
if (id == 'last') {
$('#page').val(parseInt(MaxPage));
}
if (id == 'next') {
$('#page').val(parseInt(CurPage) + 1);
}
if (id == 'previous') {
$('#page').val(parseInt(CurPage) - 1);
}
$('form').submit();
});
$('.show-list').click(function () {
$('.show-list').click(function () {
var id = $(this).data('id');
url = '#Url.Action("List", "Recordings")';
$('#listOfRecordings').html("Retrieveing data ...");
$.get(url, { StudentID: id }, function (data) {
$('#listOfRecordings').html(data);
});
});
});

Add a new row to my view dynamically

Ok, so I have this class:
public class BackstoreInventoryUtility
{
public BackstoreInventoryInfo Item { get; set; }
public List<ItemListingUtility> ListItemUtility { get; set; }
public BackstoreInventoryUtility()
{
Item = new BackstoreInventoryInfo();
ListItemUtility = new List<ItemListingUtility>();
}
}
And here's the ListItemUtility class:
public class ItemListingUtility
{
public int Quantity { get; set; }
public string Duration { get; set; }
public List<string> AvailableDurations { get; set; }
public ItemListingUtility()
{
AvailableDurations = new List<string>();
}
}
In a view I am building, I am displaying 1 BackstoreInventoryUtility based on a BackstoreInventoryInfo item my user is currently browsing.
The ListItemUtility is a class allowing the user to proceed to certain action, like display for a set time a set quantity.
The view renders like this:
#model MyApp.Utilities.BackstoreInventoryUtility
#using (Html.BeginForm())
{
<div>
#if (Model.Item.Quantity > 0)
{
<input type="submit" value="Display"/>
}
#Html.HiddenFor(_item => _item.Item.BackstoreInventoryID)
<div class="bigFontSize bold formStyle">
<label class="center">Options will eventually be displayed here.</label>
<div>
<div class="float-left">Quantity Allocated:</div>
<div class="float-right">#Html.DisplayFor(_item => _item.Item.Quantity)
#Html.HiddenFor(_item => _item.Item.Quantity)
</div>
<div class="clear"></div>
</div>
<div class="formStyle" id="itemUtilityZone">
<label>Options</label>
#for (int i = 0; i < Model.ListItemUtility.Count; i++)
{
<div>
<div class="float-left">
Quantity To Display:
</div>
<div class="float-right">
#Html.TextBoxFor(_item => _item.ListItemUtility[i].Quantity, new { #class = "positive-integer numberTextBox" })
</div>
<div class="clear"></div>
</div>
}
</div>
#if (Model.Item.Quantity > 0)
{
<input type="submit" value="Display"/>
}
</div>
}
I'd like my user to dynamically add a new row to the view, and then when the view is submitted, all the rows would be included.
So far I am at the beginning and I am trying this:
[HttpGet]
public ActionResult AddItemUtilityRow()
{
return PartialView(new ItemListingUtility());
}
Where the partial view rendered would be identical to the div used in the table. But I am not sure how could I make this happen, should I use a jQuery call? How might I do this?
EDIT Okay, so I have tried something in jquery which VISUALLY does what I want:
<script type="text/javascript">
$(document).ready(function() {
$("#addUtility").click(function() {
$.get("#Url.Action("AddItemUtilityRow")", {
}, function(data) {
$('#itemUtilityZone').append(data);
});
});
});
</script>
So, as I said, this works but only partially because when the user submits only the default number of items in the list is submitted. How can I make it so that each time the user add a row it adds up to the model and gets later submitted?
Woah! It was more complex than I thought, but thanks to this link : http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/ I was able to make the whole thing work!
I first transfered every row created in a partial view like this:
<div class="formStyle" id="itemUtilityZone">
<label>Options</label>
#foreach (var utilityRow in Model.ListItemUtility)
{
Html.RenderPartial("ItemUtilityRow", utilityRow);
}
</div>
Which renders like this:
#using HtmlHelpers.BeginCollectionItem
#model MyApp.Utilities.ItemListingUtility
#using (Html.BeginCollectionItem("listItems"))
{
<div>
<div class="float-left">
Quantity To Display:
</div>
<div class="float-right">
#Html.TextBoxFor(_item => _item.Quantity, new { #class = "positive-integer numberTextBox" })
</div>
<div class="clear"></div>
</div>
}
Note: for the Html.BeginCollectionItem Html Helper, I had to search a bit for Steven Sanderson's Helper which he mentions in the upper link. You can find it here:
https://github.com/danludwig/BeginCollectionItem
Next, my javascript call looks like this:
$(document).ready(function() {
$("#addUtility").click(function () {
$.ajax({
url: '#Url.Action("AddItemUtilityRow")',
cache: false,
success: function(html) {
$('#ItemUtilityZone').append(html);
}
});
});
});
And the controller method that adds a new row:
[HttpGet]
public ActionResult AddEbayUtilityRow()
{
return PartialView("ItemUtilityRow", new ItemListingUtility());
}
And the rows shows just fine now. The catch is, how do I catch it back in my post method? Well, following Steve Sanderson's blog, I understood that the listItems variable was actually the name of the collection which would be sent back to the post method.
So by adding this parameter to the controller post method:
IEnumerable<EBayListingUtility> listItems
The list is indeed sent back to the post method with the count being what it is supposed to be. Hurray!
We approach this in one of two ways:
1.) Client-side approach - you can use jquery/knockout whatever to append items to your table. This is fine for simple additions, but negates the use of c# in the view.
2.) Server-side approach (and usually used) - Basically, post your viewmodel back to an action that manually adds a list item;
[HttpGet]
public ActionResult AddItemUtilityRow()
{
return PartialView(new ItemListingUtility());
}
[HttpPost]
public ActionResult AddItemUtilityRow(BackstoreInventoryUtility viewModel)
{
viewModel.ListItemUtility.Add(new ItemListingUtility());
return PartialView(viewModel);
}
We have a number of ways using jquery of 'posting' to a different action (the one that simply adds an item). I would consider using jquery's ajax call to accomplish this.
But the premise is the same:
send the data from your page to the server
manipulate the data
reuse the view you created

Categories

Resources