ASP.NET MVC Required Field Indicator - asp.net-mvc

For fields in my ASP.NET MVC view that have been attributed as required, is there any way for the framework to render some sort of indicator automatically that the field is marked as required in metadata?

Should be able to do this with CSS since MVC3 adds in those custom attributes to the element:
<input data-val="true" data-val-required="The Username field is required." id="Username" name="Username" type="text" value="" />
You could key off the data-val-required in CSS like so:
input[data-val-required] {
background:red
}
or set a background image of an asterisk etc.

I did that way because my required fields must be dynamic (defined in a configuration file)
Add at the end of your View:
<script type="text/javascript">
$('input[type=text]').each(function () {
var req = $(this).attr('data-val-required');
if (undefined != req) {
var label = $('label[for="' + $(this).attr('id') + '"]');
var text = label.text();
if (text.length > 0) {
label.append('<span style="color:red"> *</span>');
}
}
});
</script>

I modified Renato Saito's answer to include more field types (all types of input and select lists) and use the jQuery namespace instead of the generic $. Here is my revision:
<script type="text/javascript">
// add indicator to required fields
jQuery('input,select').each(function () {
var req = jQuery(this).attr('data-val-required');
if (undefined != req) {
var label = jQuery('label[for="' + jQuery(this).attr('id') + '"]');
var text = label.text();
if (text.length > 0) {
label.append('<span style="color:red"> *</span>');
}
}
});
</script>

Here is one that will attach a red asterisk to the right side of anything with the attribute 'data-val-required'.
<script type="text/javascript">
$('[data-val-required]').after('<span style="color:red; font-size: 20px; vertical-align: middle;"> *</span>');
</script>

Adding html attribute is not enough. This will only cause javascript validation error. If you want to indicate that the field is required you'd probaly want to add an asterisk to it. You can do it by means of extenssion method of HtmlHelper. You can find a thorough explanation here
Indicating required field in MVC application

A Small Modification Is Done From My Side.
Actually I had primary keys (Identity Columns in DB). That I did no want to highlight.
So I Used Below Code Snippet to select only input[type=text] fields that has required attribute in annotation.
$("[data-val-required]").not(":hidden").not(":radio").not(":checkbox").after('<span style="color:red;max-width:10px;min-height:30px;">*</span>');

Related

knockout in mvc - simple example not working

I got knockout to work before in MVC, but unfortunately I lost the code, and need help figuring it out.
I am trying to simply put an html page in the ~/wwwsource/ folder of my MVC project, and in that page I would like to demo a simple knockout example.
(Eventually, I actually want to use knockout inside MVC Views, using knockout right alongside Razor if possible but first I just would at least like to get a simple working example going, and extend from there.
I tried the following, which worked in JSFiddle but not in Visual Studio:
<script src="lib/knockout/dist/knockout.debug.js" type="text/javascript">
// Here's my data model
var ViewModel = function (first, last) {
this.firstName = ko.observable(first);
this.lastName = ko.observable(last);
this.fullName = ko.pureComputed(function () {
// Knockout tracks dependencies automatically. It knows that fullName depends on firstName and lastName, because these get called when evaluating fullName.
return this.firstName() + " " + this.lastName();
}, this);
};
ko.applyBindings(new ViewModel("Planet", "Earth"));
</script>
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
<h2>Hello, <span data-bind="text: fullName"> </span>!</h2>
You are calling the javascript before the html has been fully rendered. So when ko.applyBindingsis called the html as only partially loaded.
Easiest solution is to wrap the javascript in a document loaded callback using jQuery (which should exist because you're using knockout).
You also have some invalid script tag syntax. Need to close knockout script tag before starting a new one for the page.
<script src="lib/knockout/dist/knockout.debug.js" type="text/javascript">
</script>
<script type="text/javascript">
// Here's my data model
var ViewModel = function (first, last) {
this.firstName = ko.observable(first);
this.lastName = ko.observable(last);
this.fullName = ko.pureComputed(function () {
// Knockout tracks dependencies automatically. It knows that fullName depends on firstName and lastName, because these get called when evaluating fullName.
return this.firstName() + " " + this.lastName();
}, this);
};
$(document).ready(function(){
ko.applyBindings(new ViewModel("Planet", "Earth"));
})
</script>
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
<h2>Hello, <span data-bind="text: fullName"> </span>!</h2>

Binding with multiple PartialViews in Knockout

I've got a jQuery Accordion and each panel contains a form. All of the forms are the same, and the inputs share the same IDs, names, and data-bind attributes.
Assuming each form has a different binding context (using ko with:), this is how I would set up the Knockout.js ViewModel if there were two forms.
However, I don't know in advance how many forms there will be. I'm rendering a PartialView (which contains the form) for every form object in the MVC ViewModel's collection of forms.
#model ViewModel
<div class="container-fluid">
<div id="jQueryAccordion">
#foreach (var form in Model.AllForms.ToList())
{
<!-- ko with: items[#form.Key] -->
Html.RenderPartial("_Form", form);
<!-- /ko -->
}
// etc.
How would I set up the Knockout.js ViewModel if I don't know how many forms there are going to be?
I suggest that you can load your partial view dinamically via ajax call & bind data knockout binding accordingly as follows:
//C# XxxController: return partial view:
public ActionResult MyView()
{
return PartialView("_MyView");
}
//Ajax call to load partial view at client side:
$.get('Xxx/MyView', function(view){
_contentHolder.html(view);
ko.applyBinding(self, _contentHolder[0]);
})
You can loop through your model collection and apply knockout binding dynamically.
As Anh Bui suggested, I would create them dynamically in the browser. Using applyBindings with markup you created with ASP.net on the server-side is a bit of a hack and means your working against Knockout, not with it.
It would be better to let Knockout take care of actually creating the forms. This means
supplying it only the data it needs to create each form as JSON
creating a Knockout template for the form markup
looping over the data with the forEach binding
The template:
<script type="text/html" id="form-template">
<form action="/target-url">
<label for="user_name">What's your name?</label>
<input type="text" data-bind="value: user_name" name="user_name" />
<label for="user_location">Where are you from?</label>
<input type="text" data-bind="value: user_location" name="user_location" />
</form>
</script>
Next you output your relevant form data as a JSON array on the server side. I haven't used ASP.net, so I can only offer you pseudo-code here:
<script type="application/javascript">
window.form_json_from_server = "
#foreach (var form in Model.AllForms.ToList())
{
// .. ASP.net JSON output magic goes here
}
";
</script>
so that the end result in your markup looks like
<script type="application/javascript">
window.form_json_from_server = "[
{ user_name: "Foo1", user_location: "Bar1" },
{ user_name: "Foo2", user_location: "Bar2" },
{ user_name: "Foo3", user_location: "Bar3" }
]";
</script>
(note that JS strings cannot contain line breaks. I've formatted it here with line breaks for easier reading)
Now we have our form data formatted as JSON, saved in a Javascript string. Next up: your Knockout view model:
var ViewModel = function ViewModel() {
var that = this,
raw_forms_object;
// we reconstitute our JSON string into a Javascript object
raw_forms_object = JSON.parse(window.form_json_from_server);
// this is where the objects made from our JSON will end up in
this.forms = ko.observableArray([]);
ko.utils.arrayForEach(raw_forms_object, function(f) {
// f contains one of our form objects, such as { user_name: "Foo1", user_location: "Bar1" }
// instead of adding f directly to the array, we make a new object in which the
// properties are observables
var form = {
user_name: ko.observable(f.user_name),
user_location: ko.observable(f.user_location),
};
// add our new form object to our observableArray
// make sure to use 'that', because 'this' is the scope of the arrayForEach callback we're in
that.forms.push(form);
});
}
Now we have an observableArray called 'forms' on our view model with our form objects in it. We use the forEach binding to make as many forms as we have form objects:
<div data-bind="template: { name: 'form-template', foreach: forms }"></div>
All that's left is applying an instance of our view model to the page:
ko.applyBindings( new ViewModel() );
If you like, you can try it out in this runnable code snippet:
var ViewModel = function ViewModel() {
var that = this,
raw_forms_object;
// we reconstitute our JSON string into a Javascript object
raw_forms_object = JSON.parse(window.form_json_from_server);
// this is where the objects made from our JSON will end up in
this.forms = ko.observableArray([]);
ko.utils.arrayForEach(raw_forms_object, function(f) {
// f contains one of our form objects, such as
// { user_name: "Foo1", user_location: "Bar1" }
// instead of adding f directly to the array, we make a new object in which the
// properties are observables
var form = {
user_name: ko.observable(f.user_name),
user_location: ko.observable(f.user_location),
};
// add our new form object to our observableArray
// make sure to use 'that', because 'this' is the scope
// of the arrayForEach callback we're in
that.forms.push(form);
});
}
ko.applyBindings( new ViewModel() );
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script type="text/html" id="form-template">
<form action="/target-url">
<label for="user_name">What's your name?</label>
<input type="text" data-bind="value: user_name" name="user_name" />
<label for="user_location">Where are you from?</label>
<input type="text" data-bind="value: user_location" name="user_location" />
</form>
</script>
<div data-bind="template: { name: 'form-template', foreach: forms }"></div>
<script type="application/javascript">
window.form_json_from_server = '[{"user_name": "Foo1","user_location": "Bar1"},{"user_name": "Foo2","user_location": "Bar2"},{"user_name": "Foo3","user_location": "Bar3"}]';
</script>

Making Kendo Datepicker readonly but also selectable

I´ve been struggling to make my Kendo Datepicker without user-text-input and the only solution I´ve come up with was making the tag "readonly". However I want to be able to select the date from the selector with the mouse without being able to input text directly to the picker, therefore making the datepicker readonly but selectable.
Any ideas how?
<div>
#(Html.Kendo().DatePicker()
.Start(CalendarView.Year)
.Name("DatePicker")
.Value(DateTime.Now.AddDays(-365))
.Max(DateTime.Now)
.HtmlAttributes(new { style = "width: 125px;" })
.Events(e => e.Change("onDateChange")))
</div>
After a while I found a very simple solution using javascript. I simply declared a script that prevents any user input without disabling or making the input readonly. Something like this:
$("#inputId").keypress(function (evt) {
var keycode = evt.charCode || evt.keyCode;
if (keycode == 9) { //allow Tab through
return true;
} else {
return false;
}
});
It was easier than I thought :)
########### EDITED ####################
As suggested in a comment, it is probably not good practice to suppress all the keystrokes so I will paste almost the same code but suggesting that I open the datePicker instead (but still kind of suppressing the user text input as well).
$("#inputId").keypress(function (evt) {
var keycode = evt.charCode || evt.keyCode;
if (keycode == 9) { //allow Tab through
return true;
} else {
// Allow the datepicker to open instead
var datePicker = $("#inputId").data("kendoDatePicker");
datePicker.open();
return false;
}
});
You can do something like this:
#(Html.Kendo().DatePicker().Name("FollowUpDate").HtmlAttributes(new{onkeydown="javascript:return false;" }))
when someone clicks the datepicker it returns false hence does not allow to type anything while it still remains selectable.
If you want to just select data from opening calendar which kendoDatePicker show you but user not allow to enter date
<link href="http://cdn.kendostatic.com/2015.1.408/styles/kendo.common.min.css" rel="stylesheet" />
<link href="http://cdn.kendostatic.com/2015.1.408/styles/kendo.default.min.css" rel="stylesheet" />
<input type="text" onkeydown="return false" placeholder="Enter Date" class="DatePicherKendo" />
<script src="~/bower_components/DataPicker-Kendo/JalaliDate.js"></script>
<script src="~/bower_components/DataPicker-Kendo/kendo.web.js"></script>
$(".DatePicherKendo").kendoDatePicker();
Add a maxlength attribute of 0 in HtmlAttributes.

Avoiding validation loop in jQuery unobtrusive validation

Having two fields in my form, that compare to each other to see if they are valid:
<input type="text" name="StartDate" id="StartDate" value="2"
data-val="true" data-val-equalto="xx" data-val-equalto-other="EndDate"/>
<input type="text" name="EndDate" id="EndDate" value="3"
data-val="true" data-val-equalto="xx" data-val-equalto-other="StartDate"/>
When I blur on StartDate, EndDate gets validated as well. So jQuery manages to avoid validation loop between one and the other.
Now, I am trying to implement the same mechanism in my custom validation rules. I get the value from the "other" field, and if everything is right, i trigger validation in the "other" as well, but this ends in a validation loop:
$.validator.addMethod("customequal-method", function (val, el, p) {
var $other = $(el).closest('form').find('input[name=' + p.other + ']');
if($other.val() == val){
try{$other.valid();}
finally{return true;}
}
return false;
});
How could I apply the same approach than jQuery? I mean, given these two fields:
<input type="text" name="StartDate2" id="StartDate2" value="2"
data-val="true" data-val-customequal="xx xxx" data-val-customequal-other="EndDate2"/>
<input type="text" name="EndDate2" id="EndDate2" value="3"
data-val="true" data-val-customequal="xx xx" data-val-customequal-other="StartDate2"/>
I want that when modifying EndDate2, after blur, StartDate2 gets validated as well, and both became valid in the same way than in jQuery.
I have been trying to put together an example in jsFiddle, but I cannot make my custom method work: http://jsfiddle.net/vtortola/vu6tm/ ( if you find the problem I would be very grateful ), I started a separate thread about this at jQuery unobtrusive custom adapter and method in jsFiddle
Cheers.
You need a stack to understand you returned back to a previously validates element. A single value is not enough because eache element may be involved in other rules with other elements. You may define the var that contains the stack in closure (isInStack verifies if the element is in the array):
(function () {
var stack = [];
$.validator.addMethod("customequal-method", function (val, el, p) {
var iAmTheRoot = stack.length == 0;
var $other = $(el).closest('form').find('input[name=' + p.other + ']');
if($other.val() == val){
try{
if (!isInStack($other[0]) ) $other.valid();
}
finally{
if (iAmTheRoot) stack = [];
return true;}
}
return false;
});})();

Call Action From view

This is my action :
[HttpPost]
public ActionResult AddDispo(string idv, string dd, string df)
{
try
{
Models.indisponible model = new Models.indisponible();
model.Dd = Convert.ToDateTime(dd);
model.Df = Convert.ToDateTime(df);
model.idv = idv;
entity.indisponible.AddObject(model);
entity.SaveChanges();
TempData["Resultat"] = "La nouvelle date a été ajouté courrectement";
return RedirectToAction("Dispo", "Agence", new { idv = idv});
}
catch (Exception)
{
TempData["Resultat"] = "Une erreur se produiset Vielliez ressaiyer";
return RedirectToAction("Dispo", "Agence", new { idv = idv});
}
}
I want to call this action without using Html.beginForm from my view, i have made this trial but it hasn't worked :
<%: Html.Action("Accepter", "Adddispo", new { id = Model.idv, dd = Model.Dd, df = Model.Df })%>
Your Action method is of type HTTPOST. So you need a form posting for that action to get invoked. If you do not wish to use the form tag in your view, you may use jQuery to do a POST.
The below example does a post when user clicks on a button woth ID btnPost.
HTML ( Content of Your View)
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
</head>
<body>
Name : <input type="text" id="txtName" /> <br/>
Age: <input type="text" id="txtAge" /> <br/>
Place : <input type="text" id="txtPlace" /> <br/>
<input type="button" value="Save" id="btnPost" />
<script type="text/javascript">
$(function(){
$("#btnPost").click(function(e){
e.preventDefault(); // preventing the default button submit behaviour
var name=$("#txtName").val(); //reading the text box values
var age=$("#txtAge").val();
var place=$("#txtPlace").val();
$.post("YourController/AddDispo", { idv :name, dd : age, df=place} ,function(data) {
//Do whatever with the the response. may be an alert
alert(data);
});
});
});
</script>
What it does
1) In the head section of the document, we included the reference to the jQuery library. I am including a reference from the google CDN. You may change that to include your local copy. If you are working with ASP.NET MVC, the default project template has this under the Scripts folder(version number may be different).
2) In the document ready event ($(function(){..) we are binding some functionality to the button which has an ID btnPost. We are binding the functionality on the click event. So whenever user clicks on that button, that piece of code will be executed.
3) We are reading the text box values, and making use of the post method of jQuery. It will post the data we are passing ( we are passing the values of text boxes here) to the action method. once the action method returns something back to the calle, it will be stored in the data variable. you can do further things (show some message to user/ reload some content) after checking the value of that.
Action link will always send a "GET" request. Either remove that [HttpPost] attribute from your controller action, or use a similar technique suggested by shyju. Action link has some issues with windows events, so you should stick to stylized buttons unless there is specific need for anchors. A sample styling will be :
#mybutton input[type=submit] {
background: none;
padding: 0px;
font-family: arial;
font-size: 1em;
cursor: pointer; // to make it look like link
border: none; // --- " -----
}

Resources