I'm new in ASP.NET MVC. I created a login form and created two text boxes, then I used requirements attributes for them that if the were empty or wrong make errors.
Also I created a button link by #Html.ActionLink("", "") helper, so when I click it, without checking the validation of text boxes goes to next page. Would you please help me how can I fix this problem?
view code
controller code
#using (Html.BeginForm("CheckLogin", "Login", FormMethod.Post))
{
#Html.ValidationSummary(true)
#Html.ValidationMessageFor(model => model.username, null, new { #class = "required", #style = "color : red" })
<div class="form-group has-feedback">
#Html.TextBoxFor(model => model.username, null, new { #class = "form-control", placeholder = "Enter User Name" })
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
</div>
#Html.ValidationMessageFor(model => model.userpassword, null, new { #class = "required", #style = "color : red" })
<div class="form-group has-feedback">
#Html.PasswordFor(model=>model.userpassword, new { #class = "form-control", placeholder = "Enter Password" })
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
</div>
<div class="row">
<div class="col-xs-4">
<button type="submit" class="btn btn-primary btn-block btn-flat">Sign In</button>
</div>
<!-- /.col -->
</div>
}
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
i think you simply copy and paste it
i think you should use
#Html.ActionLink("linkname", "Action name", "controller name")
and link is created .
In case if you are using Asp.Net Core you can use built-in tag builders:
<a class="btn btn-primary" asp-controller="<Controller name>" asp-action="<action name>" asp-route-<parameterName>="<parameter value>">Click Me!</a>
btn btn-primary is a bookstrap class.
You need to create a form in order to get correct validation
#model yourmodel
#using (Html.BeginForm("..", "...", FormMethod.Post))
{
#Html.ValidationSummary(true)
...
// your fields here now like
#Html.EditorFor(m=>m.prop)
#Html.ValidationFor(m=>m.prop)
//your submit button here
<input type=submit>
}
and at the end of the page don't forget to include Jquery validation scripts
Related
I am currently dealing with a problem i have been trying to solve through 'learn by doing', but i am getting no where and almost on the edge of leaving it alone and let it run the way i know it works.
The way it works now:
Currently i have scarfolded the whole identity area from asp.net, the login and registration both runs in separate views
The way i want it:
The login should be placed in the navigation bar, but to do so i need the model to paste in the username & password. If i use a model in _LoginPartial the registration does not work. Currently i can move the login form to navigation bar and login/logout as normal using the form, but then i am no longer allowed to register as it want the loginmodel for my registration page.
I can add other code if needed, but they are more or less default scarfolded classes.
_LoginPartial
#inject SignInManager<User> SignInManager
#inject UserManager<User> UserManager
#using Microsoft.AspNetCore.Identity
#using TVScreenViewer.Models.Identity
#model TVScreenViewer.Areas.Identity.Pages.Account.LoginModel
#if (SignInManager.IsSignedIn(User))
{
<form asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="#Url.Action("Index", "Home", new {area = ""})" method="post" id="logoutForm" class="navbar-nav navbar-right">
<ul class="navbar-nav navbar-right">
<li class="nav-item">
<a class="nav-link" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">Hello #UserManager.GetUserAsync(User).Result.Name!</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown1" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Menu
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown1">
<a class="dropdown-item" href="#">Settings</a>
<div class="dropdown-divider"></div>
<button type="submit" class="btn btn-secondary btn-block" style="padding: 4px 24px; text-align: left;">Logout</button>
</div>
</li>
</ul>
</form>
}
else
{
<form asp-area="Identity" asp-page="/Account/Login" method="post" class="navbar-nav navbar-right">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="row">
<div style="margin: 0rem 1rem">
<input class="form-control form-control-sm" asp-for="Input.Username"/>
<span asp-validation-for="Input.Username" class="text-danger"></span>
</div>
<div>
<input class="form-control form-control-sm" asp-for="Input.Password"/>
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
<div style="margin: 0rem 1rem">
<button type="submit" class="btn btn-primary btn-sm">Log in</button>
</div>
</div>
</form>
#*<a asp-area="Identity" asp-page="/Account/Login">Login</a>*#
<a asp-area="Identity" asp-page="/Account/Register">Register</a>
}
#section Scripts {
<partial name="_ValidationScriptsPartial"/>
}
Finding UI:
Here's a sample in bootstrap 3, which is a login form as your need:
https://getbootstrap.com/docs/3.4/examples/jumbotron/
and another in v4 which is a search bar:
https://getbootstrap.com/docs/4.3/examples/sticky-footer-navbar/
you can inspect element:
and copy this part (depending on version it may differ
Coding (The Actual Issue)
The login it self is not something special
you can use old html form , or MVC beginForm and set the action to send data to Account page... authentication perform over server, and server assign cookies, so it doesn't matter as long as you send the data to the server. and you need two input depending on your model, can be Username & Password,
Also these: asp-page and asp-for ... are new to me, i do not remember seeing them anywhere, make sure you are using either #Html.TextBoxFor(m => m.Email, new { #class = "form-control" }) kind of rezor supported field, or <input name=""> html input with name attribute
Also here's default form by Microsoft on .NetBased MVC:
#using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
Default Microsoft Code for Login
Note
I noticed you are using Core MVC due to this line #using Microsoft.AspNetCore.Identity, which it's template may be different from .netframwork template, but the concept should be same
#using OpenAndDelete.Models
#model LoginViewModel
#{
ViewBag.Title = "Log in";
}
<h2>#ViewBag.Title.</h2>
<div class="row">
<div class="col-md-8">
<section id="loginForm">
#using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Use a local account to log in.</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Email, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Password, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Password, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
#Html.CheckBoxFor(m => m.RememberMe)
#Html.LabelFor(m => m.RememberMe)
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Log in" class="btn btn-default" />
</div>
</div>
<p>
#Html.ActionLink("Register as a new user", "Register")
</p>
#* Enable this once you have account confirmation enabled for password reset functionality
<p>
#Html.ActionLink("Forgot your password?", "ForgotPassword")
</p>*#
}
</section>
</div>
<div class="col-md-4">
<section id="socialLoginForm">
#Html.Partial("_ExternalLoginsListPartial", new ExternalLoginListViewModel { ReturnUrl = ViewBag.ReturnUrl })
</section>
</div>
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
The resource cannot be found.
Requested URL: /Home/Home/Signup_User
However it should be /Home/Signup_User
where Home is the controller and Signup_User is the function in Home Controller.I have checked the spelling its correct.
My Sign Up Form as follows.
<form action="~/Home/Signup_User" method="post" enctype="multipart/form-data">
#Html.AntiForgeryToken()
<div class="row">
<div class="large-6 columns">
<label>
Enter Name
#Html.EditorFor(model => model.username, new { htmlAttributes = new { #class = "form-control" } })
</label>
</div>
<div class="large-6 columns">
<label>
Enter Age
#Html.EditorFor(model => model.age, new { htmlAttributes = new { #class = "form-control" } })
</label>
</div>
<div class="large-6 columns">
<label>
Enter Email Address
#Html.TextBoxFor(model => model.email, new { #class = "large-12", placeholder = "xyz#gmail.com", type = "email" })
</label>
</div>
<div class="large-6 columns">
<label>
Enter Password
#Html.PasswordFor(model => model.password, new { })
</label>
</div>
</div>
<br />
<hr />
<button type="submit" class="button tiny right" style="margin-left:5px;color:white;">Submit</button>
Cancel }
<a class="close-reveal-modal" aria-label="Close">×</a>
</form>
FormExtensions (with Controller and ActionName)
#using (Html.BeginForm("Signup_User", "Home", FormMethod.Post))
{
}
FormExtensions (with Controller , ActionName and Area )
#using (Html.BeginForm("Signup_User", "Home", FormMethod.Post, new { area = "AreaName" }))
{
}
Try replacing
action="~/Home/Signup_User"
with
action="#Url.Action("Signup_User", "Home")"
You just need to add Controller name slash action name, no need to add ~
Refer following code for Solution 1:
<form action="/Home/Signup_User" method="post" enctype="multipart/form-data">
//Add rest of your code
</form>
Else, use MVC's built in HTML helper to render the form and put your rest of the code into same.
#using (Html.BeginForm("Signup_User", "Home", FormMethod.Post))
{
// Add your rest of code
}
Above code will generate empty tag.
It seems you are using relative path in action URL . that's why Home Added twice like this.
/Home/Home/Signup_User
Asp.net MVC come up with beautiful Form Extensions.Just you need to specify Controller Name, Action Method Name and Area name if any.
for e.g.
#using (Html.BeginForm("actionName", "controllerName", new {area = "AreaName"}))
In your case
ActionName :"Signup_User"
ControllerName:"Home"
Assuming, you don't have no area defined. replace your piece code with below snippet. it will resolve your issue.
CODE:
#using (Html.BeginForm("Signup_User", "Home"))
#Html.AntiForgeryToken()
<div class="row">
<div class="large-6 columns">
<label>
Enter Name
#Html.EditorFor(model => model.username, new { htmlAttributes = new { #class = "form-control" } })
</label>
</div>
<div class="large-6 columns">
<label>
Enter Age
#Html.EditorFor(model => model.age, new { htmlAttributes = new { #class = "form-control" } })
</label>
</div>
<div class="large-6 columns">
<label>
Enter Email Address
#Html.TextBoxFor(model => model.email, new { #class = "large-12", placeholder = "xyz#gmail.com", type = "email" })
</label>
</div>
<div class="large-6 columns">
<label>
Enter Password
#Html.PasswordFor(model => model.password, new { })
</label>
</div>
</div>
<br />
<hr />
<button type="submit" class="button tiny right" style="margin-left:5px;color:white;">Submit</button>
Cancel }
<a class="close-reveal-modal" aria-label="Close">×</a>
</form>
One reason this could occur is if you don't have a start page set under your web project's properties. So do this:
Right click on your mvc project
Choose "Properties"
Select the "Web" tab
Select "Specific Page"
Assuming you have a controller called HomeController and an action method called Index, enter "home/index" in to the text box corresponding to the "Specific Page" radio button.
Now, if you launch your web application, it will take you to the view rendered by the HomeController's Index action method.
I have two buttons but I'm only able to validate one. When the user clicks add and the entire form is not filled out then they get error message but if they click finish instead of giving error messages, it goes to another page but I want to give the error before going to that page. This is what I have so far for one:
#model student.Models.Student
<h2>Student Record</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Issue</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.studentNumber, htmlAttributes: new { #class = "col-md-2" })
#Html.EditorFor(model => model.studentNumber, new { htmlAttributes = new { #readonly = "readonly", #id = "reqnum", #class = "form-control" } })
</div>
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "col-md-2" })
#Html.ValidationMessageFor(model => model.name, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.Label("Processed by:", htmlAttributes: new { #class = "col-md-2" })
#Html.DropDownListFor(model => model.processedbyDetails.employeeNum, new SelectList(ViewBag.StoresReps, "Value", "Text"), new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.processedbyDetails.employeeNum, "", new { #class = "text-danger" })
</div>
#* -- MANY OTHER INPUTS -- *#
<div class="form-group">
<div class="col-md-offset-4 col-md-12">
<input type="submit" value="Add" name="Add" class="btn btn-default" width="89" />
<input type="button" value="Finish" name="Issue" margin="50px" onclick="location.href='#Url.Action("ViewIssue", "Issue")' " class="btn btn-default" />
<input type="button" value="Cancel" name="Cancel" margin="50px" onclick="location.href='#Url.Action("Cancel", "Issue")' " class="btn btn-default" />
</div>
</div>
</div>
}
Edit
#{
ViewBag.Title = "Student Item";
}
<!-- JS includes -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/jquery.validate.min.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/mvc/4.0/jquery.validate.unobtrusive.min.js"></script>
<script type="text/javascript">
<script type="text/javascript">
function onFinishClick() {
if ($('form').valid()) {
location.href = '#Url.Action("ViewIssue", "Issue")';
}
return false;
}
</script>
<input type="button" value="Finish" name="Issue" margin="50px" onclick="onFinishClick()" class="btn btn-default" />
You're using MVC, so just annotate your ViewModel and submit the form with the built in functionality that the framework supplies for you.
public class Student
{
[StringLength(100)]
[DisplayName("Student Name")]
[Required(ErrorMessage = "Please enter a Student Name")]
public string Name { get; set; }
[StringLength(100)]
[DisplayName("Student Number")]
[Required(ErrorMessage = "Please enter a Student Number")]
public string StudentNumber { get; set; }
// etc...
}
Your form should also have the name of the Action you're trying to POST to...
#using (Html.BeginForm("AddOrFinish", "HomeController", FormMethod.Post, new { role = "form" }))
You can't validate against the data annotations on your viewmodel in MVC from a button that's not of type submit (well, maybe you can, but probably more work).
You should then mark both buttons as type submit, then interrogate the name of the button that was clicked once it is sent over.
<div class="form-group">
<div class="col-md-offset-4 col-md-12">
<input type="submit" value="Add" name="add" class="btn btn-default" width="89" />
<input type="submit" value="Finish" name="issue" margin="50px" class="btn btn-default" />
<input type="button" value="Cancel" name="Cancel" margin="50px" onclick="location.href='#Url.Action("Cancel", "Issue")' " class="btn btn-default" />
</div>
</div>
Then in your controller, create a method with this signature. Since you have two submit buttons, the values of the button will be sent along in the request and you can interrogate it. It will look something like this...
[HttpPost]
public ActionResult AddOrFinish(Student model, string add, string issue)
{
if (!ModelState.IsValid)
{
return RedirectToAction("PageImOnNow", model);
}
if (!string.IsNullOrEmpty(add))
{
// do your add logic
// redirect to some page when user clicks "Add"
return RedirectToAction("WhateverPageYouWant");
}
else
{
// do your finish logic
// redirect to ViewIssue page when user clicks "Finish"
return RedirectToAction("ViewIssue");
}
}
More information here -
Handling multiple submit buttons on a form in MVC
Best Practices for ViewModel validation in MVC
Here's the view which I'm using to enter the multiline article
I wish that you can also told me how to save the text properties such as bold italic too because it makes me very confused.
#model WEBSITI.Models.article
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm( "Create", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="form-group">
#Html.LabelFor(model => model.bodyofarticle, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.bodyofarticle, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.bodyofarticle, "", new { #class = "text-danger" })
</div>
<input type="file" id="file" name="file" />
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
When a form is submitted, the asp.met mvc framework will inspect the request body to see whether it has any potentially dangerous content as HTML markup(Think about script injection). If it detects any dangerous content,the Request Validation module will throw an error. This is by design
To explicitly allow the form posting with Html tags inside the property value, you may decorate your specific property with the AllowHtml attribute
public partial class article
{
[AllowHtml]
public string bodyofarticle { set; get; }
//other properties here
}
This will tell the framework to exclude this property from the above request validation.
I suggest you follow PascalCasing while writing C# code ( Ex : Article instead of article)
I´m working on ASP .NET MVC 5 application and now I´m implementing newsletter functionality. I have master (parent view) with all stuff and on this view there is also box with input field for email and submit button. After click on this button, controller method insert this e-mail to subscribers tab. I´ve got GET/POST method and PartialView for this Newsletter (all newsletter´s code is in separate area).
Everything works fine, there is only one problem. On master page I have another submit button (for submitting search string) so everytime after submitting search string, code also submit newsletter form.
Is there any solution to separate this two submit buttons and way to not refresh whole page after submit newsletter (PartialView) form?
Here is my Newsletter PartialView called _SignIn
#using (Html.BeginForm())
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.email, htmlAttributes: new {#class = "control-label col-md-12", style="text-align: left; padding-left: 30px;"})
<div class="col-md-12" align="center">
#Html.EditorFor(model => model.email, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.email, "", new {#class = "text-danger"})
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.NewsletterType, htmlAttributes: new { #class = "control-label col-md-12", style = "text-align: left; padding-left: 30px;" })
<br />
<div class="col-md-12" align="center">
#Html.EnumDropDownListFor(model => model.NewsletterType, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.NewsletterType, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-4 col-md-10" style="padding-bottom: 10px;">
<input type="submit" value="Prihlásiť" class="btn btn-success" />
</div>
</div>
</div>
Thank you for any response!
You will only achieve this using ajax calls, with that, you do not need to refresh the whole page.
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.email, htmlAttributes: new {#class = "control-label col-md-12", style="text-align: left; padding-left: 30px;"})
<div class="col-md-12" align="center">
#Html.EditorFor(model => model.email, new {htmlAttributes = new {#class = "form-control", id = "emailTxt"}})
#Html.ValidationMessageFor(model => model.email, "", new {#class = "text-danger"})
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.NewsletterType, htmlAttributes: new { #class = "control-label col-md-12", style = "text-align: left; padding-left: 30px;" })
<br />
<div class="col-md-12" align="center">
#Html.EnumDropDownListFor(model => model.NewsletterType, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.NewsletterType, "", new { #class = "text-danger", id = "ddlType" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-4 col-md-10" style="padding-bottom: 10px;">
<button type="button" class="btn btn-success btn-newsletter"></button>
</div>
</div>
</div>
<script>
$(function(){
var model = {
email: $('.emailTxt').text();
NewsletterType: $('.ddlType :selected').text();
}
$(.btn-newsletter).click(function(){
$.ajax({
url: url,
type: 'POST',
data: model,
beforeSend: function(xhr){xhr.setRequestHeader('__RequestVerificationToken', $('body').find('input[name="__RequestVerificationToken"]'));},
statusCode: {
200: function (data) { success(data); },
500: function (erro) { error(erro); }
}
});
});
});
</script>
Add name attribute to your buttons, and use the value in your controller to distinguish which button was invoked.
<button type="submit" id="btnSave" name="Command" value="Save">Save</button>
<button type="submit" id="btnSubmit" name="Command" value="Submit">Submit</button>
public ActionResult YourAction(Model model, string Command)
{
if(Command == "Save") {}
}
Refer to Handling multiple submit buttons for more info.
To prevent the full postback (refresh) you could use AJAX
You have to have two separate forms to handle each submission or handle it through some form of Javascript. I'd suggest using 2 separate forms. Put the search string submission in the parent view since it should be on all the pages and close the form. Then you can render your partial view for the newsletter subscription with a form inside of it.
Basically:
Parent view
...
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
...
<!-- Search string input field and submit button -->
...
</div>
}
<div>
#Html.RenderPartial("_SignUp")
</div>
...
_SignUp Partial view
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
...
<!-- Subscriber email input and submit -->
...
</div>
}