Kendo ui - how to tie validation to mvc model attributes - asp.net-mvc-4

From reading the posts in this thread - and being unable to post the question there for some bizarre reason :( I will ask it here in hope of getting a solution
Am I write in saying that I have to do validation like below..
I add the html5 attribute (data-required-msg/validationMessage) to the textbox and the required attribute as well..
I make a span for the invalid msg and tie it to the field with the "data-for" attribute. The message "Please enter name" should appear in this span then.
Questions
Is this the only way to work with this?
Is there no way for me to display the proper error message ("Error Message I want to show"), as in any way to tie to the mvc attributes on the ViewModel. As another poster said this is a lot more scalable/re-usable and better design.
Using a data-for="Name" is very brittle as a change in the Model field name will not reflect there and that could be forgotten about hence delivering buggy software. You are losing the type safety of something like
#Html.ValidationMessageFor(m=> m.Name)
Code
public class AViewModel
{
[Required(ErrorMessage="Error Message I want to show")]
public string Name { get; set; }
}
<div class="validation-wrapper">
<div class="input-wrapper">
#Html.TextBoxFor(m => m.Name, new { placeholder = "eg. John Smith", data_required_msg="PleaseEnter name", required="required" } )
</div>
<span class="k-invalid-msg" data-for="Name"></span>
</div>
Cheers,
J

In order to be able to do what you are saying, you need to be using Kendo UI for ASP.NET MVC. With that you can continue using your DataAnnotations attributes and Html.ValidationMessageFor() helpers as before. All you will need to do is call $('[your_form_selector]').kendoValidator() after your form (or on document.ready()).

Related

how to show all the errors on a page in one shot (submit button) by client side validation in mvc .net core

I have a page with many required fields. So when I click submit button required validation is firing for the first field then the second then the third and so on...
What I need to do here is , When I click on submit I have to show all errors on a page in one shot.
My requirement is to achieve this only by validating client side.
I am using an .Net core MVC application.
Below is the screenshot of my page
Can I achieve this.. Please help me..
Thanks !!
I can give you an idea to do your job using jquery custom validation.Please refer my solution.
Add custom style class to your required fields.
Example :
<input type="text" class="req-cls" >
Write Jquery function to Check Validation
$(document).ready(function () {
$('#btn1').click(function (e) {
var isValid = true;
$('.req-cls').each(function () {
if ($.trim($(this).val()) == '') {
isValid = false;
$(this).css({
"border": "1px solid red",
"background": "#FFCECE"
});
}
else {
$(this).css({
"border": "",
"background": ""
});
}
});
if (isValid == false)
e.preventDefault();
});
});
See Example here : https://jsfiddle.net/Shalitha/q2n8L9wg/24/
Just add this line in your .cshtml
<div class="validation-summary-valid" data-valmsg-summary="true">
<ul>
<li style="display: none;"></li>
</ul>
</div>
Since you need client side we are talking about JS. But with razor you can validate a few results using the model annotations. For example let's say you have this object.
public class UserCreationVO
{
[Required]
[StringLength(255)]
public string Username { get; set; }
}
Now what you need to do in your frontend (meaning your .cshtml file) is to tell asp.net to use this properties to validate. So for example:
#model UserCreationVO
<form method="post">
<input asp-for="UserName" />
<span asp-validation-for="UserName"></span>
</form>
As you can see above using asp-for is a great way to create validations using your models. Be careful you must pass as a model the object you want to validate. The asp-for tag shows a model property. So you can't pass it in a Viewbag or something. This produces some automatic html and js for you and handles it.
Furthermore you should always validate the result nevertheless in the controller. Because client side validation is for performance reasons and user experience and doesn't offer any kind of security:
public IActionResult CreateUser(UserCreationVO user)
{
if(!ModelState.IsValid)
return your_error;
}
Last but not least: You must include the JQuery unobtrusive validation library. Furthermore if you have some extra requirements like checking if a username exists (Which can't be done without contacting the server) then you can use the [Remote] attribute.
More info and reading about front-end validation with razor: here
How to use a remote attribute: Using remote validation with ASP.NET Core
EDIT:
So generally I advise to use models and create them. As you say policy is required in one form but not in another. What you should do to have a maintanable code where you simply change the attribute of your model and the validation happens you need to create a different VO. For example:
public class CreatePolicyVO
{
[Required]
public string PolicyNumber {get; set;}
}
And another object for example updating:
public class UpdatePolicyVO
{
public string PolicyNumber {get; set;}
}
Because you also need to validate them in the controller. So passing a different object allows you to use ModelState.IsValid and other MVC and razor features. Generally if a field is required in one case and not in another then you need a different model.
First, we need to add the JQuery,jquery.validate & jquery.validate.unobtrusive in our views.
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.16.0/jquery.validate.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js"></script>
Then in View add required data-* attributes like:
<label for="Name">Name</label>
<input type="text" data-val="true" data-val-length="Length must be between 10 to 25" data-val-length-max="25" data-val-length-min="10" data-val-required="Please enter the name" id="Name" name="Name" value="" />
<span class="field-validation-valid" data-valmsg-for="Name" data-valmsg-replace="true"></span>
<br />
You could see that it has added the several attributes starting with data-*.
The data-* attributes are part of the HTML5, which allow us the add extra information (metadata) to the HTML element.
The Javascript unobtrusive library reads the data-val attributes and performs the client side validation in the browser when the user submits the form. These Validations are done before the form is sent over an HTTP. If there is a validation error, then the request will not be sent.

SelectList dropdown list showing multiple = "multiple" for current viewmodel

This kind of a bizarre issue and I can't figure out a solution how I want.
I'm using .net core 2.1. I have a orders view model like this:
public class OrdersFilterViewModel
{
[Display(Name = "Account Numbers:")]
public IEnumerable<SelectListItem> AccountNumbers { get; set; }
}
My viewmodel and SelectList in my orders controller is called like this:
var vm = new OrdersFilterViewModel
{
AccountNumbers = new SelectList(_context.Account.Where(m => m.UserID == userId), "AccountNumber", "AccountNumber", account)
};
return PartialView("_FilterOrders", vm);
The problem lies when trying to get a dropdown list in the view which looks like this:
<form asp-action="FilterOrders" asp-controller="Order" id="ordersFilterForm" method="post">
<div class="form-group">
<label asp-for="AccountNumbers" class="control-label"></label>
<select asp-for="AccountNumbers" class="form-control" asp-items="#Model.AccountNumbers">
</select>
</div>
<div class="form-group">
<input type="submit" value="Submit" class="btn btn-default" />
</div>
</form>
This somewhat works but gives me a textarea type display where multiple = "multiple" is always tacked on in the browser. I've discovered that if I add something like the following to my viewmodel:
public int? AccountId { get; set; }
Then change my view to:
<select asp-for="AccountId" class="form-control" asp-items="#Model.AccountNumbers">
I can then have my dropdown list. However, I don't need that property for anything as far as I know. I tried a million things so it's possible I made some other slight changes I'm forgetting to get that to work, but that's the gist of it.
Is there any way around adding that extra property? Or do I need it for something I'm not aware of? Or is there any way to set multiple = "false" or something to that effect so I can get my dropdown list with my original viewmodel and such?
I haven't dealt with the post back to the controller yet, so maybe that will reveal the gotchas. I'm basically trying to create a modal type query filter that doesn't really do much other than modify some parameters and send them back to my query to update it. Thanks.
Is there any way around adding that extra property? Or do I need it
for something I'm not aware of?
Yes, you need this extra property, because in your select there are many items, and the user will select one or multiple items, and on the server side you'll need to know what the user selected, this is the purpose of the select tag.
And the multiple = "multiple" depends on what you put in the asp-for in the case of asp-for="AccountId" it is a single int value, so it won't use multiple, is you have an array in the asp-for then it will use the multiple.
Here is a pretty detailed description about the select tag helper:
Select Tag Helper in ASP.NET Core MVC

MVC 4 - Can I control where model errors are displayed?

I have an MVC 4 app and am using HTML.BeginForm to create a form on a View. I have several field sets where I have positioned them on an absolute basis. For example, here is my BeginForm and one of my fieldsets:
<div style="width:1100px; height:490px;">
#using (Html.BeginForm("Create", "BicycleSellerListing", FormMethod.Post, new { enctype = "multipart/form-data" })) {
#Html.ValidationSummary(true)
<fieldset style="position:absolute; top:180px; left:150px; width:550px">
<legend>Bicycle Information</legend>
...
...
The problem is that if there are errors in the ModelState when a submit is done, the errors generated are covered by some of the fields in the fieldsets. Is there a way I can indicate where I want model state errors to display?
There are couple ways to display errors. #Html.ValidationSummary() will display all of the errors in one place. So depending where you put #Html.ValidationSummary(true) - that's where errors will be displayed. For example, you can put it after the form, not in the beginning like you have it.
Another way is to use #Html.ValidationMessageFor(...) helper. It takes your mode's property name so the error will only be displayed for that property. Again, you can put it anywhere you want. Usually people put it next to the input so that error message is displayed next to the input as well.

.net MVC 4 Authorization (Membership)

During my first steps in .NET MVC 4 I'm creating a web site and I would like to implement users authentication/authorization.
In my implementation I would like to be able to link controls to roles. For example, if I have 2 Roles in my system : Admin and User, the in some view say I have 3 inputs:
<input class="search-field rounded" id="field1" type="text"/>
<input type="submit" name="submit"/>
<input class="search-field rounded" id="field2" type="text"/>
<input type="submit" name="submit"/>
<input class="search-field rounded" id="field3" type="text"/>
<input type="submit" name="submit"/>
I would like that an Admin will be able to see and edit all 3 fields in this view, but a User should only see 2 of them, and be able to edit one of them (this is just an example).
So basically, I would like to be able to define permissions for controls, and a role should be consisted of a collection of permissions (If you can think of a better approach I would love to hear it).
So those are my constraints, and I see quite a few packages out there (such as Fluent Security, and Security Guard) that relates to the subject, but I'm not quite sure which is best to tackle my challenge if at all.
Is there a best practice to overcome this demand?
Any help is highly appreciated.
idlehands23 has shown how you might access and check roles but i'm guessing you want to use this functionality at the view level.
Within an action method, I usually pass HttpContext.User into the ViewBag or in the case of a strongly typed view you can pass the principal into your model and parse these values out as you wish. Then pass the model to the view like so.
return View(new ModelClass(HttpContext.User))
From here you can add additional code into the view logic to parse/check the roles and render the html with greater specificity using for example:
If (Model.User.IsInRole("Admin"))
{
//Render admin controls
//...
}
else
{
//Render User Controls
//...
}
Using the [Authorize(Role="Admin||User")] attribute on your action method would restrict access to an entire group of users. In such a case you would need two action methods and one or possibly two distinct views to render the content. However if you just want to limit it to ANY authorized user you can do like so:
[Authorize]
public ActionResult Index(){}
Then you can implement the logic at the view level with the certainty that they are authorized.
I have done it this way:
//In Controller
ViewBag.Roles = Roles.GetRolesForUser(User.Identity.Name);//viewbag because I'm assuming this isn't what you want to strongly type to your page.
//In View
#{
var roles = (Roles)ViewBag.Roles;
}
if(roles.contains("admin')) //put whatever you want in place of "admin"
{
//do something
}
in your controller you can give access to certain views or partial views this way
//in controller if you want it.
[Authorize(Roles = "Admin, ImportExport, Search")] //this is just for security
public ActionResult whatever(){}
*I use razor. replace # with <% %> if your not.
I ended up creating my own custom membership provider and role provider.
In my Role Provider I added a method
public bool UserHasPermission(string username, string permission) {...}
And in my view I'm doing:
#{
var roleProvider = Roles.Provider as MyCustomRoleProvider;
bool addressEditPermission = roleProvider.UserHasPermission(User.Identity.Name, "addressEditPermission");
}
Then I can manipulate my control:
#Html.TextBoxFor(model => model.Name, new { #readonly = addressEditPermission })
You just need to make sure your control has overloads that take HTML attributes.
I hope this helps someone..

Passing a GET parameter to ActionLink in ASP.NET

Sorry but I am new to C# and ASP.NET and I saw alot of posts about this problem but I quite didn't get it. I am trying to understand how to pass a GET parameter to an action thru HTML.ActionLink:
here is the the URL:
http://localhost:36896/Movies/SearchIndex?searchString=the
and my CSHTML page should look like this:
<input type="Text" id="searchString" name="searchString" />
#Html.ActionLink("Search Existing", "SearchIndex", new { searchString = "the"})
this hard coded parameter "the" is actually working, but how can I select the input element with id=searchString, with something like document.getElementById("searchString").value
Thanks,
If the value you want to send as GET parameter is not known on the server you cannot use the Html.ActionLink helper to add it. You need to use javascript to manipulate the existing link and append the parameter.
It looks like you have an input field that contains a search string and you want to send the value entered in this field to the server. A better way to handle this scenario is to use an HTML form with method="GET" instead of an ActionLink. This way you don't need to use any javascript - it's part of the HTML specification:
#using (Html.BeginForm("SearchIndex", "Movies", FormMethod.Get))
{
#Html.EditorFor(x => x.SearchString)
<button type="submit">Search</button>
}
Now when you click on the Search button the value entered in the SearchString field will automatically be sent to the SearchIndex action:
http://localhost:36896/Movies/SearchIndex?searchString=the
But if you absolutely insist on using an ActionLink you will have to write javascript to manipulate the href of the existing link when this link is clicked in order to append the value to the url. It's an approach I wouldn't recommend though because the HTML specification already provides you this functionality throughout HTML forms.
This makes the #Html.EditorFor refer to the Title field of the object, kinda in a random way but it works!
#using (Html.BeginForm ("SearchIndex", "Movies", FormMethod.Get))
{
#Html.EditorFor( x => x.ElementAt(0).Title)
<button type="submit">Search</button>
}
Still couldn't pass input parameter to the URL in the GET.
EDIT:
FINAL SOLUTION:
#Html.TextBox("SearchString")
<button type="submit">Filter</button>
and on the controller side, switch the input parameter. Basically it will automatically recognize the passed parameter.
public ActionResult SearchIndex(string searchString)
{
...
}