i'm trying to login through a model inc asp net MVC 5, however, i can't seem to get the data from the form using serialize, there are no errors, it just shows nothing inside data
#using (Html.BeginForm("Login", "Account", new { returnUrl = Request.QueryString["ReturnUrl"] }, FormMethod.Post, new { id = "formModal" }))
{
#Html.AntiForgeryToken();
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="container">
<div class="form-login">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Login</div>
</div>
<div class="panel-body">
<div class="form-group">
<div class="input-group mb-3">
<div class="input-group-prepend">
<div class="input-group-text">
<i class="fas fa-user"></i>
</div>
</div>
#Html.EditorFor(model => model.Username, new { htmlAttributes = new { #class = "form-control", placeholder = "Username", autofocus = true } })
#Html.ValidationMessageFor(model => model.Username, "", new { #class = "text-danger" })
</div>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<div class="input-group-text">
<i class="fas fa-lock"></i>
</div>
</div>
#Html.EditorFor(model => model.Password, new { htmlAttributes = new { #class = "form-control", placeholder = "Password" } })
#Html.ValidationMessageFor(model => model.Password, "", new { #class = "text-danger" })
</div>
<div class="form-group">
<button id="btnSubmit" type="submit" class="btn primary btn-lg">
Entrar
</button>
</div>
</div>
</div>
</div>
</div>
}
<script type="text/javascript">
$("#btnSubmit").click(function () {
debugger
var formData = $('#formModal').serialize();
$.ajax({
type: 'POST',
url: '/Account/Login',
data: formData,
async: true,
success: function (data) {
}
});
return false;
});
what am i doing wrong? i saw some videos and i did exactly the same... I can reach the controller but there is no data
this is the controller
public class AccountController : Controller
{
public ActionResult Index()
{
return PartialView("_PartialLogin");
}
[HttpPost]
public ActionResult Login(LoginViewModel model, string ReturnUrl)
{
var user = Authenticate(model);
var ticket = new FormsAuthenticationTicket(
1,
user.Id.ToString(),
DateTime.Now,
DateTime.Now.AddHours(5),
model.RememberMe,
user.Roles.Select(c => c.Nome).FirstOrDefault()
);
return Redirect(ReturnUrl);
}
}
and here is view model
public class LoginViewModel
{
[Required]
[StringLength(8)]
public string Username { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
public bool RememberMe { get; set; }
}
no matter what, i cannot seem to get data from form using jquery, it's always null when i use serialize
EDIT
I forgot to mention, this form is inside a partialview, in a modal
#model Logistica.ViewModels.LoginViewModel
#{
Layout = null;
}
<link href="~/Content/bootstrap.css" rel="stylesheet" />
<link href="~/Content/login.css" rel="stylesheet" />
<link href="~/Content/fontawesome-all.css" />
<script src="~/scripts/jquery-3.3.1.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
<script src="~/Scripts/bootstrap.js"></script>
<script src="~/Scripts/fontawesome/all.js"></script>
<!-- Modal -->
<div class="modal fade" id="modalLogin" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
</div>
</div>
</div>
</div>
I can't believe i could be so stupid, I thought this would be one of the possible options for my problem, form inside a form...
I am calling the login modal from _Layout and it was inside a form... I can't believe i wasted a day for this. It's my first time going backwards on making a mvc 5 project cause our IIS server does not allow host for Asp .NET Core 2.2 yet and totally forgot about the form on layout.
<form class="form-inline my-2 my-lg-0">
#if (User.Identity.IsAuthenticated)
{
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
}
else
{
<ul class="navbar-nav mr-auto">
<li class="nav-item">
#Html.Action("Index", "Account")
<a class="nav-link" href="#" data-toggle="modal" data-target="#modalLogin">Log In</a>
</li>
</ul>
}
</form>
Change url from url: '/Login/Account' to url: '/Account/Login' because your controller is Account not Login. I tried reproduce in local and it worked
$("#btnSubmit").click(function () {
debugger
var formData = $('#formModal').serialize();
$.ajax({
type: 'POST',
url: '/Account/Login',
data: formData,
async: true,
success: function (data) {
}
});
return false;
});
the data you post needs to map to one object { model: {}, ReturnUrl: "" }, ReturnUrl can come from the query string, but your action and form models are different.
Your form model is model: {}, and your action model is { model: {}, ReturnUrl: "" }
your name attributes on your form inputs should be model.Username, model.Password, vs Username, Password
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")
}
I'm having troubles adding google reCAPTCHA to my page.
in the Layout I have added the Google Recaptcha js
_layout
<title>#ViewBag.Title</title>
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
#RenderSection("scripts", required: false)
<script src='https://www.google.com/recaptcha/api.js'></script>
<script type="text/javascript">
<script type="text/javascript">
$(document).ready(function () {
$('#subject').on("change", function (e) {
e.preventDefault();
var selectedVal = $('#subject').val();
$.ajax({
// url: "/ContactUs/GetForm",
url: '#Url.Action("GetForm", "ContactUs")',
type: "POST",
data: { searchValue: selectedVal } ,
async: true,
success: function (data) {
$('#renderForms').empty();
$('#renderForms').append(data);
},
error: function (xhr, ajaxOptions, thrownError) {
alert("An error has occured!!! " + xhr.status + " && " + xhr.responseText);
}
});
});
});
</script>
then in my index I select which form I want to show:
#Html.DropDownListFor(model => model.contactSelectListItems, new List<SelectListItem>
{
new SelectListItem() {Text = "option1", Value="option1"},
new SelectListItem() {Text = "option2", Value="option2"},
new SelectListItem() {Text = "option3", Value="option3"},
}, "--Choose--", new { id = "subject", #class= "dropdown-item" })
</div>
<div id="renderForms">
</div>
in both partial page there is a form where I do something similiar yet different viewmodels:
#using (Html.BeginForm("SendCustomerTeam", "ContactUs", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>CustomerTeamViewModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="container">
<div class="form-group form-group-sm col-sm-6">
<div class="row">
#Html.LabelFor(model => model.Phone, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-sm-9">
#Html.EditorFor(model => model.Phone, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Phone, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group form-group-sm col-sm-12">
<div class="row">
#Html.LabelFor(model => model.Inquiry, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-sm-12">
#Html.EditorFor(model => model.Inquiry, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Inquiry, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group form-group-sm col-sm-12">
<div class="row">
<div class="col-sm-12">
<div id="NotRobot">
<label>Are you Human?</label>
<div id='recaptcha' class="col-sm-12 g-recaptcha"
data-sitekey="#System.Configuration.ConfigurationManager.AppSettings["RecaptchaPublicKey"]"
>
</div>
<div id="recaptchaMessage" data-verifyrecaptchatokenurl="#Url.Action("VerifyReCaptchaToken", "Home")" style="display:none;padding:10px;color:red;font-weight:bold;" class="error">You need to verify reCAPTCHA.</div>
</div>
</div>
</div>
</div>
<div class="form-group form-group-sm col-sm-6">
<div class="row">
<div class="col-sm-9">
<input id="Send" type="submit" value="Send" class="btn btn-default" />
</div>
</div>
</div> etc...
In my controller I handle it like this thou I would like to handle the reCAPTCHA as an ajax call I have yet to figure out how to do that.
public ActionResult Index()
{
ViewData["ReCaptchaKey"] = System.Configuration.ConfigurationManager.AppSettings["RecaptchaPublicKey"];
//do something here
}
public static bool ReCaptchaPassed(string gRecaptchaResponse, string secret)
{
HttpClient httpClient = new HttpClient();
var res = httpClient.GetAsync($"https://www.google.com/recaptcha/api/siteverify?secret={secret}&response={gRecaptchaResponse}").Result;
if (res.StatusCode != HttpStatusCode.OK)
{
//logger.LogError("Error while sending request to ReCaptcha");
return false;
}
string JSONres = res.Content.ReadAsStringAsync().Result;
dynamic JSONdata = JObject.Parse(JSONres);
if (JSONdata.success != "true")
{
return false;
}
return true;
}
[HttpPost]
public ActionResult SendCustomerTeam(CustomerTeamViewModel model)
{
ContactViewModel contactModel = new ContactViewModel();
contactModel.CustomerTeamModel = model;
ViewData["ReCaptchaKey"] = System.Configuration.ConfigurationManager.AppSettings["RecaptchaPublicKey"];
if (ModelState.IsValid)
{
if (!ReCaptchaPassed(
Request.Form["g-recaptcha-response"], // that's how you get it from the Request object
System.Configuration.ConfigurationManager.AppSettings["RecaptchaPrivateKey"]
))
{
ModelState.AddModelError(string.Empty, "You failed the CAPTCHA, stupid robot. Go play some 1x1 on SFs instead.");
return View(contactModel);
}
}
My problem is the reCAPTCHA never appears on my page.
Edit:
I've tried the following simplification to see if I could find the issue.
SimplePageViewModel
public class simplePageViewModel
{
public string Name { get; set; }
}
SimplePagePartialView
#model Contact_Portal.Models.simplePageViewModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>simplePageViewModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="container">
<div class="row">
<div class="form-group form-group-sm col-sm-6">
<div class="row">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-sm-9">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group form-group-sm col-sm-12">
<div class="row">
<div class="col-sm-12">
<div id="NotRobot">
<label>Are you Human?</label>
<div id='recaptcha' class="col-sm-12 g-recaptcha" style="padding:10px;"
data-sitekey="#System.Configuration.ConfigurationManager.AppSettings["RecaptchaPublicKey"]">
</div>
<div id="recaptchaMessage" data-verifyrecaptchatokenurl="#Url.Action("VerifyReCaptchaToken", "Home")" style="display:none;padding:10px;color:red;font-weight:bold;" class="error">You need to verify reCAPTCHA.</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
in the controller I get the partial view shown through this line
return PartialView("View", contactModel.simplePageModel);
Still the same problem persist.
Could it be because I'm displaying my partial page containing the reCAPTCHA as part of an Jquery Ajax call ? like this:
$(document).ready(function () {
$('#subject').on("change", function (e) {
e.preventDefault();
var selectedVal = $('#subject').val();
$.ajax({
// url: "/ContactUs/GetForm",
url: '#Url.Action("GetForm", "ContactUs")',
type: "POST",
data: { searchValue: selectedVal } ,
async: true,
success: function (data) {
$('#renderForms').empty();
$('#renderForms').append(data);
},
error: function (xhr, ajaxOptions, thrownError) {
alert("An error has occured!!! " + xhr.status + " && " + xhr.responseText);
}
});
});
I've now tried a entire new project where I've simplified it all the way down to one html file:
Index.cshtml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>#ViewBag.Title - My ASP.NET Application</title>
<link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
<link href="~/Content/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="~/Scripts/modernizr-2.6.2.js"></script>
<script src='https://www.google.com/recaptcha/api.js'></script>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
#Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { #class = "navbar-brand" })
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
</ul>
</div>
</div>
</div>
<div class="container body-content">
<div id='recaptcha' class="col-sm-12 g-recaptcha" style="padding:10px;"
data-sitekey="#System.Configuration.ConfigurationManager.AppSettings["RecaptchaPublicKey"]"></div>
<hr />
<footer>
<p>© #DateTime.Now.Year - My ASP.NET Application</p>
</footer>
</div>
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
</body>
</html>
Still it is not visible it never appears. why is it not working ?
could it be that ASP.NET MVC is not supported by Recaptcha from google?
Your script src is wrong:
<script src='https://www.google.com/recaptcha/api.js async defer'></script>
to
<script src='https://www.google.com/recaptcha/api.js'></script>
Also could you check deveoper console, if there any error?
Well I found a solution I'm not happy with it but it works.
in my Layout file I've made a section like this:
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<script type="text/javascript">
function enableBtn() {
document.getElementById("subject").disabled = false;
}
$(document).ready(function () {
document.getElementById("subject").disabled = true;
});
</script>
Then in my view I created this
<div class="g-recaptcha" data-sitekey="*********PublicKEY*************" data-callback="enableBtn"></div>
And it seems to be working.
I wish I could make it work in the partial view because now I have to have it no matter what else will happen and not just on a submit.
I don't know if I can verify this one server side anymore as it is also outside my form. ?
Anyone with a better option would be welcomed.
EDIT:
I found a better solution for me. I changed my ajax call like this:
$('#subject').on("change", function (e) {
e.preventDefault();
var selectedVal = $('#subject').val();
$.ajax({
// url: "/ContactUs/GetForm",
url: '#Url.Action("GetForm", "ContactUs")',
type: "POST",
data: { searchValue: selectedVal } ,
async: true,
success: function (data) {
$('#renderForms').empty();
$('#renderForms').append(data);
if (!debug) {
document.getElementById("Send").disabled = true;
grecaptcha.render('Captcha', {
'sitekey': '**********PublicKey*********',
'callback': function() {
document.getElementById("Send").disabled = false;
},
'expired-callback': function() {
//document.getElementById("subject").selectedIndex = 0;
document.getElementById("Send").disabled = true;
//document.getElementById("renderForms").innerHTML = "";
}
});
}
},
error: function (xhr, ajaxOptions, thrownError) {
alert("An error has occured!!! " + xhr.status + " && " + xhr.responseText);
}
});
});
Now it is working as I intended. At least in the user interface part.
I'm developing purchase module with ASP.NET MVC 5. In Create view purchase, I'm using PartialView to load the detail purchase.
The Detail Purchase contains:
A textbox with browse button to input item
A textbox to input quantity
A button to add the item to the list (purchase detail)
When I clicked browse button the modal will show up with list of paged items (using PagedList). The modal form contains:
In modal header there are a textbox and a button for searching item name
In modal body to display list of items (load partially)
The error occurs if I searched item name
"The value of the property '$' is null or undefined, not a Function
object"
The jQuery script is already added by default at ~/Shared/_Layout.cshtml, and in the create view, I have added #Scripts.Render("~/bundles/jqueryval")
Code: View Create Purchase (Create.cshtml)
#model SalesSupportSystem.ViewModels.PurchaseOrderViewModel
#using (Html.BeginForm())
{
<div class="form-horizontal">
<h4>PurchaseOrder</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.PurchaseOrderDate, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PurchaseOrderDate)
#Html.ValidationMessageFor(model => model.PurchaseOrderDate)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.InvoiceNo, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.InvoiceNo)
#Html.ValidationMessageFor(model => model.InvoiceNo)
</div>
</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>
}
#{ Html.RenderPartial("~/Views/PurchaseOrderDetail/_AddEdit.cshtml", Model.PurchaseOrderAddEditDetails); }
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script src="~/Scripts/bootstrap-datepicker.js"></script>
<script>
$(document).ready(function () {
$(".date").datepicker({
autoclose: true,
clearBtn: true,
format: "dd/mm/yyyy",
todayBtn: "linked",
todayHighlight: true
});
$("#btnLookupItem").click(function (e) {
e.preventDefault();
$.ajax({
type: "GET",
url: "#Url.Content("~/INVENTSUM1/Lookup")",
cache: false
})
.done(function (data) {
$("#itemContainer").html(data);
$("#itemModal").modal("show");
});
});
$("#btnSubmitINVENTSUM1").click(function (e) {
e.preventDefault();
$.ajax({
type: "POST",
url: "#Url.Content("~/INVENTSUM1/Lookup")",
data: { filterValue: $("#FilterValue").val() },
cache: false
})
.done(function (data) {
$("#itemContainer").html(data);
});
});
});
function setINVENTSUM1(ITEMID, ITEMNAME) {
document.getElementById("ItemID").value = ITEMID;
document.getElementById("ItemName").value = ITEMNAME;
$("#itemModal").modal("hide");
}
</script>
}
PartialView (_AddEdit.cshtml)
#model SalesSupportSystem.ViewModels.PurchaseOrderDetailAddEditViewModel
<!-- Item Modal -->
<div class="modal fade bs-example-modal-lg" id="itemModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" id="btnCancelCUSTTABLE" title="Clear the selected input on form" class="close" data-dismiss="modal" data-toggle="tooltip" data-placement="left"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title" id="myModalLabel">Select Item</h4>
#using (Html.BeginForm("Lookup", "INVENTSUM1"))
{
<div class="form-inline">
Find by name: <input type="text" id="FilterValue" name="FilterValue" class="form-control" placeholder="Enter keyword" value="" />
<input type="submit" id="btnSubmitCUSTTABLE" value="Search" class="btn btn-primary" />
</div>
}
</div>
<div class="modal-body" id="itemContainer">
...
</div>
</div>
</div>
</div>
#using (Html.BeginForm("AddEdit", "PurchaseOrderDetail", FormMethod.Get, new { #class = "form-inline" }))
{
<h4>Detail</h4>
<hr />
<fieldset>
<div class="form-inline">
<div class="form-group">
#Html.HiddenFor(model => model.ItemID)
<div class="input-group">
#Html.EditorFor(model => model.ItemName)
<div class="input-group-btn">
<button class="btn btn-primary" id="btnLookupItem">...</button>
</div>
</div>
</div>
<div class="form-group">
#Html.EditorFor(model => model.QuantityOrder)
</div>
<button class="btn btn-primary" id="btnAddItem">Add</button>
</div>
</fieldset>
}
Controller (INVENTSUM1Controller.cs)
public ActionResult Lookup(int? page)
{
var pagedItem = db.INVENTSUM1
.OrderBy(i => i.ITEMNAME)
.ToPagedList(page, 10);
return PartialView("_Lookup", pagedItem);
}
[HttpPost]
public ActionResult Lookup(string filterValue)
{
var pagedItem = db.INVENTSUM1
.Where(i => i.ITEMNAME.Contains(filterValue))
.OrderBy(i => i.ITEMNAME)
.ToPagedList(1, 10);
return PartialView("_Lookup", pagedItem);
}
PartialView (_Lookup.cshtml)
#model IEnumerable<SalesSupportSystem.Models.INVENTSUM1>
#using PagedList.Mvc;
#{
var pagedList = (PagedList.IPagedList)Model;
}
<div>
<table class="table table-striped table-hover table-condensed">
<tr>
<th></th>
<th>
#Html.DisplayNameFor(model => model.ITEMID)
</th>
<th>
#Html.DisplayNameFor(model => model.ITEMNAME)
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td></td>
<td>#Html.DisplayFor(modelItem => item.ITEMID)</td>
<td>#Html.DisplayFor(modelItem => item.ITEMNAME)</td>
</tr>
}
</table>
</div>
Page #(pagedList.PageCount < pagedList.PageNumber ? 0 : pagedList.PageNumber) of #pagedList.PageCount
<div id="pager">
#Html.PagedListPager(pagedList, page => Url.Action("Lookup", new { page }))
</div>
<script>
$(document).ready(function () {
$("#pager").on("click", "a", function () {
if (this.href == "") {
return;
}
$.ajax({
type: "GET",
url: this.href,
cache: false
})
.done(function (data) {
$("#itemContainer").html(data);
});
return false;
});
});
</script>
Another question: as you can see in the lookup.cshtml code, I placed script at there. I've read from SO articles, it should not be placed in partialview, but I have no choice, if I placed in Create.cshtml, the paging will not work. Is there any workaround for this?
I am using MVC in ASP.NET and want a Drag n Drop in my view. I would like to call a function in my controller when the images are dropped to verify them and show an OK to the user. When the user has finished typing in information and dropped the appropriate images he/she clicks "Fortsæt" (continue) and calls submit on the form.
This method should be called when an Image is dropped.
[HttpPost]
[Authorize(Roles = "host")]
public ActionResult UploadImages()
{
bool suc;
foreach (string s in Request.Files)
{
HttpPostedFileBase image = Request.Files[s];
string fileName = Request.Headers["X-File-Name"];
string fileExtension = "";
if (!string.IsNullOrEmpty(fileName))
fileExtension = Path.GetExtension(fileName);
suc = Verify(fileExtension);
}
return Json(suc);
}
This should be called when the user clicks "Continue"
[HttpPost]
[Authorize(Roles = "host")]
public ActionResult Create(FleaMarket model, HttpPostedFileBase[] images)
{
ConditionallySetUser(model, User);
foreach (var fileName in Request.Files)
{
HttpPostedFileBase file = Request.Files[fileName.ToString()];
if (file != null && file.ContentLength > 0)
{
var image = HttpPostedFileBaseToByteArray(file);
model.Images.Add(new FleaImage
{
Image = image, FleaMarketId = model.EventId
});
}
}
db.FleaMarkets.Add(model);
db.SaveChanges();
ViewBag.HostID = new SelectList(db.Hosts, "HostId", "Name", model.HostId);
TempData["market"] = model;
return
RedirectToAction("AddStallImage", "FleaMarket");
}
Here are some snips of my View
#model FleaPortal.Models.Database.FleaMarket
<link href="~/Content/basic.css" rel="stylesheet" />
<link href="~/Content/dropzone.css" rel="stylesheet" />
<script src="~/Scripts/dropzone.min.js"></script>
#using (Html.BeginForm("Create", "FleaMarket", method: FormMethod.Post, htmlAttributes: new { #encType = "multipart/form-data",#class="dropzone", #id="dropzoneForm"}))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.HostId)
<div class="row">
<div class="form-group col-sm-6">
#Html.LabelFor(model => model.HostId, "Arrangør")
<label class="text-box single-line form-control" id="Name">
#Html.DisplayFor(model => model.Host.UserProfile.UserName)
</label>
</div>
<div class="form-group col-sm-6">
#Html.LabelFor(model => model.Name)
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group col-sm-12">
#Html.LabelFor(model => model.Description)
#Html.EditorFor(model => model.Description, new { #class = "TextAreaInput" })
#Html.ValidationMessageFor(model => model.Description)
</div>
...
...
<div class="form-group col-sm-12">
<label>Stemningsbilleder</label>
<div id="dropzonePreview">
drop your images here
<div class="dz-default dz-message" data-dz-message="">
</div>
</div>
</div>
...
...
<div class="btn-group two-bt-group col-sm-12">
<button name="ButtonType" value="Continue" id="submitAll" type="submit" class="btn btn-success two-bt">#Resources.Views_Global_Continue</button>
<button name="ButtonType" value="Cancel" type="button" class="btn btn-danger two-bt" onclick="location.href='#Url.Action("Manage", "Account")'">#Resources.Views_Global_Cancel</button>
</div>
#section Scripts {
#Scripts.Render("~/bundles/datepicker")
#Scripts.Render("~/bundles/booking")
#Scripts.Render("~/bundles/dropzonescripts")
<script type="text/javascript">
$(document).ready(function() {
$(".form_date").datetimepicker({ format: 'yyyy-mm-dd', startView: 2, minView: 2 });
$(".form_time").datetimepicker({ format: 'hh:ii', startView: 1, maxView: 1 });
});
</script>
<script>
Dropzone.options.dropzoneForm = {
clickable: false,
//url: '/FleaMarket/UploadImages',
autoProcessQueue: false,
uploadMultiple: true,
paramName: "images",// Must match the name of the HttpPostedFileBase argument that the Upload action expects
maxFiles: 100,
autoQueue: false,
previewsContainer: "#dropzonePreview",
parallelUploads:100,
init: function () {
debugger;
this.on("success", function (file, responseText) {
file.previewTemplate.appendChild(document.createTextNode(responseText));
});
}
};
</script>
I have spent way too much time trying to figure this out, and I believe there might be a simple solution - I just don't know. ? Can someone help me figuring this out?
Many thanks in advance.
I ended up calling a method in my controller every time an image was uploaded. I assigned an ID to the imaged and passed it to my view like this:
Dropzone.autoDiscover = false;
$("div#dropzonePreview").dropzone(
{
url: '/FleaMarket/UploadImage',
paramName: "images",
autoProcessQueue: true,
addRemoveLinks: true,
//clickable: "#dropzonePreview",
uploadMultiple: true,
acceptedFiles: "image/*",
maxFiles: 100,
parallelUploads: 10,
dictInvalidFileType: "Dette er ikke et billede",
dictFileTooBig: "Billedet er for stort",
success: function(file, response) {
$('#ImageIds').val($('#ImageIds').val() + "," + response.Ids);
done();
}
});
#Html.HiddenFor(model => model.ImageIds);
<div class="form-group col-sm-12">
<label>Stemningsbilleder</label>
<div id="dropzonePreview" class="dropzone">
</div>
</div>
In Asp.net mvc 5. we have a login page which implements HTML.BeginForm() to post data to controller , if the username and password are incorrect, we are sending error back to the front end using partial views. Everything work fine, In case of error only error message is displayed on the screen and nothing else.
Controller
[HttpPost]
public ActionResult SingleSSOMPLogin(SSoStateModel model)
{
//Check the Code with SP providers and Authorization server.
if(model.SAMLAssertion.validMPData)
{
return RedirectToAction("SSOServiceMP" , "SAML");
}else
{
//Error message processed.
model.errorMessage = SSOState.SAMLAssertion.errorMessage;
return PartialView("_LoginError" , model);
}
}
The view contain the following Code
<div class="peripheral">
<div class="panel panel-default panel-peripheral">
#{Html.Partial("_LoginError", Model);}
<div class="panel-heading clearfix">Please Log In</div>
<div class="panel-body">
<div class="brand-logo eop-logo">
<script type="text/javascript">
function changeImage() {
document.getElementById("Logo").src = '#Url.Content("~/Content/images/TopLogo.gif")';
}
</script>
<img id="Logo" width="200" src='#Url.Content("~/Content/images/TopLogo.gif")' onerror="changeImage()" />
#{ Html.EnableClientValidation(true);}
<!--Ajax call to Controller-->
#using (Html.BeginForm("SingleSSOMPLogin", "Accounts"))
{
#Html.ValidationSummary(true);
<div id="group-email" class="form-group col-md-12 ">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control", placeholder = "Please enter your Email address" })
#Html.ValidationMessageFor(m => m.Email)
</div>
<div id="group-password" class="form-group col-md-12">
#Html.PasswordFor(m => m.Password, new { #class = "form-control", placeholder = "Please enter your password" })
#Html.ValidationMessageFor(m => m.Password)
</div>
<div class="form-group">
<div class="col-md-12">
<button type="submit" class="btn btn-primary pull-left">Login</button>
<a id="forgot" href='#Url.Action("ForgotPassword","Accounts")' class="btn btn-link btn-sm pull-right">Forgot your password?</a>
</div>
</div>
}
</div>
</div>
</div>
</div>
Partial View
#{
Layout = null;
}
#if (Model.Result!= null)
{
<div class="alert alert-warning alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
<strong>#Model.Result.errorMessage</strong>
</div>
}
When Error occur, I get redirect to same view again with all query parameter gone and display only error message.
How to solve following issue?
The partial view will return only the fragment you defined.
So when called from a "complete" view with
#{Html.Partial("_LoginError", Model);}
it will generate the corresponding part of the view.
In your situation what is most common is to add a model error and return the complete view (that must have a ValidationSummary section):
[HttpPost]
public ActionResult SingleSSOMPLogin(SSoStateModel model)
{
//Check the Code with SP providers and Authorization server.
if(model.SAMLAssertion.validMPData)
{
return RedirectToAction("SSOServiceMP" , "SAML");
}else
{
//Error message processed.
ModelState.AddModelError("error", SSOState.SAMLAssertion.errorMessage);
return View(model);
}
}
If you want to use the partial view you have to call it from an javacript ajax call and insert the response in your page. With jQuery it is something more or less like:
$.ajax({ url: <partial view url>,
type: 'GET',
success: function (result) {
$(updateSelector).hide().html(result).effect("fade", "fast");
}
});