JQuery Datepicker for multiple .NET MVC Input Fields not working - asp.net-mvc

I have simplified my work for this question but the same problem remains. I am using the Textbox HTML helper to display empty textboxes as I loop through the items in this model.
<% foreach (var item in Model) { %>
<tr>
<td><%: item.ID %></td>
<td><%: Html.TextBox("usernames", null, new { #class = "datepicker" }) %></td>
<td><%: item.Password %></td>
<td> <%: item.Race %></td>
</tr>
<% } %>
Because I have several rows this produces several fields all with the class "datepicker". I am applying the following JQuery for the datepicker:
$(document).ready(function () {
$('input').filter('.datepicker').datepicker({
dateFormat: "dd/mm/yy",
onSelect: function (value, date) {
alert(this.value);
}
});
});
When the page renders, every textbox creates a calendar as expected but it always puts the date into the textbox on line one. I need the date to go into the textbox the calendar appeared next to. The html for the code above looks fine:
<tr>
<td>6</td>
<td><input class="datepicker" id="usernames" name="usernames" type="text" value="" /></td>
<td>dinosaur</td>
<td> 1</td>
</tr>
Interstingly, if I simply create 4 of class "datepicker" everything is fine. Its the way the html helpers create the for you.
Please Help!

The answer is to give the textboxes being generated unique id's like below otherwise it will not work.
<% foreach (var item in Model) { %>
<tr>
<td><%: item.ID %></td>
<td><%: Html.TextBox("usernames", null, new { ID=item.ID #class = "datepicker" }) %></td>
<td><%: item.Password %></td>
<td> <%: item.Race %></td>
</tr>
<% } %>

Related

How to update different targets with MVC Ajax helper?

i'm having a hard time dealing with MVC Ajax helper and trying to refresh certain part of the page. In my code, I have a situation like this:
<div id="ajaxLoadedContent">
<table>
<tr>
<th>
<%: Html.Label("ProductId") %>
</th>
<th>
<%: Html.Label("ProductName") %>
</th>
<th>
</th>
</tr>
<% foreach (var product in Model.Products)
{
%>
<tr>
<td>
<%: direccion.ProductId %>
</td>
<td>
<%: direccion.ProductName %>
</td>
<td>
<% using (Ajax.BeginForm("EditProduct", "MyController",
new { ContainerDiv = "ShowEditProducts" },
new AjaxOptions() { UpdateTargetId = "ShowEditProducts", OnSuccess = "updatePlaceholder" }))
{%>
<%: Html.Hidden("ProductId", product.ProductId)%>
<input type="submit" value="Edit" />
<%} %>
</td>
</tr>
<% } %>
</table>
<script type="text/javascript">
function updatePlaceholder(context) {
var html = context.get_data();
var placeholder = context.get_updateTarget();
$(placeholder).html(html);
return false;
}
</script>
<div id="ShowEditProducts"></div>
</div>
Now, when I press the Edit button, then the 'Editor View' appears, but the problem is that when i Submit that form, then there are two options:
The data is OK, the changes are made, the form dissapears and the list is refreshed.
The data is NOT OK, the forms stays and the validation messages appear.
The problem is that the UpdateTargetId are different for each option.
Option 1 refreshes "ShowEditProducts", while Option 2 refreshes "ajaxLoadedContent". Also, ehe 'Edit View' contains JavaScript that is executed when the view is loaded using the "Edit" button but is not executed when the form contains errors and is re-rendered.
The code of the EditView looks like this:
<% using (Ajax.BeginForm("SubmitEdit", new AjaxOptions() { UpdateTargetId = Model.ContainerDiv}))
{%>
<script type="text/javascript">
// My JavaScript
</script>
<table>
<tr>
<td>
<%: Html.Label("Id")%></br>
<%: Html.TextBoxFor(x => x.Product.ProductId)%></br>
</td>
<td>
<%: Html.Label("Name")%></br>
<%: Html.TextBoxFor(x => x.Product.ProductName)%><
</td>
</tr>
</table>
<input type="submit" value="Save" />
<%: Ajax.ActionLink("Cancel", "EmptyView","Shared", new AjaxOptions() { UpdateTargetId = Model.ContainerDiv})%>
<% } %>
So, now my two big problems are:
1. The JavaScript of the 'Edit View' don't get executed when the the view is re-renderd.
2. How can i update one target is there are errors and another one when there are not.
Thanks
The object being replaced is being set on this line:
var placeholder = context.get_updateTarget();
So instead, you should add a condition here. Eg, instead of returning HTML directly, if you return an object that looks like this:
public class Result
{
public bool Success { get; set; }
public string Html { get; set; }
}
Then you could do something like this:
var result = response.get_response().get_object();
if (result.Success)
$("#ShowEditProducts").html(html);
else
$("#ajaxLoadedContent").html(html);
Alternatively, instead of returning a Success boolean, you could have a property for the ID of the control to replace. This would be more reusable, and might make sense if you want the decision of which control to replace to be done server-side.

ASP.Net MVC returning values from List of Checkboxes

I have a model with a property that is a List. MyObjects simply has an id, a description and a selected boolean property.
I have managed to display the items as checkboxes on my view. I did this via:
<%foreach (var cat in Model.DefaultCategories)
{%>
<tr>
<td>
<%=cat.Category %>
</td>
<td>
<%=Html.CheckBoxFor(x=>cat.Selected) %>
</td>
</tr>
<%
}%>
</table>
However, there is a problem. They all end up, when rendered, with the same names. Here's a portion of my list:
<tr>
<td>
Medical
</td>
<td>
<input id="cat_Selected" name="cat.Selected" type="checkbox" value="true" /><input name="cat.Selected" type="hidden" value="false" />
</td>
</tr>
<tr>
<td>
Salary
</td>
<td>
<input checked="checked" id="cat_Selected" name="cat.Selected" type="checkbox" value="true" /><input name="cat.Selected" type="hidden" value="false" />
</td>
</tr>
They have all been named "cat.Selected".
How can I resolve this?
And then, when I submit, I need to iterate through them. With different names, I assume I can get them in my HttpPost method:
[HttpPost]
public ActionResult Modify(int id, FormCollection formValues)
{
PayeeDto p = new PayeeDto { Name = Request.Form["name"], PayeeId = id };
Services.PayeeServices.Save(p);
return RedirectToAction("Index");
}
The FormCollection will have the different names? At the moment, it just has the single 'cat.selected' item.
There is a way you can submit collections to your action by using names with []. As described here http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
<% for (int i = 0; i < Model.DefaultCategories.Count; i++) { %>
<td>
<input type="checkbox" name="[<%= i %>].Selected" <% Model.DefaultCategories[i].Selected ? "checked=\"checked\"" : string.Empty %>/>
</td>
<% }%>
Then your action can take a collection of models like so
public ActionResult Modify(int id, ICollection<UpdateModel> updates)
{}
I would recommend you using Editor Templates and stop writing loops in your views. They will take care of generating the proper names so that binding works. Example:
In your main view:
<table>
<thead>
<tr>
<th>Name</th>
<th>Selected</th>
</tr>
</thead>
<tbody>
<%: Html.EditorFor(x => x.DefaultCategories) %>
</tbody>
</table>
and then inside an editor template strongly typed to a Category (~/Views/Home/EditorTemplates/Category.ascx). Also if you want to get the corresponding Name back in your controller action you need to include it (probably as hidden field). Another technique involves adding only the id and then fetching back the relevant information from the database in your controller action:
<%# Control
Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<AppName.Models.Category>" %>
<tr>
<td><%: Model.Name %></td>
<td>
<!-- include the category name as hidden field so that
we can fetch it back in the controller action
-->
<%: Html.HiddenFor(x => x.Name) %>
<%: Html.CheckBoxListFor(x => x.Selected) %>
</td>
</tr>
Now the naming convention is important here. If the DefaultCategories property on your view model is an IEnumerable<Category>, then the editor template needs to be called Category.ascx and placed in ~/Views/Home/EditorTemplates/Category.ascx or if it will be reused between multiple controllers in ~/Views/Shared/EditorTemplates/Category.ascx.
Also your controller action you are submitting to should use a view model as parameter:
[HttpPost]
public ActionResult Modify(MyViewModel model)
{
PayeeDto = Mapper.Map<MyViewModel, PayeeDto>(model);
Services.PayeeServices.Save(p);
return RedirectToAction("Index");
}
This may not be the best answer but I try not to use generated checkboxes in MVC.
I would change
<td>
<%=Html.CheckBoxFor(x=>cat.Selected) %>
</td>
To
<td>
<input type="checkbox" name="<%: cat.value %>" id="<%: cat.value %>" <% cat.Selected ? " checked=\"checked\" " : ""; %> />
</td>

MVC datepicker in a grid

I am using the following EditorTemplate which ensure the datepicker is enabled for date fields;
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.DateTime?>" %>
<%:Html.TextBox("", (Model.HasValue ? Model.Value.ToShortDateString() : string.Empty), new { #class = "datePicker" }) %>
However the date is in the partial view following view;
<fieldset>
<legend>Enter the bank holidays here:</legend>
<table>
<tr>
<th>Bank Holiday</th>
<th>Date</th>
<th>Notes</th>
</tr>
<% foreach (var bankHolidayExtended in Model.BankHolidays)
{ %>
<% Html.RenderPartial("BankHolidaySummary", bankHolidayExtended); %>
<% } %>
<tr>
<td align="center" colspan="3" style="padding-top:20px;"><input type="submit" value="Submit" /></td>
</tr>
</table>
</fieldset>
The partial view looks like this,
<tr>
<td><%: Model.T.BankHolidayDescription%></td>
<td><%: Html.EditorFor(model => model.BH.NullableBankHolidayDate)%></td>
<td><%: Html.EditorFor(model => model.BH.BankHolidayComment)%></td>
</tr>
The problem is that the Date field has the same ID for each row. So when you enter a date on row x, it only updates the date on row 1.
How do I fix this so that I update the correct row?
Can you do something like this :
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<BankHolidays>" %> <%:Html.TextBox("", (Model.HasValue ? Model.NullableBankHolidayDate.ToShortDateString() : string.Empty), new { #class = "datePicker" id = Model.BankID }) %>
And instead sending the editor just Date, you sent him Model with date and bankID :
<td><%: Html.EditorFor(model => model.BH)%></td>
I assume that you have some sort of ID's in your BANK holiday (bankID,bankHolidayID) model. Sorry, I'm not so good at ASP.NET MVC..

How to put a jQuery click event on a checkbox in a grid in ASP.NET MVC 2

I am displaying a list of data in the following manner;
Surname
Forename
Email Address
Email Distribution
Ops Manager
Sign Off
Admin
Inputter
<% foreach (var item in Model.Users) { %>
<% Html.RenderPartial("UserSummary", item); %>
<% } %>
</table>
<div class="pager">
<%: Html.PageLinks(Model.PagingInfo, x=> Url.Action("List", new { page = x })) %>
</div>
and in the partial view;
<tr>
<td>
<%: Html.ActionLink("Edit", "Edit", new { id=Model.UserId }) %> |
<%: Html.ActionLink("Details", "Details", new { id=Model.UserId })%> |
<%: Html.ActionLink("Delete", "Delete", new { id=Model.UserId })%>
</td>
<td>
<%: Model.Surname %>
</td>
<td>
<%: Model.Forename%>
</td>
<td>
<%: Model.EmailAddress%>
</td>
<td>
<%: Html.CheckBoxFor(x => x.EmailDistributionListFlag) %>
</td>
<td>
<%: Html.CheckBoxFor(x => x.OperationsManagerFlag)%>
</td>
<td>
<%: Html.CheckBoxFor(x => x.SignOffManager)%>
</td>
<td>
<%: Html.CheckBoxFor(x => x.AdministratorFlag)%>
</td>
<td>
<%: Html.CheckBoxFor(x => x.InputterFlag)%>
</td>
</tr>
I want to put a click event on each checkbox, so when the checkbox is clicked I can do a database update.
However I do not appear to have a unique client name for each checkbox.
So I would like to know how to put the click event on the checkbox, and how do I know which user row has been clicked in relation to the checkbox.
Try to set the checkbox id this way:
Html.CheckBoxFor(x => x.EmailDistributionListFlag, new { id = "checkBoxEmailDistributionListFlag" })
And then you can access it by jquery:
$("#checkBoxEmailDistributionListFlag").click(function(){ ... });
Update:
You missed a few brackets in your js:
$(document).ready(function ()
{
$("#checkBoxEmailDistributionListFlag").click(function ()
{
alert("done!");
}) // <-- Those were missing
});
And make sure you have jquery included.
Update2
To quickly create checkboxes with uniques Ids and bind a function:
Html.CheckBoxFor(x => x.EmailDistributionListFlag, new
{
id = "checkBoxEmailDistributionListFlag_" + Model.UserId,
onclick = "EmailClickFunc(" + Model.UserId + ");"
})
And you can define your EmailClickFunc in js:
<script type="text/javascript">
function EmailClickFunc(id) { alert(id); }
</script>

ASP.Net MVC 2 - drop down list that controls a grid

I am just starting on MVC so this should be an easy question to answer.
I am using MVC 2 for ASP.Net.
I have a drop down list which when changes should cause the grid to change as well.
I have found a way to catch the change selection event and refresh the whole form using the code below.
The $('#TheForm').submit(); command causes the Index method of the Controller to run, and resets everything back as before.
What I want of course is for this method to pick up the new value of the dropdownlist, extract and display the new data in the View accordingly.
Is this how I should do it, or should I do more on the client side instead?
$(function () {
$("#StatusId").change(function () {
$('#TheForm').submit();
});
});
<p>
<% using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "TheForm" })){%>
<%: Html.DropDownList("StatusId", (SelectList) ViewData["Status"]) %>
<%}%>
</p>
<p>
<% if (Request.IsAuthenticated) { %>
<%: Html.ActionLink("Add new item", "Add") %>
<% } %>
</p>
<table>
<tr>
<th>
Title
</th>
<th>
Date
</th>
<th>
Status
</th>
</tr>
<% foreach (var item in Model) { %>
<tr>
<td>
<%: Html.ActionLink(item.Title, "Details", new { id = item.ItemCode }) %>
</td>
<td>
<%: String.Format("{0:g}", item.DateCreated) %>
</td>
<td>
<%: item.Status %>
</td>
</tr>
<% } %>
</table>
<p>
<%: Html.Label("Page: ") %>
<% for (int i = 1; i < Convert.ToInt32(ViewData["NumberOfPages"]); i++)
{ %>
<%: Html.ActionLink(i.ToString(), "Index", new { page = i })%>
<% } %>
</p>
The Index action needs a parameter StatusId.
It has to filter the list of items by StatusId. If this does not work please post the code of the action.

Resources