In my yahoo email the inbox is displayed as a list of email items. Clicking on the item displays its detail. Now, back to the inbox. One of the columns in the list is a checkbox. If I click one or more checkboxes and then click "delete" then all those items are deleted.
That's more or less what I'd like to achieve with my ASP.NET MVC application. I have a table with some rows in it and I can tick some checkboxes to delete the selected rows and update the database.
I am coming from an Web Forms background. If the delete button is clicked it will do a post back and I can inspect in my code behind what items need to be removed. I am doing this, however, in ASP.NET MVC and I do not have the benefit of postback or view state. I figure this could be achieved with AJAX but I'd like to have a simpler solution, like a simple form post. Unfortunately, I do not know where to start.
At this point I can delete the rows on the client side with JQuery but I don't have anything on the database part as yet. Any tips is highly appreciated.
Below is my view code:
#model IEnumerable<Simplex.Data.Models.MessageBoardModel>
#{
ViewBag.Title = "Message Board";
}
<script type="text/javascript">
function deleteItems() {
$('.td_checkbox:checked').closest('tr').closest(tr).remove();
}
$(document).ready(function () {
$('#btnDelete').click(function () {
deleteItems();
});
});
</script>
<div id="content">
<h2>Board List</h2>
#{ Html.RenderAction("search", "home"); }
<div class="board_list">
<table>
<tr>
<th>
No
</th>
<th>
Subject
</th>
<th>
Posted By
</th>
<th>
Posting Date
</th>
</tr>
#foreach (var item in Model) {
<tr id=#item.Id>
<td>
#Html.DisplayFor(modelItem => item.Id)
</td>
<td class="subject">
<input class="td_checkbox" type="checkbox" /> #item.Subject
</td>
<td>
#Html.DisplayFor(modelItem => item.Username)
</td>
<td>
#Html.DisplayFor(modelItem => item.DatePosted)
</td>
</tr>
}
</table>
<button id="btnDelete">Delete</button>
<input type="button" value="Post" />
</div>
First Issue, don't use the #foreach, that strips out the built-in collection handling. Use #Html.DisplayForModel() instead. This will correctly create the proper indexed item names and id's.
Then in your HttpPost handler, you will want to have the parameter be the collection, and you can walk the list and see which checkboxes are set.
Use a for loop to render the following for each message:
<input name="messages[#i.ToString()].Key" type="hidden" value="#item.Id" />
<input name="messages[#i.ToString()].Value" type="checkbox" value="true" />
Then capture the POSTed values in your action like this
[HttpPost]
public ActionResult Delete(Dictionary<int,bool> messages)
{
IEnumerable<int> idsOfItemsYouWantToDelete = messages.Where(pair => pair.Value).Select(pair => pair.Key);
// Do delete, return redirect or whatever
}
This works because Dictionary<int,bool> is a collection of KeyValuePair<int,bool>s and the .Key and .Value input fields will be matched with the .Key and .Value properties of KeyValuePair<TKey, TValue>.
You may want to read ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries
Related
I have an MVC Razor view that pulls change log information from a database (a table which only I have access to, limiting security concerns).
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Description)
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
</tr>
}
</table>
The description will contain values like New page available: http://localhost:0000/app/NewItem. What I'm trying to figure out is how to make that web address active.
I.e., turn New page available: http://localhost:0000/app/NewItem
into: New page available: http://localhost:0000/app/NewItem
and have the link properly rendered on the page. Is there a simple way to accomplish this, short of using regular expressions in the controller to pull that link out?
How can I create a column in a table in MVC4 to show an uneditable checkbox instead of the word true.
#foreach (var m in Model)
{
<tr>
<td>#m.UserLogin
</td>
<td>#m.UserEmployeeName
</td>
<td>#m.UserAccessRightsID
</td>
<td>#m.SystemManager #*CHECK BOX SHOULD BE HERE*#
</td>
Here is a screen shot of what I am currently getting.
<input type="checkbox" checked='#m.SystemManager' disabled="disabled" />
It uses the Razor V2 feature which removes the attribute if the value is null or false.
You can read more about it here
How to read from a text box value when using Html.ActionLink so that the value can be passed to the action?
I have the below code:
<table>
<tr>
<th>
Consumer Key:
</th>
<td>
#Html.TextBox("ConsumerKey")
</td>
</tr>
<tr>
<th>
Consumer Secret Key:
</th>
<td>#Html.TextBox("ConsumerSecretKey")
</td>
</tr>
<tr>
<th>
</th>
<td>#Html.ActionLink("Retreive Access Tokens", "/Retrieve"</td>
</tr>
</table>
Basically, I'd need to call the Controller Action and pass the text box values.
How would that be possible with MVC?
I know I can implement it using just an html button and an AJAX call to that Action but I hoped there would be another way using MVC controls.
By putting your code inside the Html.BeginForm("Retrieve", "Twitter") block, the html that is rendered to the browser will be enclosed inside a form-tag, something like:
<form method="POST" action="/Retrieve/Twitter">
<table>...</table>
</form>
Then when you click on the submit button the form, along with all the values in the text boxes will be posted to you MVC application. Then MVC does the work of mapping these form values (the text boxes created using #Html.TextBox("ConsumerSecretKey") and their values) to the parameters of your controller actions.
In your case, roughly the following will be rendered to the browser (the action link will need to be changed to an input of type "submit," as I have done below:
<form method="POST" action="/Retrieve/Twitter">
<table>
<tr>
<th>
Consumer Key:
</th>
<td>
<input id="ConsumerKey" name="ConsumerKey" type="text" value="" />
</td>
</tr>
<tr>
<th>
Consumer Secret Key:
</th>
<td>
<input id="ConsumerSecretKey" name="ConsumerSecretKey" type="text" value="" />
</td>
</tr>
<td><input type="submit" id="Retrieve" value="Retreive Access Tokens" /></td>
</tr>
</table>
</form>
When this is posted back to your Application the text you entered into the text boxes (rendered as tags) would map to the parameters of your action method matching their name:
public ActionResult Retrieve(string consumerKey, string consumerSecretKey)
{
//action method code here
}
The concept at work here is called model-binding. See Controllers and Action Methods in ASP.NET MVC Applications and scroll down to the "Action Method Parameters" section for an overview
I used, Html.BeginForm with a submit button, then oddly the textbox values are submitted to the server automatically:
#using (Html.BeginForm("Retrieve", "Twitter"))
{
<table>
<tr>
<th>
Consumer Key:
</th>
<td>
#Html.TextBox("ConsumerKey")
</td>
</tr>
<tr>
<th>
Consumer Secret Key:
</th>
<td>#Html.TextBox("ConsumerSecretKey")
</td>
</tr>
<tr>
<th>
</th>
<td>
<input type="submit" id="Retrieve" value="Retreive Access Tokens" />
</td>
</tr>
</table>
}
And in my Controller Action:
public ActionResult Retrieve(string consumerKey, string consumerSecretKey)
{
}
You can use FormCollection object.
[HTTPPost]
public ActionResult Retrieve(FormCollection collection)
{
string consumerKey=collection["ConsumerKey"];
string consumerSecretKey=collection["ConsumerSecretKey"];
}
Use form post method by using a submit button in your form.
In reality you cannot POST using Html.ActionLink. You can achieve that using Ajax.ActionLink and setting AjaxOptions properties. If using form is not an option for you, you can always implement jQuery function that intercepts a click generated by Html.ActionLink (based on an ID generated by this helper) and add a value from text box as a parameter. The problem here is that if you don't use Ajax you will submit the values using GET method and this is a big NO. GET should be used for retrieving values, and not for modifying the contents of a database or other backend data store. If you plan to use Ajax you could do something like this:
$(document).ready(function() {
$("myActionLinkId").click(function() {
var textBoxValue = $("#myTextBoxId").val();
$.post($(this).attr("href"), { id: textBoxValue }, function(result) {
alert("Result data: " + result);
});
});
});
I have a user control: VendorDDL.ascx, with the following code:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<List<MeetingCalendar.Models.Vendor>>" %>
<table>
<tr>
<th></th>
<th>
VendorId
</th>
<th>
VendorName
</th>
</tr>
<% foreach (var item in Model) { %>
<tr>
<td></td>
<td>
<%= Html.Encode(item.VendorId) %>
</td>
<td>
<%= Html.Encode(item.VendorName) %>
</td>
</tr>
<% } %>
</table>
My view: Create.aspx, has the following code snippet:
<p>
<label for="VendorNameSearch">Vendor Name:</label>
<input type="text" name="VendorNameSearch" id="VendorNameSearch" style="width:100px" />
<input type="submit" value="search" />
</p>
<% Html.RenderPartial("VendorDDL", MeetingCalendar.Controllers.HomeController.VendorsToSelect); %>
And everything works fine when I load up the Create view. The VendorDDL control is populated with the default values that are found in the VendorsToSelect. My controller has a List<Vendor> VendorsToSelect, which is getting updated properly.
Here is the problem: when the user clicks the SEARCH button, this fires off code in the Controller: return PartialView("VendorDDL", VendorsToSelect); I can see that VendorsToSelect is getting populated correctly based upon the user search.
I can step through the code, line-by-line, and see that immediately after return PartialView("VendorDDL", VendorsToSelect);, the debugger goes directly to the VendorDDL.ascx, and I can see that the Model is properly populated with the new VendorsToSelect, and the item.VendorId and item.VendorName are showing the correct values. But when debugging is done, and the Create view is shown, the VendorDDL control is not showing the new data.
Any suggestions?
I think that the output of your controller is discarded because the view (Create) has the same Html.RenderPartial("VendorDDL", MeetingCalendar.Controllers.HomeController.VendorsToSelect) as during initial load.
If I understand your problem correctly (and admittedly, without looking at the controller I may not) - you need to pass the model dynamically. The simplest (but not the most efficient) way would be to have jquery call $.load("/Home/VendorDDL") that would populate with the whole model; and then on submit hijax the form and pass form data to the same controller action.
I'm trying to build a Editable GridView like control (Order column) with this code in the view:
<table>
<tr>
<th>
Name
</th>
<th>
Order
</th>
<th>
<img alt="Save order" src="<%= Url.Content("~/Content/minisave.png") %>" />
</th>
<th></th>
</tr>
<% foreach (var item in Model) { %>
<tr>
<td>
<%= Html.Encode(item.Name) %>
</td>
<td colspan="2">
<%= Html.TextBox("Order", item.Order, new { size = "3" }) %>
</td>
<td>
<%= Html.ActionLink("Edit", "Edit", new { id=item.id }) %> |
<%= Html.ActionLink("Details", "Details", new { id=item.id })%>
</td>
</tr>
<% } %>
</table>
The result table look like:
The questions are: How I receive this data in my controller? I need a form tag around the table? How I know which Order value belongs to which record?
A couple extra questions: If you see the code I add the size attribute to the input tab but when the browser renders it, the input is larger, how can I fix it?
Thanks for your help!
I've done this before. I did it by having the ID as part of the name, and a form around the entire table. That way the controller pulled all the data from all the rows and updated it all at once like a spreadsheet.
That works well for a unit of work, where you edit the page and save it, though of course you'd need to consider how to cope with your locking strategy, be it optimistic or pessimistic.
However, these days a better alternative might be to use ajax to submit specific values, somewhat like Google Spreadsheet, maybe?