Post datepicker value when changed - asp.net-mvc

I'm using bootstrap.datepicker to set a datepicker in one of my Asp.Net MVC 5 Views. I want to post the date whenever a new one is selected. My code looks as follows:
#using (Html.BeginForm("ActionName", "ControllerName", FormMethod.Post))
{
<div class="form-group form-horizontal">
#Html.LabelFor(model => model.Date)
#Html.TextBoxFor(model => model.Date, new { #class = "form-control datepicker", data_provide="datepicker", data_date_format="dd/mm/yyyy"})
#Html.ValidationMessageFor(model => model.Date)
</div>
}
Hoever, I don't know how to force the Post method when I select a new date.

You can subscribe to the datepicker's changedate event and post the form:
$('.datepicker').datepicker().on('changeDate', function () {
$(this).closest('form').submit(); // or this.form.submit();
});

Related

Inputs inside Partialview takes value from main model

I render a PartialView inside my main View
View:
#model FullProductViewModel
...
<div class="send-container">
#Html.Partial("_CommentForm", new CommentViewModel { ProductId = Model.Id, Title = "" , Context="" })
</div>
...
I have a filed with name "Title" in Both my classes "FullProductViewModel" and "CommentViewModel".
_CommentForm PartialView:
#model CommentViewModel
<p class="page-title">#Resources.SendComment</p>
#using (Html.BeginForm("Comment", "Home", FormMethod.Post, new { #class = "form-comment form-submit" }))
{
#Html.AntiForgeryToken()
<div class="input-group">
#Html.LabelFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title, "", new { #class = "text-danger" })
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control" } })
</div>
<div class="input-group">
#Html.LabelFor(model => model.Context)
#Html.ValidationMessageFor(model => model.Context, "", new { #class = "text-danger" })
#Html.TextAreaFor(model => model.Context, htmlAttributes: new { #class = "form-control", rows = "8" })
</div>
<div class="input-group">
#Html.LabelFor(model => model.CaptchaCode)
#Html.ValidationMessageFor(model => model.CaptchaCode, "", new { #class = "text-danger" })
#Html.EditorFor(model => model.CaptchaCode, new { htmlAttributes = new { #class = "form-control" } })
</div>
<div class="captcha-wrapper">
<img alt="Captcha" id="imgcaptcha" src="#Url.Action("Captcha", "Captcha")" />
</div>
<button class="btn btn-submit" type="submit">#Resources.SendMessage</button>
}
The problem is "Title" inside PartialView take its value form "FullProductViewModel" model but not "CommentViewModel ". i can easily change the field name "Title" inside one of models to solve problem... but why this happened and how i can fix it without change field name?
Your Title property is conflicting with the #{ ViewBag.Title = ".. line of code in your view (the ViewBag code is used by the _Layout.cshtml file to set the global <title> attribute for the page).
All the HtmlHelper methods that generate form controls set the value by checking (in order)
ModelState
The ViewDataDictionary (ViewData or ViewBag)
The value of the models property
In your case, nothing has been added to ModelState. But because a value for Title has been added to the ViewDataDictionary, its that value which is used for the value of your textbox. The method never gets to read the actual value you have set in your model.
The only realistic option (unless you want to modify the code in the _Layout and all views that use it) is to change the name of the property.

How do I post varied length list to controller?

MVC4. I have a dynamic list on a view, a new textbox is added with button click (which adds a partialView) so user can enter a list of stuff. That is contained in a form element with a submit button.
In the controller I have tried three different types:
[HttpPost]
public ActionResult Index(IEnumerable<AccessoryVM> form)
{
-- form is NULL
[HttpPost]
public ActionResult Index(AccessoryVM form)
{
-- form has only the first item in the list
[HttpPost]
public ActionResult Index(FormCollection form)
{
-- seems to receive the list, but having trouble getting the values
All the examples I have seen are using a for list to add an index to each item, but they aren't using a dynamic list (it has a fixed length).
What should the Controller receiving type be?
EDIT to add more detail:
Button click appends partial view:
$("#add-item").on("click", function () {
$.ajax({
url: '/Accessory/AddItem',
cache: false,
success: function (html) {
$("#form-body").append(html);
}
})
return false;
})
Partial View:
#model EmployeeHardwareRequest.Models.ViewModels.AccessoryVM
<div class="form-group col-md-3">
#Html.LabelFor(model => model.ItemDescription, htmlAttributes: new { #class = "control-label" })
<div>
#Html.DropDownListFor(model => model.AccessoryId, Model.AccessoryDdl, new { #class = "form-control" })
</div>
</div>
<div class="form-group col-md-9">
#Html.LabelFor(model => model.ProductLink, htmlAttributes: new { #class = "control-label" })
<div>
#Html.EditorFor(model => model.ProductLink, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ProductLink, "", new { #class = "text-danger" })
</div>
</div>
Main View - partial is appended to the #form-body:
#using (Html.BeginForm("Index", "Accessory", FormMethod.Post, new { #id="accessory-form", #class = "form-horizontal" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div id="form-body">
<div class="form-group col-md-3">
#Html.LabelFor(model => model.ItemDescription, htmlAttributes: new { #class = "control-label" })
<div>
#Html.DropDownListFor(model => model.SelectedAccessory, Model.AccessoryDdl, new { #class = "form-control" })
</div>
</div>
<div class="form-group col-md-9">
#Html.LabelFor(model => model.ProductLink, htmlAttributes: new { #class = "control-label" })
<div>
#Html.EditorFor(model => model.ProductLink, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ProductLink, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<button id="add-item" class="btn btn-primary">Add Another Item</button>
</div>
<div class="col-md-6">
<input type="submit" value="Select Software" class="btn btn-default pull-right" />
</div>
</div>
}
Most likely, you have a binding issue. Assuming all you're posting is a collection of AccessoryVM, then the parameter should be List<AccessoryVM> form. However, in order for the modelbinder properly bind the posted values, your input names must be in a specific format, namely either form[N].Foo or just [N].Foo.
You haven't given any detail about what's going on in your view, but since these are dynamically added, you must be using JavaScript to add additional inputs to the page. If you're doing it via AJAX (returning a partial view), you'll need to pass the index to your endpoint so that it can be utilized to generate the right input names. If you're using something like Knockout, Angular, etc., you should ensure that whatever template is being used to generate the inputs takes an index into account.

MVC5 with EF6 : EditorFor() with an ICollection

I have a problem with my MVC5/EF6 website. I have a model like this :
(source: hostingpics.net)
When I'm creating an activity, I would like to add at least one date to it. So I created a new field in the form :
<div class="form-group">
#Html.LabelFor(model => model.Days, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Days)
#Html.ValidationMessageFor(model => model.Days)
</div>
</div>
According to various sources I've read here and there (https://stackoverflow.com/a/11403858/360708), I must create a file Day.cshtml in View/Shared/EditorTemplates/ so that I can tell MVC I want Day to have an editor for "day1" (DatePicker here).
This is because my model Day is an ICollection inside Activity, so I can't access the field day1 like this : "model.Days.day1". I've tried creating the Day.cshtml but it doesn't work. Here's the content of Day.cshtml
#model GAS_VS2013.Models.Day
#Html.EditorFor(o => o.day1)
Am I forgetting something or doing something wrong ?
Thanks
Thanks to Fals, it's now working with :
<div class="form-group">
#Html.LabelFor(model => model.Days, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Days, "Day")
#Html.ValidationMessageFor(model => model.Days)
</div>
</div>
To display the textbox as a HTML5 DatePicker, don't forget to add a DateTime.cshtml in the EditorTemplates with the following code (type of your day field must be DateTime) :
#model Nullable<DateTime>
#{
DateTime dt = DateTime.Now;
if (Model != null)
{
dt = (System.DateTime)Model;
}
#Html.TextBox("", String.Format("{0:d}", dt.ToShortDateString()), new { #class = "form-control datecontrol", type = "date" })
}
Source : http://www.aubrett.com/InformationTechnology/WebDevelopment/MVC/DatePickerMVC5.aspx(

Send single value through RouteValueDictionary

One of the properties of my ViewModel is an array which, unfortunately, is null every time I post back to the controller. I figured a simple hack where I place the values into a coma-delimited string.
This works great for our paging plugin, which posts back to our Index method, using a RouteValueDictionary. However, it is not working in the Html.BeginForm helper which posts back to a different controller action (the Update method).
View
#*Since we can't send arrays or complex objects break array down into string for RouteValueDictionary*#
var channelCodes = "";
for (int i = 0; i < Model.searchChannelCode.Length; i++)
{
channelCodes += Model.searchChannelCode[i];
if (i + 1 < Model.searchChannelCode.Length)
{
channelCodes += ",";
}
}
#*The 'searchChannelCodesPagin' variable from this RouteValueDictionary always posts back as null
using (Html.BeginForm("Update", "ZipCodeTerritory", new RouteValueDictionary()
{
{"searchChannelCodesPaging", channelCodes }
}, FormMethod.Post, new {id = "UpdateForm"}))
{
#Html.HiddenFor(model => model.searchZip)
#Html.HiddenFor(model => model.searchTerritory)
#Html.HiddenFor(model => model.searchState)
#Html.HiddenFor(model => model.searchActiveOnly)
#Html.HiddenFor(model => model.zipCodeTerritory)
<div id="cloneBox">
<div id="rw1">
#Html.LabelFor(model => model.newTerritory)
#Html.TextBoxFor(model => model.newTerritory, new { style = "width: 30px;padding-left:10px;", maxLength = 3 })
#Html.LabelFor(model => model.newDescription)
#Html.TextBoxFor(model => model.newDescription, new { style = "width: 250px;padding-left:10px;", maxLength = 30 })
#Html.LabelFor(model => model.newEffectiveDate)
#Html.TextBoxFor(model => model.newEffectiveDate, new { style = "width: 80px;padding-left:10px;" })
<div id="rw2" style="padding-top: 10px;">
#Html.LabelFor(model => model.newChannelCode)
#Html.DropDownListFor(model => model.newChannelCode, Model.ChannelCodes, " ")
#Html.LabelFor(model => model.newStateCode)
#Html.DropDownListFor(model => model.newStateCode, Model.StateCodes, " ")
#Html.LabelFor(model => model.newEndDate)
#Html.TextBoxFor(model => model.newEndDate, new { style = "width: 80px;" })
</div>
</div>
</div>
<br/>
<div id="buttonDiv">
<button type="submit" id="CloneButton" name="button" value="clone">Apply New Data</button>
<button type="submit" id="deleteButton" name="button" value="delete">Delete Selected Items</button>
<button type="submit" id="removeButton" name="button" value="removeErrors">Remove Selected Errors</button>
</div>
}
Controller
The forma above posts to this controller action. The searchChannelCodePaging variable is null each time.
[HttpPost]
public ActionResult Update(ZipCodeIndex updateZip, string button, string searchChannelCodesPaging)
{
Since you are doing a post, the simplest way to get it to the backend would be add a hidden field:
#Html.HiddenFor("searchChannelCodesPaging", searchChannelCodesPaging);
As a routing value, you may need to get it explicitly within the control via one of the two following approaches. These objects are directly accessible within the Controller class.
RouteData.Values("searchChannelCodesPaging")
Request.QueryString.Get("searchChannelCodesPaging");
You don't have to serialize a array type model parameter to a CSV string to get it to post to your controller. You can do this instead:
#for (var i = 0; i < Model.searchChannelCode.Length; i++)
{
#Html.HiddenFor(m => m.searchChannelCode[i]);
}

MVC - Showing validation message in place of Label

Suppose this is my view...
<div class="control-group">
#Html.LabelFor(model => model.Title, new { #class = "control-label" })
#Html.ValidationMessageFor(model => model.Title, null, new { #class = "help-inline" })
<div class="controls">
#Html.EditorFor(model => model.Title)
</div>
</div>
In case of error How we can hide the Label and display validation message in place of Label?
Please suggest on this...
You could display the Label only if the ModelState is valid:
<div class="control-group">
#if (this.ViewData.ModelState.IsValid)
{
#Html.LabelFor(model => model.Title, new { #class = "control-label" })
}
#Html.ValidationMessageFor(model => model.Title, null, new { #class = "help-inline" })
<div class="controls">
#Html.EditorFor(model => model.Title)
</div>
</div>
Notice that if you are using client side validation you will also need to hook up to the validate method on the client and toggle the corresponding label visibility as well.
Just to compliment Darin's answer, if you are using client-side validation you will need to do something like
$("#myForm").validate({
invalidHandler: function(event, validator) {
$('.control-label').hide();
}
});
Otherwise the label won't hide.
It's worth still checking ModelState.IsValid when the page loads as well though incase the user has JS disabled.

Resources