Passing Model Data to a Bootstrap Modal on click - ajax

I'm extremely new to MVC and I don't know how to make this work-
I have a model that stores different news items based on categories:
NewsModel.cs:
public class NewsModel
{
public int ID { get; set; }
public string category { get; set; }
public String headline { get; set; }
public string source { get; set; }
public DateTime date { get; set; }
public string body { get; set; }
public string summary { get; set; }
}
I have a View that displays each of the news items as a list Item:
Sports.cshtml:
#model IEnumerable<Test.Models.NewsModel>
#foreach (var item in Model)
{
<div class="news_target-left floatleft">
<div class="image-container">
<img src="~/Content/Images/demo_img.png" alt="website template image">
<div class="top-left-text">
#item.category
</div>
</div>
<h3>#item.headline</h3>
<p> #item.summary </p>
<p class="single_cat_left_content_meta"><span>#item.source</span> | #item.date</p>
<span class="readmore">#Html.ActionLink("Read More", "NewsModal", "Home", #item)</span>
</div>
}
When the user clicks on Read More, I want to load a bootstrap modal that gets the current model object and displays the entire news data in detail. Currently, the readmore span uses an Html actionlink that does not seem to be working. I want to load the modal using Ajax but cannot figure out how to do so.
This is the bootstrap Modal that I have:
NewsModal.cshtml:
#model Test.Models.NewsModel
<div id="newsModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Leadsquared Express</h4>
</div>
<div class="modal-body">
<h2>#Model.headline</h2>
<i><small>#Model.source</small></i>
<p>#Model.body</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
The Model is in Models/NewsModel
The Sports View is in Views/Categories/
The Sports controller Action is in Controllers/Categories:Sports
The NewsModal is currently in Views/Categories/. I have tried putting this view in Shared, as well as its own folder, but I'm obviously doing something wrong.
Any help?
Edit:
I used this link to make the following changes but clicking on "Read more" does not open the modal popup.
http://www.c-sharpcorner.com/UploadFile/092589/implementing-modal-pop-up-in-mvc-application/
changed <span class="readmore">#Html.ActionLink("Read More", "NewsModal", "Home", #item)</span> in Sports.cshtml to
<a id="openmodal "href="javascript:void(0)" class="readmore" data-model="#Json.Encode(#item)">Read More</a>
and added this script:
$(document).ready(function () {
var url = "/Home/NewsModal";
var model = $("#openmodal").attr("data-model");
alert("script running- sports.html");
$.ajax({
type: 'GET',
url: '/Home/NewsModal',
data: model,
contentType: 'application/json; charset=utf-8',
success: function (data, status, settings) {
$("#openmodal").html(data);
},
error: function (ajaxrequest, ajaxOptions, thrownError) {
$("#openmodal").html('Failed to load more content');
}
});
});
Additionally, this is the Action Method I have for the Modal Popup, in HomeController:
public ActionResult NewsModal(NewsModel tempData)
{
NewsModel currentItem = new NewsModel();
currentItem = tempData;
return PartialView("NewsModal", currentItem);
}

You can do by make a click event by using Anchor tag instead ActionLink,
and in that you can do like this.
Open a Modal by jQuery
function openModal()
{
$('#newsModal').modal('show');
}
// $('#newsModal').modal('toggle');
// $('#newsModal').modal('show');
// $('#newsModal').modal('hide');
OR can do directly with data-target,
<button type="button" data-toggle="modal" data-target="#newsModal">Launch modal</button>

Related

MVC reusable search window [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
In mvc how to create customer search page. Also how to call invoke this as modal popup from other views button (need to call in different views). How to pass the customerid and customername after searching to the page invoking the search page. Requirement is reusable customer search window.
Tried with bootstrap modal popup
Create a partial view _PartialSearch.cshtml and include it in your _Layout.cshtml file:
#Html.Partial("_PartialSearch")
The partial view will call the Search method in your controller and get the search results.
Views/Shared/_PartialSearch.cshtml
<!-- Modal -->
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Search window</h4>
</div>
<div class="modal-body">
<div>
<input type="search" id="searchString"><button type="submit" id="search">Search</button>
</div>
<br/>
<div id="result"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
#{
<script>
$(function () {
//Init the result
$("#result").load("#Url.Action("GetAll", "Home")");
$("#search").click(function() {
var searchString = $("#searchString").val();
$.ajax({
type: "POST",
url: "#Url.Action("Search", "Home")",
data: '{searchString: "' + searchString + '" }',
contentType: "application/json; charset=utf-8",
dataType: "html",
success: function(response) {
$('#result').html(response);
},
failure: function(response) {
alert(response.responseText);
},
error: function(response) {
alert(response.responseText);
}
});
});
});
</script>
}
Views/Shared/_Layout.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>
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
</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">
<li>#Html.ActionLink("Home", "Index", "Home")</li>
<li>#Html.ActionLink("Another Page", "AnotherPage", "Home")</li>
</ul>
</div>
</div>
</div>
<div class="container body-content">
#RenderBody()
<hr />
<footer>
<p>© #DateTime.Now.Year - My ASP.NET Application</p>
</footer>
</div>
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
#RenderSection("scripts", required: false)
#Html.Partial("_PartialSearch")
</body>
</html>
Create a Customer model to store your customer's data
Models/Customer.cs
namespace SearchModal.Models
{
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
}
Create a Movie model to store your search data
Models/Movie.cs
namespace SearchModal.Models
{
public class Movie
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
}
Create a SearchResultVm viewmodel to store your view data
Viewmodels/SearchResultVm.cs
using System.Collections.Generic;
using SearchModal.Models;
namespace SearchModal.ViewModels
{
public class SearchResultVm
{
public List<Movie> Movies { get; set; }
}
}
Create a SessionDataManager manager to manage your Customer session
Managers/SessionDataManager.cs
using System.Web;
using System.Web.SessionState;
using SearchModal.Models;
namespace SearchModal.Managers
{
public class SessionDataManager : ISessionDataManager
{
private HttpSessionState CurrentSession => HttpContext.Current?.Session;
private object GetSessionObject(string key, bool redirectToSessionEnd = true)
{
var obj = CurrentSession?[key];
if (obj == null)
{
//no session
}
return obj;
}
private void SetSessionObject<T>(string sessionObjectName, T value)
{
CurrentSession[sessionObjectName] = value;
}
public Customer Customer
{
get => GetSessionObject("Customer") as Customer;
set => SetSessionObject("Customer", value);
}
}
public interface ISessionDataManager
{
Customer Customer { get; set; }
}
}
Create a HomeController controller to handle your different views that has the search button (i.e. Index and AnotherPage)
Create a Search method to handle your search request and return a partial view with the results
Controllers/HomeController.cs
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using SearchModal.Managers;
using SearchModal.Models;
using SearchModal.ViewModels;
namespace SearchModal.Controllers
{
public class HomeController : Controller
{
private ISessionDataManager _sessionDataManager;
private List<Movie> _movies;
public HomeController()
{
//TODO Inject through Dependency Injection
_sessionDataManager = new SessionDataManager();
_movies = new List<Movie>
{
new Movie
{
Id = 1, Name="Die Hard", Description = "Christmas movie"
},
new Movie
{
Id = 2, Name="Armageddon", Description = "End of the world"
},
new Movie
{
Id = 3, Name="Love actually", Description = "Chick flick"
}
};
}
public ActionResult Index()
{
//Set customer details
var customer = new Customer {Id = 1, Name = "Bob"};
_sessionDataManager.Customer = customer;
return View();
}
public ActionResult AnotherPage()
{
//Get customer info
var customer = _sessionDataManager.Customer as Customer;
//Do something with customer info
return View();
}
public ActionResult GetAll()
{
//Get customer info
var customer = _sessionDataManager.Customer as Customer;
//Do something with customer info
var viewModel = new SearchResultVm
{
Movies = _movies
};
return PartialView("_SearchResult", viewModel);
}
public ActionResult Search(string searchString)
{
//Get customer info
var customer = _sessionDataManager.Customer as Customer;
//Do something with customer info
var viewModel = new SearchResultVm
{
Movies = _movies.Where(m => m.Name.Contains(searchString)).ToList()
};
return PartialView("_SearchResult", viewModel);
}
}
}
Create an Index view to show your search button. The only line you need to include in other views are this:
<button type="button" class="btn btn-info btn-lg" data-toggle="modal" data-target="#myModal">Open Modal</button>
Views/Home/Index.cshtml
<div>
<h1>Index</h1>
<button type="button" class="btn btn-info btn-lg" data-toggle="modal" data-target="#myModal">Open Modal</button>
</div>
Create an AnotherPage view for another page with the search button
Views/Home/AnotherPage.cshtml
<div>
<h1>Another Page</h1>
<button type="button" class="btn btn-info btn-lg" data-toggle="modal" data-target="#myModal">Open Modal</button>
</div>
Create a _SearchResult partial view to show results
Views/Home/_SearchResult.cshtml
#model SearchModal.ViewModels.SearchResultVm
<br/>
<b>Results: </b><br/>
#foreach (var movie in Model.Movies)
{
<b>#movie.Name</b> #:- #movie.Description<br />
}
Output:

How do you connect a POST to a different razor page loaded via AJAX into a modal popup?

Edit: Have marked up where the error in the original code was stopping this from working.
I can find plenty of info and examples of this on MVC, but doesn't seem to apply for Razor Pages?
Simple scenario: I have a page (FooList) showing a list of Foo items. Each has an Edit button. This opens a modal popup with the layout (and data) coming from a second page (FooEdit).
The Edit form appears and populates fine, but I can't work out how to get it to post the data back to the FooEdit code behind?
List page, FooList.cshtml
#page
#model Pages.FooListModel
<table>
#foreach (var item in Model.FooListVM)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
<a onclick="openModal(#item.ID);">Edit</a>
</td>
</tr>
}
</table>
<div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header border-bottom-0">
<h5 class="modal-title" id="exampleModalLabel">Edit Foo</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<form> <---- Edit: ** This shouldn't be here **
<div class="modal-body">
</div>
</form> <---- Edit
</div>
</div>
</div>
<script>
function openModal(i) {
$.get("FooEdit?id="+i,
null,
data => {
$("#editModal").modal("show");
$("#editModal .modal-body").html(data);
});
};
</script>
Code behind, FooList.cshtml.cs
public class FooListModel : PageModel
{
public IList<FooListVM> FooListVM { get; set; }
public void OnGet()
{
FooListVM = new List<FooListVM>
{
new FooListVM { ID = 1, Name = "Foo 1" },
new FooListVM { ID = 2, Name = "Foo2" }
};
}
}
public class FooListVM
{
public int ID { get; set; }
public string Name { get; set; }
}
Second page for the popup, FooEdit.cshtml
#page
#model Pages.FooEditModel
#(Layout=null)
<form method="post">
<input asp-for="FooEditVM.Name" class="form-control" /><br />
<input asp-for="FooEditVM.Stuff1" class="form-control" /><br />
<input asp-for="FooEditVM.Stuff2" class="form-control" /><br />
<input type="submit" value="Save"/>
</form>
And the code behind for the popup, FooEdit.cshtml.cs
public class FooEditModel : PageModel
{
[BindProperty]
public FooEditVM FooEditVM { get; set; }
public void OnGet(int id)
{
FooEditVM = new FooEditVM
{
Name = $"This is item {id}",
Stuff1 = "Stuff1",
Stuff2 = "Stuff2"
};
}
public void OnPost(int id)
{
// How do we get to here???
var a = FooEditVM.Name;
}
}
public class FooEditVM
{
public string Name { get; set; }
public string Stuff1 { get; set; }
public string Stuff2 { get; set; }
}
I've been through all the MS Tutorial stuff on Asp.net Core 2.2, but it doesn't seem to cover this.
Also as a side question, although it works, is there a "ASP helper tag" way of doing the ajax bit?
Have realised the problem was the 'form' tag in the Modal Dialog markup that was clashing the 'form' tag from the partial page. Removing it fixed everything using:
In FooEdit.cshtml
<form id="editForm" asp-page="FooEdit">
. . .
</form>
In FooEdit.cshtml.cs
public void OnPost()
{
// Fires in here
}
I'm pretty sure the fooedit page is going to need some jQuery to handle this.
See below for what I would do in the fooedit page.
#page
#model Pages.FooEditModel
#(Layout=null)
<form id=fooedit method="post" action="FooEdit">
<input asp-for="FooEditVM.Name" class="form-control" /><br />
<input asp-for="FooEditVM.Stuff1" class="form-control" /><br />
<input asp-for="FooEditVM.Stuff2" class="form-control" /><br />
<input type="submit" value="Save"/>
</form>
<SCRIPT language="JavaScript" type="text/Javascript">
<!--
$(document).ready(function(e) {
$("#fooedit").submit(function(e) {
e.preventDefault();
var form_data = $(this).serialize();
var form_url = $(this).attr("action");
var form_method = $(this).attr("method").toUpperCase();
$.ajax({
url: form_url,
type: form_method,
data: form_data,
cache: false,
success: function(returnhtml){
$("#editModal.modal-body").html(returnhtml);
}
});
});
});
</SCRIPT>

Validation error message not displayed in Asp.Net Core 2 MVC partial view

I have an index page with a list of "workbooks" titles and for each workbook, there is a "share" button. When pressing the button a bootstrap model (i.e. dialog) appears which displays the title of the workbook and a textarea allowing the user to type in a sharees email addresses.
When the user presses on the "share" button, I am calling a javascript function which calls a controller action that returns a partial view containing the modal dialog with a form inside it. The problem is that after pressing the submit button (i.e. "Share") there are no validation errors being shown to the user and I am not sure why that is. Could anyone provide some ideas, please?
That is my main (index.cshtml) page:
#model DNAAnalysisCore.Models.WorkBookModel
#{
}
#section BodyFill
{
<script type="text/javascript">
function showSharingView(title) {
var url = "#Url.Action("ShowShareDialog", "Home")" + "?workbookTitle=" + encodeURI(title);
$('#shareFormContainer').load(url,
function() {
$('#shareFormModal').modal("show");
});
}
function hideSharingView() {
$('#shareFormModal').modal("hide");
}
</script>
<div id="shareFormContainer" >
<!--PLACEHOLDER FOR SHARE DIALOG -->
</div>
<div class="workbook-container">
<table class="table">
<tbody>
#foreach (var workbook in Model.Workbooks)
{
<tr>
<td>#Html.ActionLink(workbook.Name, "Open", "OpenAnalytics", new {id = Model.Id, workbook = workbook.Name})</td>
<td>
<button title="Share" class="share-button" onclick='showSharingView("#workbook.Name")'> </button>
</td>
</tr>
}
</tbody>
</table>
</div>
}
That is my Controller:
public class HomeController : Controller
{
[HttpGet]
public IActionResult ShowShareDialog(string workbookTitle)
{
var shareModel = new ShareModel
{
Title = workbookTitle
};
return PartialView("_ShareView", shareModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult ShareWorkbook(string emails, string title)
{
var share = new ShareModel
{
Emails = emails
};
// TODO EMAIL THE SHARED WORKBOOK using the 'title' of the workbook and the 'email' string value
// return no content to avoid page refresh
return NoContent();
}
}
This is my partial view/modal dialog (_ShareView):
#using DNAAnalysisCore.Resources
#model DNAAnalysisCore.Models.ShareModel
<!-- Modal -->
<div class="modal fade" id="shareFormModal" role="dialog">
<div class="modal-dialog modal-md">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Share Workbook - #Model.Title</h4>
</div>
#using (Html.BeginForm("ShareWorkbook", "Home", FormMethod.Post))
{
<div class="modal-body">
<label>#BaseLanguage.Share_workbook_Instruction_text</label>
<div class="form-group">
<textarea class="form-control" asp-for="Emails" rows="4" cols="50" placeholder="#BaseLanguage.ShareDialogPlaceholder"></textarea>
#* TODO add client-side validation using jquery.validate.unobtrusive.js. See US268276 *#
<span asp-validation-for="Emails" class="text-danger"></span>
</div>
<input asp-for="Title" />
</div>
<div class="modal-footer">
<button type="submit" onclick="hideSharingView()" class="btn btn-primary">Share</button>
<button id="btnCancelDialog" type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
</div>
}
</div>
</div>
</div>
#section Scripts {
#{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}
This is my ShareModel:
public class ShareModel
{
[HiddenInput]
public string Title { get; set; }
[Required]
public string Emails { get; set; }
}
The form is not added to the page when the page loads, the unobtrusive validation will not pick it up.A simple solution is to use $.validator.unobtrusive.parse("#id-of-the-form");.Refer to here.
1.Add id to your form in _ShareView partial view:
#using (Html.BeginForm("ShareWorkbook", "Home", FormMethod.Post,new { #id="partialform"}))
2.Introduce validation file _ValidationScriptsPartial.cshtml into main page(Index.cshtml) and manually register the form with the unobtrusive validation.
#section Scripts
{
#await Html.PartialAsync("_ValidationScriptsPartial")
<script type="text/javascript">
function showSharingView(title) {
var url = "#Url.Action("ShowShareDialog", "Home")" + "?workbookTitle=" + encodeURI(title);
$('#shareFormContainer').load(url,
function() {
$('#shareFormModal').modal("show");
$.validator.unobtrusive.parse("#partialform");
});
}
function hideSharingView() {
$('#shareFormModal').modal("hide");
}
</script>
}

MVC4 api routing can find one action but not another

I have the following MVC4 api controller:
public class VisitorController : ApiController
{
private ApplicationDbContext db = new ApplicationDbContext();
public Visitor Get(int id)
{
return db.Visitors.Find(id);
}
public void SaveNotes(int id, string notes)
{
var visitor = db.Visitors.Find(id);
visitor.Notes = notes;
db.SaveChanges();
}
}
the Get works but the SaveNotes doesn't. I can't figure out why, but at run time, SaveNotes can't be found. (For what it's worth, Application Insights can see the attempt to POST to it, and that it gets a 404 error. See: )
Here's how I'm trying to call it: I have a modal dialog, like so:
<div class="modal fade" id="notesModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Notes</h4>
</div>
<div class="modal-body">
<form id="notesForm">
<input type="hidden" name="id" id="notesID"/>
<textarea id="notesTextarea" name="notes"></textarea>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" onclick="saveNotes();">Save</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
And I have two javascript functions;
function showNotes(id) {
$("#searchingModal").modal("show");
$.ajax("#Url.Action("Get", "API/Visitor")/" + id)
.done(function (data) {
$("#searchingModal").modal("hide");
$("#notesID").val(id);
$("#notesTextarea").val(data.Notes);
$("#notesModal").modal("show");
})
.fail(function (xhr, status, errorThrown) {
$("#searchingModal").modal("hide");
genericError(status, errorThrown);
});
}
function saveNotes() {
//alert("#Url.Action("SaveNotes", "API/Visitor")/");
$.ajax({ url: "#Url.Action("SaveNotes", "API/Visitor")/", data: $("#notesForm").serialize(), method:"POST" })
.done(function () {
$("#notesModal").modal("hide");
})
.fail(function (xhr, status, errorThrown) {
$("#notesModal").modal("hide");
genericError(status, errorThrown);
});
}
The function showNotes works great. I run an ajax request, it calls Get on the visitor controller, a visitor is returned, I populate that textarea with the Notes field, and show the modal. The problem is saveNotes. Every time I click the save button on the modal I get the failure function instead of the done function. The errorThrown is "Not Found". So how is it that only one action can't be found? I've tried putting the [HttpPost] attribute on it. I've tried making the id a nullable int (even though it's already optional in the route config, see:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
). I've tried making savenotes return a string instead of void. I've tried using $.post instead of $.ajax.
When you're getting post data, it must be an object. So make an object like
public class SaveNotesInput
{
public int id { get; set; }
public string notes { get; set;}
}
change your function to accept that class, like so:
public void SaveNotes(SaveNotesInput input)
and it should work.
(couldn't tell you why)
(Credit to Ju66ernaut's comment, I'm just making this an answer for easier searchability)

AJAX Model Validation with Partial View

I have a partial view, which is a login that functions as a popup. All I want to do is have my model do the validation (server side) and return any errors via AJAX. The code below returns the partial view only with the errors. I want my action result to not return a a view, but only the errors. In old ASP.NET, this would be a Partial Post back. I am not sure how to accomplish this in MVC.
Here is the Model
public class LoginModel
{
[Required]
public String Email { get; set; }
[Required]
[DataType(DataType.Password)]
public String Password { get; set; }
}
Here is the Partial View
#model MySite.Models.LoginModel
#using (Ajax.BeginForm("Authenticate", "Account", null, new AjaxOptions { OnFailure = "error" }, new { id = "LoginForm" }))
{
<div class="modal-body" id="LoginPopupDialogMessage">
The page you have requested requires you to login. Please enter your credentials and choose your country:
<br />
<br />
<div class="row">
<div class="form-group col-lg-offset-2 col-lg-8">
<label>Email Address</label>
#Html.TextBoxFor(u => u.Email, new { #class = "form-control input-lg input-sm", id = "Email", name = "Email" })
#Html.ValidationMessageFor(u => u.Email)
</div>
</div>
<div class="row">
<div class="form-group col-lg-offset-2 col-lg-8 ">
<label>Password</label>
#Html.PasswordFor(u => u.Password, new { #class = "form-control input-lg input-sm", name = "Password" })
#Html.ValidationMessageFor(u => u.Password)
</div>
</div>
<div style="text-align: center; padding-top: 20px;" class="ImageGroup">
<button name="companyCode" value="LB_US" class="btn-link" type="submit">
<img src="../../WebContent/Images/icon-flag-usa.png" />
</button>
<button name="companyCode" value="LB_CA" class="btn-link" type="submit">
<img src="../../WebContent/Images/icon-flag-canada.png" />
</button>
<button name="companyCode" value="LB_EU" class="btn-link" type="submit">
<img src="../../WebContent/Images/icon-flag-europe.png" />
</button>
</div>
</div>
}
I call the parial view from _layout.cshtml.
<div class="modal fade" id="LoginPopupDialog" tabindex="-1" role="dialog" aria-labelledby="myModalLabel1" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header" style="background: #e7e3e7; color:#000;">
<button type="button" class="close" data-dismiss="modal" aria-label="Close" style="color:#000;">
<span aria-hidden="true">×</span>
</button>
<div class="modal-title" id="LoginPopupDialogHeader">Please Login</div>
</div>
#Html.Action("Login", "Account")
</div>
</div>
</div>
My Controller Action:
[HttpPost]
[Route("account/authenticate")]
public ActionResult Authenticate(String companyCode, LoginModel model)
{
if (!ModelState.IsValid)
{
// ??
}
return PartialView("Login", model);
}
Since your code is doing an ajax form submission for the login, you should try to return a JSON response from the server. If model validation fails, you may read the validation errors from the model state dictionary and store that in a collection of strings (error messages) and return that as part of the json response. If model validation passes, you can continue executing your code to verify the login credentials and if those looks good, send back a json response with the next url for the user (to which we can redirect the user).
[HttpPost]
public ActionResult Authenticate(String companyCode, LoginModel model)
{
if (!ModelState.IsValid)
{
var errors = ViewData.ModelState.Values
.SelectMany(x => x.Errors.Select(c => c.ErrorMessage));
return Json(new { Status = "Error", Errors = errors });
}
//to do :Verify login, if good, return the below respose
var url=new UrlHelper(Request.RequestContext);
var newUrl = url.Action("About");
return Json(new { Status="Success", Url = newUrl});
}
Now in your view, you may specify a OnSuccess handler as part of the AjaxOptions. This will be a javascript object to which the json response from the server will come. We basicallly need to check the Status property value and do the appropriate things.
new AjaxOptions { OnFailure = "error" , OnSuccess="loginDone"}
The below implementation of loginDone simply alerts the error messages. You can update it to show it as part of the DOM.
function loginDone(d) {
if (d.Status === "Success") {
window.location.href = d.Url;
} else {
$.each(d.Errors,function(a, b) {
alert(b);
});
}
}
You may also consider enabling the unobtrusive client side validation which does the client side validation before trying to make a call to server. This will also show the error messages in the validation error spans (same as the normal mvc model validation does)

Resources