My application needs to do an HTTP post of a table with checkboxes like in the image above. On the controller side I will need to traverse the table and perform certain operations for each row that was checked.
The things that I need to do are:
Identify whether a row is checked
Get the cell values of a checked row
I have a good understanding on how this will be done in Razor in as far as posting the form is concerned. But I am clueless once I am in my controller's action method.
Please help. Thanks.
From what you've show, it appears that all you really need in your action method is a collection of ids to identify which "rows" to modify. I'd use a series of checkboxes with values set to the id of the row they represent. Presumably you have some sort of persistence mechanism in which these rows can be looked up or have them cached server side.
[HttpPost]
public ActionResult Update( List<int> rowIDs ) // where your checkboxes are named rowIDs
{
var messages = DB.Messages.Where( m => rowIDs.Contains( m.ID ) );
foreach (var message in messages)
{
// process the update
}
DB.SaveChanges();
return RedirectToAction( "index" ); // display the updated list
}
Note that it's more likely that you have a model with the collection of ids as well as some other data representing what "update" to perform. Posting collections can be tricky; you might need to play with the name of the input and/or with hidden indexes if you're not getting all the data posted back as expected.
Related
All. more or less new to MVC so not sure how to handle the issue.
I have data model generated from a database table(approximately 100 columns). The application form is broken up into 6-7 views. The first view creates a new record and inserts it into the database. The rest of the views suppose to gather information from the form and update the created record.
[HttpPost]
public ActionResult GeneralInfo(ADP.Models.ADPRegistration _registration)
{
try
{
ADP.Models.IS_WEBEntities _test = new IS_WEBEntities();
_test.ADPRegistrations.Attach(_registration);
_test.ObjectStateManager.ChangeObjectState(_registration, System.Data.EntityState.Modified);
_test.SaveChanges();
return View("ReferralMethod",_registration);
}
catch(Exception er)
{
return View();
}
}
This is the general code that updates my table, it is similar across all of the views. The reason for passing the model back to the view is to preserve the ID across the views.
The problem that I have is that, my entity _registration contains all of the table fields, so when the view is posted only the fields in the views get updated, the previous columns are getting NULLs, since they don't exist in the view my guess. I can't seem to enumerate through the database first model as well.
You are correct in that when MVC reconstitutes your model in a POSTback, any fields that are not in the form will be NULL in your model.
Your choices are to include the field(s) as hidden in your view:
#Html.HiddenFor(model => model.SomeValue)
Or update the model after post, but prior to passing it to your validation & repository layers:
ModelState.SetModelValue("Name", new ValueProviderResult("Some string",string.Empty,new CultureInfo("en-US")));
I have a usercontrol that is rendering a list of items. Each row contains a unique id in a hidden field, a text and a delete button. When clicking on the delete button I use jquery ajax to call the controller method DeleteCA (seen below). DeleteCA returns a new list of items that replaces the old list.
[HttpPost]
public PartialViewResult DeleteCA(CAsViewModel CAs, Guid CAIdToDelete)
{
int indexToRemove = CAs.CAList.IndexOf(CAs.CAList.Single(m => m.Id == CAIdToDelete));
CAs.CAList.RemoveAt(indexToRemove);
return PartialView("EditorTemplates/CAs", CAs);
}
I have checked that DeleteCA is really removing the correct item. The modified list of CAs passed to PartialView no longer contains the deleted item.
Something weird happens when the partial view is rendered. The number of items in the list is reduced but it is always the last element that is removed from the list. The rendered items does not correspond to the items in the list/model sent to PartialView.
In the usercontrol file (ascx) I'm using both Model.CAList and lambda expression m => m.CAList.
How is it possible for the usercontrol to render stuff that is not in the model sent to PartialView?
Thanx
Andreas
It sounds like the ModelState is the trouble here, as you bind to CAs the ModelState save this values in the background as Attempted Values, so its true the object is no longer present at the Model, but the ModelSate still have the values of the deleted object. You can try a:
ModelState.Clear();
To remove all those old values.
Check in firebug what the response realy is. This way you can see if you have a serverside problem or it is a jquery issue.
I am new to ASP.NET MVC, particularly ajax operations. I have a form with a jquery dialog for adding items to a drop-down list. This posts to the controller action.
If nothing (ie void method) is returned from the Controller Action the page returns having updated the database, but obviously there no chnage to the form. What would be the best practice in updating the drop down list with the added id/value and selecting the item.
I think my options are:
1) Construct and return the html manually that makes up the new <select> tag
[this would be easy enough and work, but seems like I am missing something]
2) Use some kind of "helper" to construct the new html
[This seems to make sense]
3) Only return the id/value and add this to the list and select the item
[This seems like an overkill considering the item needs to be placed in the correct order etc]
4) Use some kind of Partial View
[Does this mean creating additional forms within ascx controls? not sure how this would effect submitting the main form its on? Also unless this is reusable by passing in parameters(not sure how thats done) maybe 2 is the option?]
UPDATE:
Having looked around a bit, it seems that generating html withing the controller is not a good idea. I have seen other posts that render partialviews to strings which I guess is what I need and separates concerns (since the html bits are in the ascx). Any comments on whether that is good practice.
look at the ContentResult you can specify the mime type of what you return (text/html)
You could alternatively make a control that take a IEnumerable of whatever you put in the selectlist, and build it using the view engine. That way you keep the formatting of the html (in this case a list of options) into a view, and not in your code.
<%# Control Language="C#"Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Article>>"%>
<%foreach (var article in Model){%>
<option><%:article.Title %></option>
<%} %>
I think I would go for that second one
From what I understood, the jQuery dialog contains a form that, when submitted, will post to an action which updates the database with some information. You want to get the newly added database information and update the same form that was used to trigger the database update.
If that is the case, then I think the best clean and logical option is to return JSON serialization of the items to be put in the drop down right after you update the database. Then, using jQuery, you would clear the drop down and append option tags into it.
You can also write a new, seperate action that returns the JSON serialization of the database objects you need. You would have jQuery call another post to this action as a callback to your first ajax post (the one used to update the database).
Here is a quick snippet
public ActionResult UpdateDatabase(string something)
{
/// update the database
IEnumerable<Items> items = getItemsFromDatabase(); // or w/e
var vals = items.Select(x=> new { value = x.ID, text = x.Name }); // something similar
return Json(vals);
}
Personally, I would write a separate function that returns JSON. This ensure separation of concerns, and gives me a function I can use in many different places.
Returning a JsonResult with all the items is the most versatile and least-bandwidth intensive solution as long as you are happy to iterate through the list in jQuery and update your drop-down list.
Using a partial view is nice for HTML that you can .load(...) directly into your select, but less versatile.
I would go with the JsonResult.
In your Controller:
public JsonResult UpdateItem(string sItem)
{
// 1. Insert new item into database if not exist...
// {update code here}
// 2. retrieve items from database:
IEnumerable<Item> Items = GetItems();
// 3. return enumerable list in JSON format:
return new JsonResult{ Data = new {Items = Items, Result = "OK" }};
}
On client-side:
Iterate through Items array and add the items to your list.
I have a bunch of text inputs on my page (HTML.TEXTBOX, generated through for loop), and I want to read their values and commit to database only when user has modified something in those textboxes.
What would be a proper way to do that? (Do you think it may make more sense to commit the entire thing to database if number of textboxes is less than 100?)
Also, in general, how would I read values from a bunch on textboxes and commit to the database? I would need something that uses a key-value pair, where key would be the id and value would be that input in the textbox.
Unless you use for example JavaScript and hidden fields to keep track of user changes, there is no way for you to know which fields have been modified without querying the database, since the web in general, and ASP.NET MVC in particular, is stateless. However, if you loop out the fields with their values filled in with data stored in an object, you can probably save that object in a session variable to compare against on the next request.
Pseudo-example:
public ActionResult GetFormView()
{
var values = (select relevant information from db and store in a
IQueryable<Dictionary<string, string>> or something similar
where you have a relation between input field id/name and value);
Session["TheInputListValues"] = values;
return View(values); // Your view renders your list of input fields
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveChanges(FormCollection form)
{
var oldValues = (Dictionary<string, string>)Session["TheInputListValues"];
var changedValues = new Dictionary<string, string>();
foreach(string key in form.AllKeys)
{
if(oldValues.ContainsKey(key))
{
if (oldValues[key] != form[key])
{
changedValues(key, form[key]);
}
}
}
SaveToDB(changedValues);
return Redirect("SomeWhereElse"); // PRG is king!
}
I haven't tested this implementation, but it's worth a try =)
I have done something similar using jQuery and it works pretty well. Attach a behavior to the textboxes where if the data changes then submit it's value to an action that saves the data.
$(function(){
$("input[type='text']").change(function(){
$.post("/SaveChanges",{id: $(this).attr("id"),value : $(this).attr("text")});
});
});
This would be assuming you had ID's that were some sort of unique key to you record on each input.
<input id="4576" name="4576"/>
you could also have a callback that would say add a class to this field letting them know that the information was saved by changing it to green or something.
Check this out for more details:
http://docs.jquery.com/Ajax/jQuery.post
I've got a nice MVC app running now, and I'm adding some AJax functionality. I have a table which displays 10 items, only certain users can see certain items. When the user adds a new post I've set-up the ajax to save the new entry.
However I then need to update the table, I cant find out from JQuery what status the user is (And hence what they can see) so I cant just insert a new row (As some users cant see that row). If this was web-forms I would likly have a page that dumps the table and then i would use JQuery to load the contents of that trimed down 'page' into the relevent slot on the current page.
Whats the best way to achieve this with MVC?
Thanks
As #Robert Koritnik suggests, the best way to handle this is using a PartialView. I would suggest having two separate controller actions -- one that handles the original request and another that handles the AJAX new entry. Both actions would call the same logic to get the data for the table. The former would put the data into the view model along with other page data. The latter would package the data into a model for the partial view.
Model classes
public class PageViewModel
{
....
public IEnumerable<TableViewModel> TableData { get; set; }
}
public class TableViewModel
{
...
}
Controller Code
[AcceptVerbs( HttpVerbs.Get )]
public ActionResult Index()
{
var model = new PageViewModel();
model.TableData = GetTableForUser( this.User );
return View( model );
}
[AcceptVerbs( HttpVerbs.Post )]
public ActionResult AddEntry( ... )
{
... add the new entry ...
var model = GetTableForUser( this.User );
return PartialView( "TableView", model );
}
private TableViewModel GetTableForUser( IIdentity user )
{
...
}
View Code
Main View
<% Html.RenderPartial( "TableView", model.TableData ); %>
<script type="text/javascript">
$('#entryForm').submit( function() {
$.post( '<%= Url.Action( "addentry", "controller" ) %>',
$('#entryForm').serialize(),
function(data) {
$('#table').replaceWith( data );
},
'html' );
return false;
});
</script>
TableView
<table id="table">
<% foreach (var row in Model) { %>
<tr>
...
</tr>
<% } %>
</table>
Use PartialView functionality that will return just the <table> you need. In your main page it will be included but in your Ajax call it will only emit HTML back to the client that you can use to replace existing <table> element.
If I understand you correctly, you're saying that user A is viewing a list of entries and user B (In some other part of the world. maybe) posts a new entry. You want the list on user A's screen to update, but only if the new entry is one that user A is allowed to see?
If this is the case, you can have a timer running on the page and, when the timer triggers, it causes an AJAX call to the server, asking if there are any new entries for the user. The identity of the user and - therefore - which items they can see, should be determined from the session (Exactly how this works depends on your particular architecture, but I'd guess that you're already doing this, to display the list of items for user A to start with)
There are all sorts of fine details to consider here...
How often should the timer trigger, in order to get updates in a timely manner, but without causing too much traffic to the server
Should you simply update the entire list (This makes the code simple) or should you only download new items (This makes the logic more complicated, but also keeps the traffic smaller)
How do you ensure that you correctly identify the user, and correctly filter the entries to show only the relevant ones.
It's a relatively simple scenario - and ones that's no too uncommon - but it needs to be approached in a sensible manner to prevent complication setting in.
It's not hard to add a cookie which will store the current status of the user, or you can simply add another Ajax call to find out whether the user is authorized or no. you simply create some items in your controller to handle all the situations: whether user is authorized or no, what you show/hide from them.
what exactly do you need thou?