How do I convert this to MVC 3? - asp.net-mvc-3

I have this on a base page class in asp.net 4.
How do I convert or do this on mvc 3?
protected void ForceFullRefreshInFF()
{
if (Request.Browser.Browser == "Firefox")
Form.Attributes.Add("autocomplete", "off");//This fails
}

I think that you may want to store that in your ViewData. This allows you to use this value across all pages and partials. I believe "Form" in your case will be targeting the actual FormCollection.
protected void ForceFullRefreshInFF()
{
if (Request.Browser.Browser == "Firefox")
ViewData["autocomplete"] = "off";//This fails
}
Then in your view you can do:
<form autocomplete="<%: ViewData["autocomplete"] %>" ...>
...
</form>

Related

Handling multiple submit button in form

i was looking for good trick to handle multiple submit button in form and then i got some advice from this url and i followed but fail.
How do you handle multiple submit buttons in ASP.NET MVC Framework?
posted by #Andrey Shchekin.
he just said create a class like below one so i did in same controller
public class HttpParamActionAttribute : ActionNameSelectorAttribute {
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) {
if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
return true;
if (!actionName.Equals("Action", StringComparison.InvariantCultureIgnoreCase))
return false;
var request = controllerContext.RequestContext.HttpContext.Request;
return request[methodInfo.Name] != null;
}
}
then multiple submit button in the view look like & also controller code look like below
<% using (Html.BeginForm("Action", "Post")) { %>
<!— …form fields… -->
<input type="submit" name="saveDraft" value="Save Draft" />
<input type="submit" name="publish" value="Publish" />
<% } %>
and controller with two methods
public class PostController : Controller {
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveDraft(…) {
//…
}
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Publish(…) {
//…
}
}
but when i test his code it never work. so any can tell me where i am making the mistake or code itself is wrong for handling the situation. thanks
View:
<input type="submit" name="mySubmit" value="Save Draft" />
<input type="submit" name="mySubmit" value="Publish" />
Controller Action:
[HttpPost]
public ActionResult ActionName(ModelType model, string mySubmit)
{
if(mySubmit == "Save Draft")
{
//save draft code here
} else if(mySubmit == "Publish")
{
//publish code here
}
}
I had to deal with the similar scenario when I had the requirement that Users can finalize or save progress of the hospital infant record - essentially both actions are submit but one validates the record for insertion into the main DB table and another one saves it into a temp table without any validation. I handled it like this:
I have 2 buttons both are type submit with different IDs (btnSave and btnFinalize). When btnSave is clicked I intercept that event with some JQuery code:
$("#btnSave").click(function () {
$("#SaveForm").validate().settings.rules = null;
$('#SaveForm').attr('action', '#(Url.Content("~/Home/EditCase?finalize=false"))');
});
As you can see I modify the action attribute of the form to point to a different URL with a querystring attribute of finalize = false. I also remove any validation present on the model. If the other button is clicked I do nothing - executes the default behavior.
And in my controller I have a single action that handles both submit actions:
public ActionResult EditCase(EditInfantModel model, bool finalize = true)
{
// Logic for handling submit in here...
}
I think you can apply the similar technique for your problem. I'm not sure if it's the answer you're looking for but I thought it was worth mentioning...

Render different partial views

I'm trying to render different partial views from the _Layout file depending on what function I'm in, controller-wise.
The partial view is in the right column of the website which is located in the _Layout like so:
<aside id="right">
#Html.Partial("RightPartial")
</aside>
What I want to do is render a different partial view depending on where I am.
If I'm in the Index view I might want to view news and in the About view I might want to view phone numbers or something.
Appreciate any help :)
#{
string currentAction = ViewContext.RouteData.GetRequiredString("action");
string currentController = ViewContext.RouteData.GetRequiredString("controller");
}
Now based on the values of those variables decide which partial to render. To avoid polluting the Layout I would write a custom HTML helper:
<aside id="right">
#Html.RightPartial()
</aside>
which might look like this:
public static class HtmlExtensions
{
public static IHtmlString RightPartial(this HtmlHelper html)
{
var routeData = html.ViewContext.RouteData;
string currentAction = routeData.GetRequiredString("action");
if (currentAction == "Index")
{
return html.Partial("IndexPartialView");
}
else if (currentAction == "About")
{
return html.Partial("AboutPartialView");
}
return html.Partial("SomeDefaultPartialView");
}
}

Access global page variable in helper

#{
int i = 0;
}
#helper Text() {
<input type="text" name="Ans[#i].Text" />
}
i is not accessible in helper. How to access it?
You can simply add it as member to you page by using #functions declaration:
#functions
{
private int i;
}
You could pass it as parameter to the helper:
#helper Text(int i) {
<input type="text" name="Ans[#i].Text" />
}
and then:
#{
int i = 0;
}
#SomeHelper.Text(i)
or you could simply use editor templates which will take care of everything and get rid of those helpers. For example:
#Html.EditorFor(x => x.Ans)
You can achieve this by changing base class for your view. This scenario applies to situation where helper is declared in view.
Create a base class that inherits from WebViewPage and introduce shared field or property:
public class MyBasePage<T> : WebViewPage<T>
{
public int i;
public override void Execute()
{ }
}
Using #inherits directive change base class. And now field/property is acessible both from "page context" and helper:
#inherits NamespaceOfYourBaseClass.MyBasePage<YourModel>
#{
i = 0;
}
#helper Text() {
<input type="text" name="Ans[#i].Text" />
}
If you want to have a thing that is close to term "page property/field" but dont want to create a base class or helpers are stored within App_Code folder then you can try WebPageBase.Page property.
MSDN: Provides property-like access to page data that is shared between
pages, layout pages, and partial pages.
The code in this case would be:
#{
Page.i = 0;
}
#helper Text() {
<input type="text" name="Ans[#Page.i].Text" />
}
The drawback is that Page property is of type dynamic and thus does not support intellisense. As an alternative to Page there is another property - WebPageBase.PageData.
MSDN: Provides array-like access to page data that is shared between pages,
layout pages, and partial pages.
In this case a class-container of strings/ints keys for "page variables" could be created. And the code would be like:
// class visible to views and helpers
class MyViewFields {
public const string i = "MyViewFields.i"; // or maybe generate guid for key so there would be not doubts about its uniqueness.. but how would you debug this? :)
}
// in MyView.cshtml
#{
PageData[MyViewFields.i] = 0
}
#helper Text() {
<input type="text" name="Ans[#PageData[MyViewFields.i]].Text" />
}
This at least provides constraints for shared page data but still no control over value type.

ASP.NET MVC 3 - Custom client side validation not working

I'm trying to implement a custom client side validation, but it is not working. I'm basing myself on the article on Codeproject http://www.codeproject.com/Articles/275056/Custom-Client-Side-Validation-in-ASP-NET-MVC3
I also looked here on SO, but I think I'm implementing it in the correct manner, but I'm overlooking something.
My goal is to validate a date (required, date format and not earlier than another date on the form). The first two can be done with data annotations, the last I have to do with custom validation.
I have on my base class some dataannotations (ClassLibrary is in VB.NET):
Imports System.ComponentModel
Imports System.ComponentModel.DataAnnotations
<MetadataType(GetType(CM_CONTRACTVALIDATIONData))>
Partial Public Class CM_CONTRACTACTIVATION
'...
End Class
Public Class CM_CONTRACTVALIDATIONdata
'...
<DataType(DataType.Date)>
<Required()>
Public Property TakeBackDeviceWhen
'..
End Class
In the javascript file I have added the custom method:
//validation
$.validator.addMethod("checkPickupDate", function (value, element) {
return false;
});
$("#form").validate({
rules: {
TakeBackDeviceWhen: {
checkPickupDate: true
}
},
messages: {
TakeBackDeviceWhen: {
checkPickupDate: "Test"
}
}
}
);
My chtml file is as follow:
#Html.TextBox("TakeBackDeviceWhen", Model.TakeBackDeviceWhen.HasValue ? Model.TakeBackDeviceWhen.Value.ToShortDateString() : "", new { style = "Width: 200px" })
The resulting HTML is as follow:
<input id="TakeBackDeviceWhen" class="hasDatepicker" type="text" value="" style="Width: 200px" name="TakeBackDeviceWhen" data-val-required="The TakeBackDeviceWhen field is required." data-val="true">
It seems that neither my type validation and my custom validation isn't implemented.
What is going wrong?
OK, solved it. I hope :-)
What did I learned today:
(1) Don't use EditorFor: when you scaffold it from a MVC template, input fields are generated to EditorFor, it seems that you can't add custom unobtrusive validation tags. So, I was trying to get this fixed, untill I changed it to TextBoxFor.
(2) You can add custom validation methods in jQuery, but you can't mix them with unobtrusive validation. After adding a custom method, you have to also add it to the unobtrusive adapters. And don't forget to add jQuery on the bottom :-s (I got this from jQuery.validator.unobtrusive.adapters.addMinMax round trips, doesn't work in MVC3)
$(function () {
$.validator.addMethod("checkpickupdate", function (value, element) {
if (value == "20/09/2012") {
return false;
} else {
return true;
}
});
$.validator.unobtrusive.adapters.addBool("checkpickupdate");
} (jQuery));
(3) Add validation tags to the input field in the htmlAttributes:
#Html.TextBox("TakeBackDeviceWhen", Model.TakeBackDeviceWhen.HasValue ? Model.TakeBackDeviceWhen.Value.ToShortDateString() : "",
new {
style = "Width: 200px",
data_val = "true",
data_val_required = "verplicht!",
data_val_date = "moet datum zijn",
data_val_checkpickupdate = "wow"
})
(4) Datatype data annotations will not enforce a validation. You have to add it like in (3). You can add a custom ValidationAttribute like (for server side validation):
public class MustBeDateAttribute : ValidationAttribute {
public override bool IsValid(object value) {
try
{
DateTime dte = DateTime.Parse(value.ToString());
return true;
}
catch (Exception)
{
return false;
throw;
}
}
}
And this is the resulting html output:
<input type="text" value="" style="Width: 200px" name="TakeBackDeviceWhen" id="TakeBackDeviceWhen" data-val-required="required!" data-val-date="has to be a date" data-val-checkpickupdate="custom error" data-val="true" class="hasDatepicker valid">
As I'm using my ClassLibrary in different projects, I'm now going to try to seperate the dataannotations meta data from the class library (maybe with dependency resolver).

asp.net mvc 2 client side validation missing ValidationRules on custom attribute

Can't seem to get checkbox to be validate on client-side using asp.net mvc 2. Here is my code.
Model
[Serializable]
public class RegistrationModel
{
bool termsAndCondition = false;
[RequiredToBeTrue(ErrorMessage = "Need terms and service")]
public bool TermsAndConditions
{
get
{
return termsAndCondition;
}
set
{
termsAndCondition = value;
}
}
}
Custom Attribute
public class RequiredToBeTrueAttribute : RequiredAttribute
{
public override bool IsValid(object value)
{
return (value != null) && (value is bool) ? (bool)value : false;
}
}
View
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<RegistrationModel>" %>
<% Html.EnableClientValidation(); %>
<% using (Html.BeginForm("Register", "Registration", new { area="Account", id = "openid_form", inRegistration = true }))
<%=Html.ValidationSummary(false) %>
blah blah blah
<div class="checkbox"><label><%= Html.CheckBoxFor(model => model.TermsAndConditions) %>I agree to the terms and conditions of use.</label></div>
<input type="submit" id="submit" name="submit" value="Join Now" />
<%
Html.ValidateFor(m => m.TermsAndConditions);
%>
<% } %>
I am trying to call Html.ValidateFor at the end to push up all error message at top of the page. However, the property "TermsAndConditions" is not getting validated on client side (works great on server side). This leads me to look at the the window.mvcClientValidationMetData method at that mvc push out and I saw the following:
{"FieldName":"TermsAndConditions","ReplaceValidationMessageContents":false,"ValidationMessageId":null,"ValidationRules":[]}
Which you can see that "ValidationRules" are empty meaning that it is trying to validate it but the error message wasn't push out to the client for some reason.
Any ideas? Any help is appreciated.
Seems like I need to do more digging first. Was hoping the new attribute will appear magically on the client side. Instead, have to write some customer javascript to wire it up. See phil hack's post for detail.
This article from Phil Haack, ASP.NET MVC 2 Custom Validation, should help point you in the right direction.
Basically you need to create your own DataAnnotationsModelValidator<RequiredToBeTrueAttribute> and then write some client side script to get it done.
HTHs,
Charles

Resources