In my ASP.NET MVC 5 project, I have created a new HelperResult.
My goal is to create a reusable autocomplete dropdownlist component (that contains the bootstrap-select) and with a setting of several parameters can assume behaviors different on needed, but especially that use a controller method or API in POST to populate itself.
It seems It works well but not enough in postback action.
I can't bind my helper to retrieve data at the postback action.
I don't know how getting data selected from combobox...
To be more clear, I'd like to show you the interface
Well, when I press button I don't know how to get data in the controller.
Follow the View where I have put new HelperResult
View
#{
ViewBag.Title = "Test";
Layout = "";
}
<h2>Test</h2>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<link href="~/UIComponent/bootstrap-select/css/bootstrap-select.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.bundle.min.js"></script>
<script src="~/UIComponent/bootstrap-select/js/bootstrap-select.js"></script>
#using (Html.BeginForm("testpost", "Home"))
{
<br />
<div style="padding:30px">
Lists
#UIHelper.HubCombo("/HUB/GetMezziOrdinari", "ID", "Descrizione", false, "Seleziona un item", "cboItems", "<b>Selezionare un item</b>", "ID")
<input type="submit" value="submit" id="btnSubmit" />
</div>
}
This is my Helper defined in the "UIHelper.cshtml" within App_Code
Helper
#helper HubCombo(string UrlHub,
string nomecampoValue,
string nomecampoText,
bool MultiSelection = false,
string placeholder = "",
string controlID = "cboSelect",
string header = "",
string subText = ""
)
{
string _subText = subText.Trim();
<select class=""
id="#controlID"
data-live-search="true"
title="#placeholder"
data-hide-disabled="true"
data-header="#header"
data-width="auto"
#if (MultiSelection)
{
<text>multiple</text>
}
>
</select>
<script type="text/javascript">
$.ajax({
url: '#UrlHub',
type: 'POST',
contentType: 'application/json',
data: '',
success: function (response) {
var options = [], _options;
$.each(response.Data, function (idx, obj) {
#{
if (_subText.Length>0)
{
<text>
options.push("<option data-subtext='"+ obj.#_subText+"' value='" + obj.#nomecampoValue + "'>" + obj.#nomecampoText + "</option>");
</text>
}
else
{
<text>
options.push("<option value='" + obj.#nomecampoValue + "'>" + obj.#nomecampoText + "</option>");
</text>
}
}
});
_options = options.join('');
$('##controlID')[0].innerHTML = _options;
$('##controlID').selectpicker();
}
});
</script>
}
At the end my controller but I'm stuck!
Controller
[HttpPost]
public ActionResult testpost()
{
//How to get value of my custom Helper Result?
return View();
}
if you have other solutions, please let me know. thx
With this signature for controller action, now you can retrieve data:
[HttpPost]
public ActionResult testpost(List<string> cboItems)
{
ViewBag.cboItems = string.Join("<br />", cboItems);
return View();
}
even so
[HttpPost]
public ActionResult testpost(string[] cboItems)
{
...
so, I think the ViewModel class used by Controller and View should container those fields.
Related
I am creating an MVC application in which I will have an input field for a list of emails. In order to do so, I added multiple in order to allow for the user to enter a comma separated list of emails. By doing it this way, I'm able to have input controls to check for the email(s) to be properly formatted (".+#gmail.com").
The problem is that when I test this, it automatically adds class="input-validation-error" (even if I set the #class="" prior) and will not allow me to post due to an invalid input, as a result. Is there any way to allow for this, or is my only option to make it an Email string property and parse it by commas into the EmailList property in the controller?
(Here is my code):
View:
#Html.TextBoxFor(model => model.EmailList, new { type = "email", placeholder
= "ex#gmail.com (',' Delimited)", title = "Make sure your email(s) are
formatted appropriately (and comma separated).", multiple = "" })
Model:
public List<string> EmailList { get; set; }
UPDATE:
I should also add that I am performing json serialization on post, so It needs to be in the form of a list. Ideally, I would be able to use the multiple for the input of type email tag, since it would allow for the necessary input controls that I would need without making me take it as a string and writing it to a list.
The new fiddle is here, click on it https://dotnetfiddle.net/ORYDVJ
View
#model Testy20161006.Controllers.MurphyModel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Tut122</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
$("#emailField").change(function () {
var theList = {
emaillist: []
};
var array = $('#emailField').val().split(",");
$.each(array, function (i) {
theList.emaillist.push(
array[i]
);
});
$.ajax({
url: '/Home/Tut122',
traditional: true,
type: "POST",
contentType: "application/json",
data: JSON.stringify({ murphyModel: theList }),
success: function (data) {
console.log('success!!');
$("#theOutput").html(data)
}
});
})
})
</script>
</head>
<body>
#Html.TextBoxFor(model => model.EmailList, new
{
id = "emailField",
type = "email",
placeholder = "ex#gmail.com (',' Delimited)",
title = "Make sure your email(s) are formatted appropriately (and comma separated).",
multiple = ""
})
<span>The output data:</span>
<div id="theOutput">
</div>
</body>
</html>
Controller/View Model
public class MurphyModel
{
public List<string> EmailList { get; set; }
}
public class HomeController : Controller
{
[HttpPost]
public string Tut122(MurphyModel murphyModel)
{
//You need to get Newtonsoft.JSON
var json = JsonConvert.SerializeObject(murphyModel);
return json;
}
public ActionResult Tut122()
{
MurphyModel model = new MurphyModel();
return View(model);
}
https://dotnetfiddle.net/eadTjh
View
#model Testy20161006.Controllers.MurphyModel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Tut122</title>
</head>
<body>
#if (ViewBag.Output != null)
{
<span>#ViewBag.Output</span>
}
#using (Html.BeginForm())
{
#Html.TextBoxFor(model => model.EmailList, new
{
type = "email",
placeholder = "ex#gmail.com (',' Delimited)",
title = "Make sure your email(s) are formatted appropriately (and comma separated).",
multiple = ""
})
<input type="submit" value="submit" />
}
</body>
</html>
Controller/View Model
namespace Testy20161006.Controllers
{
public class MurphyModel
{
//We don't want a list class, rather a string
public string EmailList { get; set; }
}
public class HomeController : Controller
{
[HttpPost]
public ActionResult Tut122(MurphyModel model)
{
var splitEmails = model.EmailList.Split(',');
var anEmail = "These are the different emails: ";
foreach (string email in splitEmails)
{
//set breakpoint here
anEmail+= email + " and ";
}
anEmail = anEmail.Substring(0, anEmail.Length - 5);
ViewBag.Output = anEmail;
return View(model); }
public ActionResult Tut122()
{
MurphyModel model = new MurphyModel();
return View(model);
}
add a js file hopefully u use jQuery
$(document).ready(function () {
$("#EmailList").removeClass("input-validation-error");
});
After Reviewing kblau's answer, I realized that was partially the reason. The other issue that I was running into (where MVC was stepping over any of my manually entered client-side validation) was the result of the unobtrusive validation:
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
After commenting this out, it allowed for me to have the input write to a string Email which I would then assign to a list of strings EmailList in the controller. This ended up working for me.
i wrote behind code.
but Viewbag.message will show null in alert message .myvar is a variable.
i used breakpoint , myvar will set by Viewbag.message correctly. but it will be shown null in alert .
<script src="~/Scripts/jquery-1.7.1.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
#{string myvar = ViewBag.AlertMessage;}
#using (Ajax.BeginForm("action", "controller", new AjaxOptions { HttpMethod = "Post", OnSuccess = "Messsage" }))
{
<script type="text/javascript">
function Messsage() {
alert('#ViewBag.AlertMessage'); //infact, it shows alert('');
}
</script>
<script type="text/javascript">
function Messsage() {
alert('#myvar'); // should show "hello there"
}
</script>
#using (Ajax.BeginForm("AjaxAction", "Home", new AjaxOptions { HttpMethod = "Post", OnSuccess = "Messsage" }))
{
<script type="text/javascript">
function Messsage() {
alert("#ViewBag.AjaxMessage");
}
</script>
<input type="submit" value="Submit" />
}
is the ViewBag.AlertMessage being defined in the controller action ?
you can replace the data by
#{string myvar = "hello there !";}
<script type="text/javascript">
function Messsage() {
alert('#myvar'); // should show "hello there"
}
</script>
or define your viewbag item in the action method behind the result
public ActionResult Index() {
ViewBag.AlertMessage = "hello there !"
return View();
}
Try setting the value for ViewBag.AlertMessage in controller action that returns the view on which you have defined the Ajax.Begin form.
eg
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
ViewBag.AlertMessage = "AjaxMessage.";
return View();
}
}
on Index view i have placed the following code, calling AjaxAction on Home Controller.
#using (Ajax.BeginForm("AjaxAction", "Home", new AjaxOptions { HttpMethod = "Post", OnSuccess = "Messsage" }))
{
<script type="text/javascript">
function Messsage() {
alert("#ViewBag.AjaxMessage");
}
</script>
<input type="submit" value="Submit" />
}
My simpel test Model:
public class MovieModel {
public string SelectedCategorieID { get; set; }
public List<CategorieModel> Categories { get; set; }
public MovieModel() {
this.SelectedCategorieID = "0";
this.Categories = new List<CategorieModel>() {new CategorieModel {ID = 1,
Name = "Drama"},
new CategorieModel {ID = 2,
Name = "Scifi"}};
}
}
public class CategorieModel {
public int ID { get; set; }
public string Name { get; set; }
}
My Home controller action Index:
public ActionResult Index() {
Models.MovieModel mm = new Models.MovieModel();
return View(mm);
}
My strongly typed View:
#model MvcDropDownList.Models.MovieModel
#{
ViewBag.Title = "Home Page";
}
<script type="text/javascript">
function categoryChosen(selectedCatID) {
// debugger;
var url = "Home/CategoryChosen?SelectedCategorieID=" + selectedCatID;
$.post(url, function (data) {
$("#minicart").html(data);
});
}
</script>
#using (Html.BeginForm("CategoryChosen", "Home", FormMethod.Get)) {
<fieldset>
Movie Type
#Html.DropDownListFor(m => m.SelectedCategorieID, new SelectList(Model.Categories, "ID", "Name", Model.SelectedCategorieID), "---Select categorie---")
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
}
<input type="button" value="Minicart test" onclick="categoryChosen('#Model.SelectedCategorieID');" />
<div id="minicart">
#Html.Partial("Information")
</div>
Please ignore the first input, because I'm using the second input with 'Minicart test' on it (the HTML.Beginform is there to learn something else later). The mini cart stuff is from another tutorial, I apologize. Don't let it distract you please.
When the button is clicked categoryChosen jQuery is called, which calls the action:
[AcceptVerbs("POST")]
public ActionResult CategoryChosen(string SelectedCategorieID) {
ViewBag.messageString = SelectedCategorieID;
return PartialView("Information");
}
The partial view Information looks like this:
#{
ViewBag.Title = "Information";
}
<h2>Information</h2>
<h2>You selected: #ViewBag.messageString</h2>
My question is why is Model.SelectCategorieID zero (Model.SelectCategorieID = 0) even after I changed the value in the dropdownlist? What am I doing wrong? Thank you very much in advance for answering. If you need any information or anything in unclear, please let me know.
My question is why is Model.SelectCategorieID zero
(Model.SelectCategorieID = 0) even after I changed the value in the
dropdownlist?
That's because you have hardcoded that value in your onclick handler:
onclick="categoryChosen('#Model.SelectedCategorieID');"
If you want to do that properly you should read the value from the dropdown list:
onclick="categoryChosen(this);"
and then modify your categoryChosen function:
<script type="text/javascript">
function categoryChosen(ddl) {
// debugger;
var url = 'Home/CategoryChosen';
$.post(url, { selectedCategorieID: $(ddl).val() }, function (data) {
$('#minicart').html(data);
});
}
</script>
Also I would recommend you using an URL helper to generate the url to invoke instead of hardcoding it in your javascript function. And last but not least, I would recommend you doing this unobtrusively, so that you could put this in a separate javascript file and stop mixing markup and script.
So here's how your code will look like after taking into consideration my remarks:
#model MvcDropDownList.Models.MovieModel
#{
ViewBag.Title = "Home Page";
}
#using (Html.BeginForm("CategoryChosen", "Home", FormMethod.Get))
{
<fieldset>
Movie Type
#Html.DropDownListFor(
m => m.SelectedCategorieID,
new SelectList(Model.Categories, "ID", "Name"),
"---Select categorie---",
new {
id = "categoryDdl"
data_url = Url.Action("CategoryChoosen", "Home")
}
)
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
}
<input type="button" value="Minicart test" id="minicart-button" />
<div id="minicart">
#Html.Partial("Information")
</div>
and then in your separate javascript file unobtrusively subscribe to the click handler of your button and send the AJAX request:
$(function() {
$('#minicart-button').click(function() {
// debugger;
var $categoryDdl = $('#categoryDdl');
var selectedCategorieID = $categoryDdl.val();
var url = $categoryDdl.data('url');
$.post(url, { selectedCategorieID: selectedCategorieID }, function (data) {
$('#minicart').html(data);
});
});
});
Provide an id for your dropdownlist:
#Html.DropDownListFor(m => m.SelectedCategorieID, new SelectList(Model.Categories, "ID",
"Name", Model.SelectedCategorieID), new {id = "myDropDownList"})
And your javascript function as follows:
<script type="text/javascript">
function categoryChosen() {
var cat = $("#myDropDownList").val();
var url = "Home/CategoryChosen?SelectedCategorieID=" + cat;
$.post(url, function (data) {
$("#minicart").html(data);
});
}
</script>
Why your code did not work?
onclick="categoryChosen('#Model.SelectedCategorieID')
is generated as
onclick="categoryChosen('0')
because the value of SelectedCategorieID is 0 when it is generated.
I have simple report page- a couple of text boxes where when data is entered and submitted I want to load the jqgrid on the same page asynchronously.
I am using the MVC version of JQGrid.
without a jqgrid I am able to load a table data and my view looks like below
#using (Ajax.BeginForm("GetReport", new AjaxOptions {UpdateTargetId = "result", HttpMethod = "Post" }))
{
<div class="editor-label">Start Date</div>
<div class="editor-field">#Html.Editor("StartDate", "DateTime")</div>
<div class="editor-label">End Date</div>
<div class="editor-field">#Html.Editor("EndDate", "DateTime")</div>
<input type="submit" value="Submit" />
}
<div id="result"></div>
instead of a result being a table I want to display a jqGrid in its place. A jqGrid which is defined as below.
#Html.Trirand().JQGrid(Model.ReportGrid, "ReportGrid")
How do I achieve this?
I'll step out how I would do it, which I think would work for you as well (I build a number of jqGrids with a MVC3 backend.
You already have the HTML component, or you could use something like this.
<div id="ExampleGridContainer" >
<table id="ExampleGridName" class="scroll" cellpadding="0" cellspacing="0" ></table>
<div id="ExampleGridPager" class="scroll" style="text-align:center;"></div>
</div>
Then for your Javascript you would need to include a reference to both (in this example I"m using English as my location)
<script src="#Url.Content("~/Scripts/trirand/i18n/grid.locale-en.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/trirand/jquery.jqGrid.min.js")" type="text/javascript"></script>
You could include this on your page if it was a one of or in your _Layout.chtml
Then inside your script portion on the view you could build somthing similar to
<script type="text/javascript">
$(document).ready(function () {
//initalize jqGrid
$('#ExampleGridName').jqGrid({
datatype: 'json',
url: '/ControllerName/ActionName',
colNames: [ 'ColumnOneName', 'ColumnTwoName']
colModel: [
{ name: 'ColumnOneName', //etc}
{ name: 'ColumnTwoName', //etc}
],
pager: $('#ExampleGridPager'),
rowNum: 5,
rowList: [5,10,20],
sortname: 'ColumnOneName',
//etc
//rest of grid settings
});
});
</script>
Now in the example above with the datatype: 'json', and the url: property filled out when the view is displayed and the ready event is processed your grid will go out to the URL and look for data. If you want to do this later on after another action, or repeat it dynamically you can start off with the datatype: 'local', and no url: property.
When it comes time to set these properties and reload the grid you would either:
//set the `datatype:` and `url:` properties and load the grid
$('#ExampleGridName').jqGrid('setGridParam', { datatype: 'json', url: '/ControllerName/ActionName' }).trigger('reloadGrid', [{ page: 1}]);
//reload the grid if the `datatype:` and `url:` properties are already configured
$('#ExampleGridName').jqGrid().trigger('reloadGrid', [{ page: 1}]);
On your Controller you would have an action that would be able to respond to the requests for data and produce the results in a JSON format. This by no means is anything beyond a basic example of how to get up and running with a MVC3 jqGrid with dynamic loading, and there are many more advanced filtering, searching, etc options.
public ActionResult ActionName(string sidx, string sord, int page, int rows, bool _search, string filters)
{
//load data from somthing,
IQuerable<Object> results = database.getresults //whatever you want to populate a set of data really
int totalRecords = results.Count();
var pagedResults = results.OrderBy(sidx + " " + sord).Skip((page -1) * rows).Take(rows);
var jsonData = new
{
total = (totalRecords + rows - 1) / rows,
page = page,
records = totalRecords,
rows = (
from tempValue in pagedResults.ToList()
select new
{
cell = new string[] {
tempValue.ColumnOneValue,
tempValue.ColumnTwoIntValue.ToString(),
//Etc
}).ToArray()
};
return Json(jsonData, JsonRequestBehavior.AllowGet);
}//ActionName
That would be a very basic way to display a jqGrid and then dynamically interact with it after other actions/events. enter code here
After much struggling here is what I did.I have a main view and a partial view. Initially the main view does not contain the partial view. When data is submitted , the partial view is loaded.
MyReport.cshtml
#{
ViewBag.Title = "Report";
}
<h2>Report</h2>
<br />
#using (Ajax.BeginForm("GetReportData", new AjaxOptions { UpdateTargetId = "result", HttpMethod = "Post", InsertionMode = InsertionMode.Replace}))
{
<div class="editor-label">Start Date</div>
<div class="editor-field">#Html.Editor("StartDate", "DateTime")</div>
<div class="editor-label">End Date</div>
<div class="editor-field">#Html.Editor("EndDate", "DateTime")</div>
<input type="submit" value="Submit" />
}
<div id="result">
</div>
Then I have a partial view of the Grid- MyReportPartial.cshtml
#model MyGridModel
#using Trirand.Web.Mvc
<link href="#Url.Content("~/Content/theme/ui.jqgrid.css")" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="#Url.Content("~/Scripts/trirand/i18n/grid.locale-en.js")"></script>
<script type="text/javascript" src="#Url.Content("~/Scripts/trirand/jquery.jqGrid.min.js")"></script>
<br />
#Html.Trirand().JQGrid(Model.Grid, "ReportGrid")
My Controller has the following
public ActionResult MyReport()
{
var gridModel = new Models.Grid.EmpHeadcountGridModel();
var grid = gridModel.MyGrid;
SetupHeadCountGrid(grid, DateTime.Now.ToShortDateString(), DateTime.Now.ToShortDateString());
return View(gridModel);
}
public ActionResult GetReportData(string startdate ,string enddate)
{
var gridModel = new Models.Grid.MyGridModel();
var grid = gridModel.EmpHeadcountGrid;
SetupHeadCountGrid(grid,costcenterid,startdate,enddate);
return PartialView("MyReportPartial",gridModel);
}
private void SetupHeadCountGrid(JQGrid grid,int costcenterid,string startdate,string enddate)
{
grid.ID = "ReportGrid";
grid.DataUrl = Url.Action("GetHeadcountData") + "?startdate=" + startdate + "&enddate=" + enddate;
}
public JsonResult GetHeadcountData(string startdate, string enddate)
{
DateTime startdt = DateTime.Parse(startdate);
DateTime enddt = DateTime.Parse(enddate + " 23:59:59");
var gridModel = new Models.Grid.MyGridModel();
var query= { soem query using date criteria}
gridModel.MyGrid.DataSource = query;
return gridModel.MyGrid.DataBind();
}
<script src="../../Scripts/MicrosoftAjax.debug.js" type="text/javascript"></script>
<script type="text/javascript">
function loginOK()
{
var item = document.getElementById('statusLabel');
item.innerHTML = "OK";
document.getElementById('LoadImg').style.visibility = 'hidden';
}
function process()
{
var lab = document.getElementById('statusLabel');
lab.innerHTML = 'Checking...';
lab.style.color = 'Black';
document.getElementById('LoadImg').style.visibility = 'visible';
}
function fail()
{
var lab = document.getElementById('statusLabel');
lab.innerHTML = 'Login is being used';
lab.style.color = 'Red';
document.getElementById('LoadImg').style.visibility = 'hidden';
}
</script>
<div style="width:30%; float:left;">
<label for="Login">Login:</label>
<%= Html.TextBoxFor(model=>model.Login) %>
<%= Html.ValidationMessageFor(model=>model.Login) %>
<img id="LoadImg" alt="" src="../../Content/Images/ajax-loader.gif" style="visibility:hidden;"/>
<br />
<label id="statusLabel" />
<br />
<%=Ajax.ActionLink("CheckLogin","CheckLoginAvailability", "Account",
new AjaxOptions { UpdateTargetId = "statusLabel", OnBegin = "process", OnFailure = "fail", OnSuccess="loginOK"})%>
</div>
and, in the AccountController:
[AcceptVerbs(HttpVerbs.Post)]
public void CheckLoginAvailability(string login)
{
//do some job
}
And, FireBug says that /Account/CheckLoginAvailability is not found. Also, after callback that ActionLink is hidden. Why ?
You are talking about Ajax.BeginForm in your question but this is nowhere to be seen in the markup you provided. There are a couple of issues that I can see with your code:
Your action method doesn't return an ActionResult. Yeah I know, you will say that this is possible, right, but that's against any good practices, conventions and rendering your controllers unit-test friendly.
You are using Microsoft Ajax which will mix markup and javascript which IMHO is bad for multiple reasons: increasing bandwidth which of course leads to decreased performance, incapacity to externalize javascript into separate files in order to cache them by client browsers, having to write things like document.getElementById, innerHTML, style.color, style.visibility, etc... which is not guaranteed to work cross browser.
Here's what I would suggest you to improve this. While this doesn't answer your question, take it as an alternative approach.
As always the first thing to deal with is to define a model which in your case might look something like this:
public class LoginViewModel
{
public string Login { get; set; }
}
Of course you might wish to add other fields such as Password, but this is out of scope for the moment. The next step is to write a controller dealing with this model (in parallel you should be already setting a unit-test for the future controller to prepare the ground):
public class HomeController : Controller
{
public ActionResult Index()
{
// Simply return the Login form
return View(new LoginViewModel());
}
[HttpPost]
public ActionResult Index(LoginViewModel model)
{
// Deal with the actual authentication, etc...
throw new NotImplementedException();
}
[HttpPost]
public ActionResult CheckLoginAvailability(LoginViewModel model)
{
// TODO: query your datasource to determine whether
// model.Login is taken
// For this purpose we will suppose that it is taken
bool isLoginTaken = true;
// return a JSON object containing the result
return Json(new { IsLoginTaken = isLoginTaken });
}
}
The last part is to paint the screen:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<SomeNs.Models.LoginViewModel>" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Login</title>
<!-- Use a separate CSS to avoid mixing markup with styling -->
<link rel="stylesheet" type="text/css" href="<%: Url.Content("~/content/site.css") %>" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<!-- Always use HTML helpers when dealing with Urls -->
<script type="text/javascript" src="<%: Url.Content("~/scripts/login.js") %>"></script>
</head>
<body>
<% using (Html.BeginForm()) { %>
<%: Html.LabelFor(x => x.Login) %>:
<%: Html.TextBoxFor(x => x.Login) %>
<%: Html.ValidationMessageFor(x => x.Login) %>
<br/>
<!-- Always use HTML helpers when dealing with Urls -->
<img id="loadImg" alt="" src="<%: Url.Content("~/content/images/ajax-loader.gif") %>" style="display:none;" />
<br />
<div id="statusLabel"></div>
<br />
<!-- Give this link an id so that we can easily identify it from javascript -->
<%: Html.ActionLink("CheckLogin", "CheckLoginAvailability", "Home", null, new { id = "checkLogin" })%>
<input type="submit" value="Login" />
<% } %>
</body>
</html>
And the last part is to unobtrusively attach our javascript (using jQuery of course) in the login.js file:
// When the DOM is ready
$(function () {
// Attach a click handler to the checkLogin link
$('a#checkLogin').click(function () {
// When this link is clicked send an AJAX POST request
// to the address this link is pointing to
$.ajax({
type: 'POST',
url: this.href,
// Pass as parameter in the POST body the login
// entered by the user
data: { login: $('#Login').val() },
beforeSend: function () {
// show the spinner image before sending any AJAX request
// to inform the user of an ongoing activity
$('#loadImg').show();
},
complete: function () {
// hide the spinner image when the AJAX request completes
// no matter if it succeeded or not
$('#loadImg').hide();
},
success: function (result) {
// if the AJAX request succeeds
// query the IsLoginTaken property
// of the resulting JSON object
if (result.IsLoginTaken) {
// Show the status label with red if the login is taken
$('#statusLabel').html('Login is being used').css('color', 'red');
} else {
// Show the status label in black if the login is not taken
$('#statusLabel').html('OK').css('color', 'black');
}
}
});
return false;
});
});
As #SLaks says actions can return void but, I think the action signature is such that it is required to return an action result and you can return EmptyResult if you don't want to return anything.
see this http://www.asp.net/mvc/tutorials/asp-net-mvc-controller-overview-cs
try changing your AccountController to
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CheckLoginAvailability(string login)
{
//do some job
return new EmptyResult();
}