Hi I was learning this tutorial to learn MVC with entity framework. I found that in this example, it has 3 parameters for edit method submitted by beginform() in view page.
public ActionResult Edit(int id, FormCollection formCollection, string[] selectedCourses)
{....}
controller
#using (Html.BeginForm())
{
...
<input type="submit" value="Save" />
}
view
I can guess 'string[] selectedCourse' parameter is from the checkbox inside of the fieldset in the form. But I'm still not sure about where does 'int id' comes from. Please give me an idea about how httppost works in MVC
If you look at the URL from the tutorial, you'll see its /Instructor/Edit/1. 1 is the ID parameter and it maps to the ID in the action method when the form is submitted.
Related
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.
I currently have a view containing a form. In the form there is a link which allows the user to view one of the textboxes in a separate tab/window.
My question is how do I retrieve the text from that textbox and pass only that text to a controller?
Currently I have the below code
(which returns:
The request filtering module is configured to deny a request where the query string is too long
)
View
#using (Html.BeginForm("PostValuation", "Property", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
....Some data (part of a view model)...
View as letter
....Some data (part of a view model)...
<input type="submit" value="Pass ...Some data... using a View Model" class="btn btn-default" />
}
Controller
public ActionResult ShowLetter(string letter)
{
ViewBag.Letter = letter;
return View();
}
I understand there is a limit on the length of the string I can pass and after reading suggestions I see I can change the web.config to resolve the max length. But this can potentially be thousands of characters long, so I feel that altering the web.config is not the right solution. Can someone offer a better suggestion please.
I'm facing a very annoying issue in my mvc 4 application.
What I'm doing:
I have a main view (Index) and a partial view added to main view. on partial view a form is added to post data to the action in some controller but, it posts to Home controller each time.
Note: both of the controllers are on root.
Here is how my code looks like:
form on partial view:
#using (Html.BeginForm("SearchLaptop", "SearchControl", FormMethod.Post))
{
<input type="submit" value="Search">
}
Action in SearchControl controller:
[HttpPost]
public ActionResult SearchLaptop()
{
}
but on clicking the button in form it never goes to the SearchControl controller but, goes to Home controller always.
i.e. the url is supposed to be:
/SearchControl/SearchLaptop
but, it is always looks like:
/Home/SearchLaptop
Can anyone please help in this regard. Thanks
I managed to solve this issue by moving partial view to Shared folder.
If I do the following
ViewModel:
public class ToleranceInput{
public decimal Tolerance{get;set;}
}
And in my views
AssignTolerances.cshtml
#model ToleranceInput
#using (#Html.BeginForm("AssignTolerances", Tolerances", FormMethod.Post, new {#class="form-horizontal"}))
{
#Html.ValidationSummary()
#Html.Partial("_AssignOrEditTolerances", Model)
<div class="form-actions">
<button type="submit">
<i class="icon-ok icon-white"></i> Save
</button>
</div>
}
_AssignOrEditTolerances.cshtml:
#model ToleranceInput
#Html.TextBoxFor(a=>a.Tolerance)
#Html.ValidationMessageFor(a=>a.Tolerance)
The standard MVC validation works correctly. When I type in letters (instead of numbers) it shows a red error message as it should. However, in the viewmodel if I change Tolerance to a nullable decimal? it does not work correctly. if I type a non-decimal such as 'asdf' in the textbox I see a quick flash of the red validation messsage when I hit the save button, but then the POST goes through and the [HttpPost] AssignTolerances method in my controller gets executed. Why is this happening? Any ideas?
Edit: I have just found the following link. Looks like the strings get converted to nulls and the workaround looks horrible: Integer validation against non-required attributes in MVC
Have you also considered adding the check in the controller action?
[HttpPost]
public ActionResult TestPost(ToleranceInput model)
{
if(!ModelState.IsValid)
{
return View(model);
}
}
And then simply add validation into your Model, such as the [Required] attribute
Sitecore 7.1v1, most recent Glass Mapper, MVC4. When we submit the form POST, we get no layout with the return View. I'd prefer not to have to redirect to another page since this is supposed to be a wizard-like experience. This is also lightweight enough not to require Ajax, although we could use it as a last resort. I can't find who to make sure that while returning the View that we get the layout as well. I'm new to Sitecore MVC and pretty new at MVC in general. The PageBase that's referenced is a Custom Model using Glass.
We have the following Controller Rendering:
public class RegistrationController : Controller
{
[HttpGet]
public ActionResult VerifyAccount()
{
return View("~/Views/Public/Wizards/Registration/VerifyAccount.cshtml",
new SitecoreContext().GetCurrentItem<PageBase>());
}
[HttpPost]
public ActionResult CreateProfile()
{
ViewBag.Name = Request["VerificationType"];
ViewBag.Step = 2;
return View("~/Views/Public/Wizards/Registration/CreateProfile.cshtml",
new SitecoreContext().GetCurrentItem<PageBase>());
}
}
The default action for this is VerifyAccount(). This renders as expected. The initial view is as follows:
#inherits Glass.Mapper.Sc.Web.Mvc.GlassView<Public.Model.GlassModel.Primary.PageBase>
<div>
<h3>#Editable(a => a.Title)</h3>
<p>
#Editable(a => a.Description)
</p>
<hr />
#using (Html.BeginRouteForm(Sitecore.Mvc.Configuration.MvcSettings.SitecoreRouteName, FormMethod.Post))
{
#Html.Sitecore().FormHandler("Registration", "CreateProfile")
#Html.ValidationSummary(true, "Verification Not Selected.")
<fieldset>
#Sitecore.Globalization.Translate.Text("$Registration.VerificationTitle")
#{ var validations = new SitecoreContext().GetItem<GlassFrameBase>(Guid.Parse("{3694FC43-3DB7-470A-A1E9-2649856AAF10}"));}
<select id="VerType" name="VerificationType">
#foreach (var validation in validations.GetChildren<VerificationMethod>())
{
<option value="#validation.MethodValue">#validation.MethodName</option>
}
</select>
<input type="submit" value="Next" />
</fieldset>
}
This posts back to the CreateProfile() Method. This part works great. The only issue is that when it returns the view this time, it returns just the view without the layout.
The final view is as follows:
#using (Html.BeginRouteForm(Sitecore.Mvc.Configuration.MvcSettings.SitecoreRouteName, FormMethod.Post))
{
#Html.Sitecore().FormHandler()
<p>
<b>Verification Type Was: </b>#ViewBag.Name
</p>
<p>#ViewBag.Step</p>
<input type="hidden" value="ThisIsATest" name="TestHidden" id="TestHidden"/>
<input type="submit" name="back" value="Back" /><br />
<input type="submit" name="next" value="Next" />
}
Everything else is working exactly as expected but I'm missing something important that loads the Layout on the return trip.
I have noticed this before as well and I think it relates to this line:
#Html.Sitecore().FormHandler("Registration", "CreateProfile")
It seems to bypass the standard rendering pipeline and just call the target action. I have written a blog post on how you can control calls to different action on multiple controllers. this might help:
http://www.experimentsincode.com/?p=425
Try changing the return type of CreateProfile from ActionResult to PartialViewResult, and then return View("... to return PartialView("...
Also, here's a post about what you can return for Sitecore Controller Renderings.
http://mhwelander.net/2014/04/09/sitecore-controller-rendering-action-results-what-can-i-return/
I haven't looked deeply into form posting with Controller Renderings, but if the above suggestion doesn't work then maybe consider the execution lifestyle used in Sitecore MVC (mentioned in the post).