How to provide validation with single button in mvc3 - asp.net-mvc-3

I have two buttons on single form.
First button used to upload file and second button is submit .
I want validation , when i clicked on submit button that time validation should be generate.
But in my application when i clicked on upload button that time validation generated.
View:
<% using (Html.BeginForm("Create","Document", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
<table>
<tr>
<td >
File Name:
</td>
<td >
<%: Html.EditorFor(model=>model.document.DOCUMENT_NAME) %>
<%: Html.ValidationMessageFor(model => model.document.DOCUMENT_NAME) %>
</td>
</tr>
<tr>
<td>
Select File:
</td>
<td>
<input type="file" name="file" id="file" style="height: 24px" />
<input type="submit" name="submitButton" value="Upload" />
</td>
<tr>
</table>
<div>
<input type="submit" name="submitButton" value="Create" />
</div
<%}%>
Controller:
[Required]
[Display(Name = "DOCUMENT NAME")]
[ReadOnly(true)]
public string DOCUMENT_NAME
{
get;
set;
}

Any button on form (and You have two) will trigger validation. One of possibile solutions is replace upload button by some element and do uploading via jquery.

you can also check which button is click like below
View:
<div>
<input type="file" name="file" id="file" style="height: 24px" />
<input type="submit" id="btnUpload" name="submitButton" value="Upload" />
</div>
<div>
<input type="submit" id="btnCreate" name="submitButton" value="Create" />
</div
controller
public ActionResult actionName(string btnUpload,string btnCreate)
{
//now you can easily check here for which button is clicked
if(btnUpload != null || btnUpload !="")
{
//perform uploading logic here
}
if(btnCreate!=null || btnCreate !="")
{
//perform your validation here
}
}
i hope this will help you.

Related

Hidden input data is not passed from view component to post action method in controller - ASP.NET Core 6 MVC

I am trying to pass parameters value from a view component to a post action method, but the hidden input is not received in the controller.
I know how to pass from view to controller and it works fine, but in the view component it is not passed to action.
This is component for show images in Edit view:
public class EditPostImageComponent: ViewComponent
{
private IPostService _postService;
public EditPostImageComponent(IPostService postService)
{
_postService = postService;
}
public async Task<IViewComponentResult> InvokeAsync(ShowPostListItemViewModel showPostListItemViewModel)
{
return await Task.FromResult((IViewComponentResult)View("EditPostImage", _postService.GetPostGallary(showPostListItemViewModel.PostId)));
}
}
This is view component for displaying images:
#model List<DataLayer.Models.ViewModels.Post.ShowPostListItemViewModel>
#foreach (var item in Model)
{
<div class="col-lg-4 mb-4">
#if (item.ImageName != null)
{
<form method="post" asp-area="Admin" asp-controller="Post" asp-action="DeletePostImg">
<input type="hidden" asp-for="#item.PostId" />
<input type="hidden" asp-for="#item.Title" />
<input type="hidden" asp-for="#item.Description" />
<input type="hidden" asp-for="#item.ImageName" />
<div class="blog-item position-relative overflow-hidden rounded mb-2">
<img id="imgPost" class="img-fluid thumbnail" src="/img/post/#item.Title/#item.ImageName" alt="">
<br />
<br />
#*<a asp-controller="Post" asp-action="DeletePostImg"
asp-route-id="#item.PostId" class="btn btn-danger btn-sm">Delete</a>*#
<input type="submit" class="btn btn-danger btn-sm" value="Delete" />
</div>
</form>
}
else
{
<div class="blog-item position-relative overflow-hidden rounded mb-2">
<img id="imgAvatar" class="thumbnail" src="/UserAvatar/Defult.jpg" />
</div>
}
</div>
This is action method for delete images from database directly.
[HttpPost]
public void DeletePostImg(ShowPostListItemViewModel showPostListItemViewModel)
{
_postService.DeletePostImage(showPostListItemViewModel);
}
When I debug, I get a null or zero value for input hidden fields. in view,in similar circumstances these parameters is sent to the controller correctly.
Where is the problem from? Please help me
Thanks a lot
You could press F12 to check the name attribute of the input box,in your case,the name was item.PostId but in your controller the name of the parameter is showPostListItemViewModel ,the name don't match,so it bind failed
You could try as below in your view component:
#foreach (var showPostListItemViewModel in Model)
{
<form method="post" asp-controller="Home" asp-action="Post">
<input type="hidden" asp-for="#showPostListItemViewModel.PostId">
<br />
<input type="hidden" asp-for="#showPostListItemViewModel.Description">
<div class="blog-item position-relative overflow-hidden rounded mb-2">
<input type="submit" value="Submit" />
</div>
</form>
}
The Result:

How can I submit ASP,NET MVC listbox selections outside of the html form?

I have a basic ASP.NET MVC3 view like this:
#Html.Label("Administrative Options");
<br />
#Html.ListBoxFor(m => m.SelectedUsers, Model.Users)
<br />
using (Html.BeginForm("AssignAdmins", "Account"))
{
<div id="MakeAdminsbtn">
<input id="MakeAdmins" type="submit" value="Assign Administrators" onclick="return confirm('Are you sure you want to Admin?');" />
</div>
}
<br />
using (Html.BeginForm("RevokeAdmins", "Account"))
{
<div id="RemAdminsbtn">
<input id="RemAdmins" type="submit" value="Revoke Administrators" onclick="return confirm('Are you sure you want to De-Admin?');" />
</div>
}
<br />
using (Html.BeginForm("DeleteAccounts", "Account"))
{
<div id="DelAcctbtn">
<input id="DelAcct" type="submit" value="Delete Accounts" onclick="return confirm('Are you sure you want to Delete?');" />
</div>
}
Each button is in it's own form because I think that's what I have to do in order to submit to different actions?
The problem I'm having is that the returned model does not contain the SelectedUsers from the ListBoxFor unless that statement is inside the form used by the submit button.
How can I get the model appropriately populated with the selected users for each of the given submit options while only displaying a single ListBox?
You could use only one ActionMethod and there base on witch button is clicked to call that action that you nead example:
#using (Html.BeginForm("Index", "Home"))
{
<div>
#Html.ListBoxFor(m => m.SelectedUsers, Model.Users)
<input id="MakeAdmins" type="submit" name="btnSubmit" value="Assign Administrators" onclick="return confirm('Are you sure you want to Admin?');" />
<input id="RemAdmins" type="submit" name="btnSubmit" value="Revoke Administrators" onclick="return confirm('Are you sure you want to De-Admin?');" />
<input id="DelAcct" type="submit" name="btnSubmit" value="Delete Accounts" onclick="return confirm('Are you sure you want to Delete?');" />
</div>
}
and then in your controller
[HttpPost]
public ActionResult Index(string btnSubmit, FormCollection collection)
{
//btnSubmit this is the button that is clicked.
return View();
}
Sorry for my bad English.

How can I Add Custom Validation in Kendo Grid Popup

How can I add validation for minimum length to a Textbox and display custom error messages?
I want validation for the following:
UserName to have a minimum length of 6
Password and Confirm Password to match
Address1 is required
Here is the code for the popup template. The specified minlength in the template is not working but the maxlength is working properly.
<script id="popup_editor" type="text/x-kendo-template">
<table cellpadding="0" cellspacing="0">
<tr>
<td>
<label for="UserName"><b>UserName*</b></label>
</td>
<td>
<div class="control-row">
<input type="text"
name="UserName"
id="UserName"
class="k-input k-textbox"
required
**minLength**="6"
maxlength="8"
pattern="[a-zA-Z0-9]+"
validationMessage="Please enter username"/>
<span class="k-invalid-msg" data-for="UserName" ></span>
</div>
</td>
<td></td>
<td></td>
</tr>
<tr>
<td>
<div>
<label for="Password"><b>Password*</b></label>
</div>
</td>
<td>
<div class="k-edit-label">
<input type="password"
id="Password"
name="Password"
class="k-input k-textbox"required
validationMessage="Please enter Password"/>
<span class="k-invalid-msg" data-for="Password"></span>
</div>
</td>
<td>
<div>
<label for="ConfirmPassword" style=""><b>Confirm Password</b></label>
</div>
</td>
<td>
<div class="k-edit-label">
<input type="password"
id="ConfirmPassword"
name="ConfirmPassword"
class="k-input k-textbox"required
validationMessage="Please enter Confirm Password"/>
</div>
</td>
</tr>
<tr>
<td>
<div>
<label for="Company_Name"><b>Company Name*</b></label>
</div>
</td>
<td>
<div class="k-edit-label">
<input name="Company_Name"
id="Company_Name"
required
pattern="[a-zA-Z0-9]+"
validationMessage="Please enter Valid CompanyName"/>
</div>
</td>
<td></td>
<td></td>
</tr>
<tr>
<td>
<div>
<label for="First_Name"><b>First Name*</b></label>
</div>
</td>
<td>
<div class="k-edit-label">
<input type="text"
name="First_Name"
id="First_Name"
data-type="string"
data-bind="value:First_Name"
class="k-input k-textbox" required
pattern="[a-zA-Z]+"
validationMessage="Please enter FirstName"/>
</div>
</td>
<td>
<div>
<label for="Last_Name"><b>Last Name*</b></label>
</div>
</td>
<td>
<div class="k-edit-label">
<input type="text"
id="Last_Name"
name="Last_Name"
class="k-input k-textbox" required
pattern="[a-zA-Z]+"
validationMessage="Please enter LastName"/>
</div>
</td>
</tr>
<tr>
<td>
<div>
<label for="Address1"><b>Address1*</b></label>
</div>
</td>
<td>
<div class="k-edit-label">
<textArea style="resize: none;"
rows="5"
cols="18"
name="Address1"
maxlength="150"
id="Address1" required
pattern="[a-zA-Z0-9]+"
validationMessage="Please enter Address">
</textarea>
</div>
</td>
</tr>
</table>
You can add custom validation for popup editing within the dataSource of your grid.
var dataSource = new kendo.data.DataSource({
transport: {
...
},
schema: {
model: {
id: "UserName",
fields: {
UserName: {}
Password: {}
ConfirmPassword: {}
Company_Name: {}
First_Name: {}
Last_Name: {}
Address1: {
validation: {
minLength: function (input) {
if (input.is("[name=UserName]")) {
return input.val().length >= 6;
}
return true;
},
match: function (input) {
if (input.is("[name=ConfirmPassword]")) {
return input.val() == $("#Password").val();
}
return true;
}
}
}
}
}
}
});
There are a few things to respect:
The validation runs for ALL input elements within your popup, therefore
you only have to define it for ONE of the fields in your model. Which one does not matter.
you have to check which input element is checked in the current run, which does the if statement in my example.
you have to append a return true at the end of each and every rule you define or otherwise you'll get an error message for every input you're not explicitly checking. If there's no return value passed, kendo automatically assumes the check had a false result.
Every validation rule needs its own validation message or otherwise your validation tooltip box will only display a warning logo without any text. You can add it as an html attribute (data-{validation rule}-msg) in your input elements, like this:
<input type="text"
name="UserName"
id="UserName"
class="k-input k-textbox"
required
maxlength="8"
pattern="[a-zA-Z0-9]+"
validationMessage="Please enter username"
data-minLenght-msg="Username must be at least 6 characters"/>
<input type="password"
id="ConfirmPassword"
name="ConfirmPassword"
class="k-input k-textbox"
required
validationMessage="Please enter Confirm Password"
data-match-msg="Password and confirmation must be equal"/>
Hope this helps
In rules add this:
match: function (input) {
if ((input.is('[name=\'Password\']') || input.is('[name=\'ConfirmPassword\']'))&& $('#ConfirmPassword').length !== 0) {
if ($('#Password').val().length > 0 && $('#ConfirmPassword').val().length > 0) {
if (input.is('[name=\'Password\']')) {
return input.val() === $('#ConfirmPassword').val();
}
else if (input.is('[name=\'ConfirmPassword\']')) {
return input.val() === $('#Password').val();
}
}
}
return true;
},
minLength: function (input) {
if (input.is("[name=UserName]")) {
return input.val().length >= 6;
}
return true;
},
requiredAddress: function (input) {
if (input.is("[name=Address1]")) {
return $('#Address1').val() !== '' ? false : true;
}
return true;
}

Dynamically added input elements are not preserving entered data when creating new input elements

I've created a test app to learn more about asp.net mvc. The app is supposed to allow the use to add an "unlimited" number of inputs via jQuery using partial views and editor templates. I've managed to get the adding of the new input elements but I'm having issues preserving the entered data from the user when adding newer input elements.
My strongly-typed view
#model TestApp.Models.ItemViewModel
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<div class="editor-label">
#Html.LabelFor(model => model.ItemName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ItemName)
#Html.ValidationMessageFor(model => model.ItemName)
</div>
<div class="editor-label">
Click to add rates
</div>
<div class="editor-field">
Add Rate
<input type="hidden" value="0" id="rateCounter" />
</div>
<br />
<span id="itemRates"></span>
<p>
<input type="submit" value="Save" />
</p>
}
My javascript
When the user clicks on the NewRate element above, I fire this jQuery to get the partial view. I also keep track of the number of rows created by the user via a hidden element rateCounter which I increment everytime the click event fires.
$("#NewRate").click(function () {
var count = parseInt($("#rateCounter").val());
$("#rateCounter").val(count + 1);
$.ajax({
type: 'GET',
url: '/Item/AddRate',
data: {
rateCount: $("#rateCounter").val()
},
success: function (data) {
$('#itemRates').html(data);
}
});
});
My controller
This accepts the number of rows to create and passes to the partial view.
public PartialViewResult AddRate(int rateCount)
{
var itemVM = new ItemViewModel { Rates = new List<ItemRatesViewModel>() };
for (int i = 0; i < RateCount; i++)
{
itemVM.Rates.Add(new ItemRatesViewModel());
}
return PartialView("_ItemRates", itemVM);
}
My strongly-typed partial view
The partial view just uses an editor template
#model TestApp.Models.ItemViewModel
#Html.EditorFor(model => model.Rates)
My editor template
The editor template basically displays each rate
#model TestApp.Models.ItemRatesViewModel
<tr>
<td>
#Html.EditorFor(model => model.Rate)
#Html.ValidationMessageFor(model => model.Rate)
</td>
<td>
#Html.EditorFor(model => model.StartDate)
#Html.ValidationMessageFor(model => model.StartDate)
</td>
<td>
#Html.EditorFor(model => model.EndDate)
#Html.ValidationMessageFor(model => model.EndDate)
</td>
</tr>
On the first click
Using Google Chrome's developer tools, I see that the response is like this. Which should be correct. When I submit the form, the model binder picks up the entered data.
<tr>
<td>
<input class="text-box single-line" data-val="true" data-val-number="The field Rate must be a number." data-val-required="*" id="Rates_0__Rate" name="Rates[0].Rate" type="text" value="0.00" />
<span class="field-validation-valid" data-valmsg-for="Rates[0].Rate" data-valmsg-replace="true"></span>
</td>
<td>
<input data-datepicker-future="True" data-val="true" data-val-required="*" id="Rates_0__StartDate" name="Rates[0].StartDate" type="text" value="01/01/0001" />
<span class="field-validation-valid" data-valmsg-for="Rates[0].StartDate" data-valmsg-replace="true"></span>
</td>
<td>
<input data-datepicker-future="True" data-val="true" data-val-required="*" id="Rates_0__EndDate" name="Rates[0].EndDate" type="text" value="01/01/0001" />
<span class="field-validation-valid" data-valmsg-for="Rates[0].EndDate" data-valmsg-replace="true"></span>
</td>
</tr>
On the second click
The entered data on the first set of input element (index [0]) is discarded and replaced by newly initialized one since I am using $('#itemRates').html(data); in my javascript instead of $('#itemRates').append(data);. Below is what I get. When I submit the form, the model binder picks up the entered data correctly in the Rates collection of the view model.
<tr>
<td>
<input class="text-box single-line" data-val="true" data-val-number="The field Rate must be a number." data-val-required="*" id="Rates_0__Rate" name="Rates[0].Rate" type="text" value="0.00" />
<span class="field-validation-valid" data-valmsg-for="Rates[0].Rate" data-valmsg-replace="true"></span>
</td>
<td>
<input data-datepicker-future="True" data-val="true" data-val-required="*" id="Rates_0__StartDate" name="Rates[0].StartDate" type="text" value="01/01/0001" />
<span class="field-validation-valid" data-valmsg-for="Rates[0].StartDate" data-valmsg-replace="true"></span>
</td>
<td>
<input data-datepicker-future="True" data-val="true" data-val-required="*" id="Rates_0__EndDate" name="Rates[0].EndDate" type="text" value="01/01/0001" />
<span class="field-validation-valid" data-valmsg-for="Rates[0].EndDate" data-valmsg-replace="true"></span>
</td>
</tr>
<tr>
<td>
<input class="text-box single-line" data-val="true" data-val-number="The field Rate must be a number." data-val-required="*" id="Rates_1__Rate" name="Rates[1].Rate" type="text" value="0.00" />
<span class="field-validation-valid" data-valmsg-for="Rates[1].Rate" data-valmsg-replace="true"></span>
</td>
<td>
<input data-datepicker-future="True" data-val="true" data-val-required="*" id="Rates_0__StartDate" name="Rates[1].StartDate" type="text" value="01/01/0001" />
<span class="field-validation-valid" data-valmsg-for="Rates[1].StartDate" data-valmsg-replace="true"></span>
</td>
<td>
<input data-datepicker-future="True" data-val="true" data-val-required="*" id="Rates_0__EndDate" name="Rates[1].EndDate" type="text" value="01/01/0001" />
<span class="field-validation-valid" data-valmsg-for="Rates[1].EndDate" data-valmsg-replace="true"></span>
</td>
</tr>
FINALLY, my question
Is there a way to get just the 2nd row (index [1]) in the generated response then use jQuery's append instead of replacing the whole html with the new rows? What is the correct way of doing this? I know I'm close but a little guidance would go a long way. :)
I probably wouldn't be going back to the server and getting the whole view with all the rows this way.
The way MVC parses the sent data once posting the form is the array of elements sent back (specified by the number in [] brackets in the name attribute of the elements.
The way I have done it in the past is cloned the row by jquery and used a regex function to replace the[0] with [1] and cleared the values out also. Then just append it.
This will also save you from doing a call to the server every time the add is clicked.

How to add an increment value for each id attribute within the div contents with cloned jQuery object

Having a hard time figuring out how to add an increment value for each id attribute within the div contents with cloned jQuery object.
http://jsfiddle.net/hvK8d/
===================== HTML=====================
<div class="upload-file-container">
<div class="uploadFile left clearfix">
<input type="file" id="FileUpload1">
<table id="RadioButtonList1">
<tbody>
<tr>
<td><input type="radio" value="Resume" id="RadioButtonList1_1">
<label for="RadioButtonList1_1">Resume</label></td>
<td><input type="radio" value="Letter of Recommendation" id="RadioButtonList1_2">
<label for="RadioButtonList1_2">Letter of Recommendation</label></td>
<td><input type="radio" value="Other" id="RadioButtonList1_3">
<label for="RadioButtonList1_3">Other</label></td>
</tr>
</tbody>
</table>
</div>
Remove </div>
<div class=""><a class="plus" href="javascript:;">plus one</a></div>
===================== JQUERY =====================
//Cloning upload file control
$('.remove').live('click', function () {
if (confirm("Are you sure you wish to remove this item?")) {
$(this).parent().slideUp('fast', function () {
$(this).remove();
});
}
return false;
});
$('.plus').click(function () {
console.log('cloning');
var divCloned = $('.upload-file-container:first').clone();
divCloned.hide().insertAfter('.upload-file-container:last').slideDown('fast');
return false;
});
For the sake of completeness I will put here a small solution making use of a "template."
A class for hiding the template:
.upload-file-container.template {
display: none;
} ​
A small function to do replacements:
$.fn.template = function(variables) {
return this.each(function() {
this.innerHTML = this.innerHTML.replace(/{{(.+)}}/g, function(match, variable) {
return variables[variable];
});
return this;
});
};
A template:
<div class="upload-file-container template">
<div class="uploadFile left clearfix">
<input type="file" id="FileUpload{{id}}">
<table id="RadioButtonList{{id}}"><tbody>
<tr>
<td>
<input type="radio" value="Resume" id="RadioButtonList{{id}}_1">
<label for="RadioButtonList{{id}}_1">Resume</label>
</td>
</tr>
</tbody></table>
</div>
</div>
Usage:
var count = 0;
var divCloned = $(".upload-file-container.template")
.clone()
.removeClass("template")
.template({
id: count++
});
Instead of using numbered IDs, you should be using the array-like notation (e.g. RadioButtonList[]) in the name attribute, and wrap your labels around the inputs:
<td>
<label for="RadioButtonList1_1">
<input type="radio" value="Resume" name="RadioButtonList1[]">
Resume
</label>
</td>
<td>
<label for="RadioButtonList1_2">
<input type="radio" value="Letter of Recommendation" name="RadioButtonList2[]">
Letter of Recommendation
</label>
</td>
<td>
<label for="RadioButtonList1_3">
<input type="radio" value="Other" name="RadioButtonList3[]">
Other
</label>
</td>
P.S. You should also consider using a more descriptive name than RadioButtonList.

Resources