mvc3 jquery mobile how to use Html.BeginForm - asp.net-mvc-3

I have already written an entire site in MVC3. I am trying to build the mobile version with Jquery Mobile. I haven't changed my controller code, except to add a check for whether or not it should return a mobile page. I have the following in the document head of my mobile logon page:
<head>
<title>Mobile Logon</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0-alpha.1/jquery.mobile-1.2.0-alpha.1.min.css" />
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
$(document).bind("mobileinit", function(){
$.extend( $.mobile , {
ajaxEnabled: false
});
});
<script src="http://code.jquery.com/mobile/1.2.0-alpha.1/jquery.mobile-1.2.0-alpha.1.min.js"></script>
</head>
I have a page with a header and content. In the content, I want to let the user redirect to the register form. the following seems to work:
<form action="Register" method="get" data-ajax="false">
<button type="submit" value="Register for an account"></button>
</form>
This does not work: (the url seems correct in the browser, but all that loads is a blank, white page)
#using(Html.BeginForm("Register", "Account", FormMethod.Get, null ))
{
<button type="submit" value="Register for an account"></button>
}
When I look in the page source, I notice two differences: The first one gives a form tag with
action="Register"
while the second gives a form tag with
action="Account/Register"
The other difference is the "data-ajax=false" in the form tag.
Questions:
Am I able to use #Html.BeginForm() with Jquery Mobile? If not, how do I redirect to a different controller?
How come my code in the head section doesn't turn off the default ajax behavior of Jquery Mobile? (I tried using the form tag above without data-ajax=false, and I got the same blank, white screen as the #Html.BeginForm gave me).
EDIT: here is my logon controller code (Account controller)
public ActionResult LogOn()
{
//return View();
return SelectView("Logon", null);
}
private ActionResult SelectView(string viewName, object model, string outputType = "html")
{
if (outputType.ToLower() == "json")
{
return Json(model, JsonRequestBehavior.AllowGet);
}
else
{
#if MOBILE
return View(viewName + ".Mobile", model);
#else
if (Request.Browser.IsMobileDevice)
{
return View(viewName + ".Mobile", model);
}
else
{
return View(viewName, model);
}
#endif
}
}
here is my Register controller code: (Account controller)
public ActionResult Register(string returnUrl = "")
{
//if no return url supplied, use referrer url.
//Protect against endless loop by checking for empty referrer.
if (String.IsNullOrEmpty(returnUrl) && Request.UrlReferrer != null && Request.UrlReferrer.ToString().Length > 0)
{
return RedirectToAction("Register", new { returnUrl = Request.UrlReferrer.ToString() });
}
return View();
}

Related

How to display alert message box in asp.net core mvc controller?

I want to display alert message box when the account model is invalid.
How should i gonna do this in controller in Asp.Net Core MVC?
Here is my Controller's code
[HttpPost]
public IActionResult Index(Account model)
{
if (model.ID != null && model.PassWord != null)
{
using (var db = new AccountDBContext())
{
var account = db.Account.FirstOrDefault(
a => a.ID.Equals(model.ID) && a.PassWord.Equals(model.PassWord)
);
if(account != null)
return RedirectToAction("Index", "Main");
}
//I want to display error msg box...here like "Check ID or PW".
ModelState.AddModelError("", "Error");
}
return View();
}
I searched the way but there is no "Page" identifier or "Response.write()" Method in this controller class....
How should i gonna do?
p.s
The way that i checked model's validation like that is right way?
(I used a model and check it's partial properties, instead using view model )
Define the error in your controller:
ModelState.AddModelError("Error", "Check ID");
And then display it in the view:
#if (!ViewData.ModelState.IsValid && ViewData.ModelState["Error"].Errors.Count > 0)
{
<div class="alert alert-
<strong>Error!</strong> danger">#ViewData.ModelState["Error"].Errors.First().ErrorMessage
</div>
}
EDIT
To show an alert box, add some javascript in your view, the following uses jquery:
<head>
<script type="text/javascript">
#if (!ViewData.ModelState.IsValid && ViewData.ModelState["Error"].Errors.Count > 0)
{
<text>
$(document).ready(function() {
alert('#ViewData.ModelState["Error"].Errors.First().ErrorMessage');
});
</text>
}
</script>
</head>

How to redirect to Login page from an Ajax postback?

I work on an MVC 3 application. My cshtml page looks like this:
#Ajax.BeginForm("Filter", new AjaxOptions() { UpdateTargetId = "div_GridPlaceholder")
{
...some HTML
<input id="btn_Filter" type='submit' ... />
}
<div id="div_GridPlaceholder">...</div>
The Filter ( ) action method marked with the Authorize attribute returns some string at the moment. Everything works fine but when the forms authentication ticket expires and I hit the btn_Filter button, my Login page gets rendered in the div_GridPlaceholder which is pretty strange. I would like to have the see the Login page rendered on the whole page instead of inside that div.
Any help is appreciated.
In your Logon action you could append a custom response HTTP header:
public ActionResult LogOn()
{
Response.AppendHeader("X-LOGON", "true");
return View();
}
and then subscribe for the complete event and test for the presence of this header and act accordingly:
$(function () {
$('#div_GridPlaceholder').ajaxComplete(function (event, XMLHttpRequest, ajaxOptions) {
if (XMLHttpRequest.getResponseHeader('X-LOGON') == 'true') {
window.location.href = '#Url.Action("LogOn", "Account")';
}
});
});

MVC3 RemoteAttribute and muliple submit buttons

I have discovered what appears to be a bug using MVC 3 with the RemoteAttibute and the ActionNameSelectorAttribute.
I have implemented a solution to support multiple submit buttons on the same view similar to this post: http://blog.ashmind.com/2010/03/15/multiple-submit-buttons-with-asp-net-mvc-final-solution/
The solution works however, when I introduce the RemoteAttribute in my model, the controllerContext.RequestContext.HttpContext.Request no longer contains any of my submit buttons which causes the the "multi-submit-button" solution to fail.
Has anyone else experienced this scenario?
I know this is not a direct answer to your question, but I would propose an alternative solution to the multiple submit-buttons using clientside JQuery and markup instead:
Javascript
<script type="text/javascript">
$(document).ready(function () {
$("input[type=submit][data-action]").click(function (e) {
var $this = $(this);
var form = $this.parents("form");
var action = $this.attr('data-action');
var controller = $this.attr('data-controller');
form.attr('action', "/" + controller + "/" + action);
form.submit();
e.preventDefault();
});
});
</script>
Html
#using (Html.BeginForm())
{
<input type="text" name="name" id="name" />
<input type="submit" value="Save draft" data-action="SaveDraft" data-controller="Home" />
<input type="submit" value="Publish" data-action="Publish" data-controller="Home" />
}
It might not be as elegant as a code-solution, but it offers somewhat less hassle in that the only thing that actually changes is the action-attribute of the form when a submitbutton is clicked.
Basically what it does is that whenever a submit-button with the attribute data-action set is clicked, it replaces its parent forms action-attribute with a combination of the attributes data-controller and data-action on the clicked button, and then fires the submit-event of the form.
Of course, this particular example is poorly generic and it will always create /Controller/Action url, but this could easily be extended with some more logic in the click-action.
Just a tip :)
i'm not sure that its a bug in mvc 3 as it's not something that you were expecting. the RemoteAttribute causes javascript to intercept and validate the form with an ajax post. to do that, the form post is probably canceled, and when the validation is complete, the form's submit event is probably called directly, rather than using the actual button clicked. i can see where that would be problematic in your scenario, but it makes sense. my suggestion, either don't use the RemoteAttributeand validate things yourself, or don't have multiple form actions.
The problem manifests itself when the RemoteAttribute is used on a model in a view where mutliple submit buttons are used. Regardless of what "multi-button" solution you use, the POST no longer contains any submit inputs.
I managed to solve the problem with a few tweeks to the ActionMethodSelectorAttribute and the addition of a hidden view field and some javascript to help wire up the pieces.
ViewModel
public class NomineeViewModel
{
[Remote("UserAlreadyRegistered", "Nominee", AdditionalFields="Version", ErrorMessage="This Username is already registered with the agency.")]
public string UserName { get; set; }
public int Version {get; set;}
public string SubmitButtonName{ get; set; }
}
ActionMethodSelectorAttribute
public class OnlyIfPostedFromButtonAttribute : ActionMethodSelectorAttribute
{
public String SubmitButton { get; set; }
public String ViewModelSubmitButton { get; set; }
public override Boolean IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
var buttonName = controllerContext.HttpContext.Request[SubmitButton];
if (buttonName == null)
{
//This is neccessary to support the RemoteAttribute that appears to intercepted the form post
//and removes the submit button from the Request (normally detected in the code above)
var viewModelSubmitButton = controllerContext.HttpContext.Request[ViewModelSubmitButton];
if ((viewModelSubmitButton == null) || (viewModelSubmitButton != SubmitButton))
return false;
}
// Modify the requested action to the name of the method the attribute is attached to
controllerContext.RouteData.Values["action"] = methodInfo.Name;
return true;
}
}
View
<script type="text/javascript" language="javascript">
$(function () {
$("input[type=submit][data-action]").click(function (e) {
var action = $(this).attr('data-action');
$("#SubmitButtonName").val(action);
});
});
</script>
<% using (Html.BeginForm())
{%>
<p>
<%= Html.LabelFor(m => m.UserName)%>
<%= Html.DisplayFor(m => m.UserName)%>
</p>
<input type="submit" name="editNominee" value="Edit" data-action="editNominee" />
<input type="submit" name="sendActivationEmail" value="SendActivationEmail" data-action="sendActivationEmail" />
<%=Html.HiddenFor(m=>m.SubmitButtonName) %>
<% } %>
Controller
[AcceptVerbs(HttpVerbs.Post)]
[ActionName("Details")]
[OnlyIfPostedFromButton(SubmitButton = "editNominee", ViewModelSubmitButton = "SubmitButtonName")]
public ActionResult DetailsEditNominee(NomineeViewModel nom)
{
return RedirectToAction("Edit", "Nominee", new { id = nom.UserName });
}
[AcceptVerbs(HttpVerbs.Post)]
[ActionName("Details")]
[OnlyIfPostedFromButton(SubmitButton = "sendActivationEmail", ViewModelSubmitButton = "SubmitButtonName")]
public ActionResult DetailsSendActivationEmail(NomineeViewModel nom)
{
return RedirectToAction("SendActivationEmail", "Nominee", new { id = nom.UserName });
}
[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
public ActionResult UserAlreadyRegistered(string UserName, int Version)
{
//Only validate this property for new records (i.e. Version != zero)
return Version != 0 ? Json(true, JsonRequestBehavior.AllowGet)
: Json(! nomineeService.UserNameAlreadyRegistered(CurrentLogonDetails.TaxAgentId, UserName), JsonRequestBehavior.AllowGet);
}
I encountered the same issue.
I also attached an on submit event to prepare the form before submit. Interestingly, when I insert a break point in the on submit function, and then continue, the problem has disappeared.
I ended up with an Ajax form by removing the Remote attribute and validate the field using the ModelState.

Ajaxified link in MVC3/JQuery not working in IE8 (missing header)

Consider the following code (it is based on a default EMPTY MVC3 project created in visual web developer express 2010sp1):
_Layout.cshtml:
<!DOCTYPE html>
<html>
<head>
<title>#ViewBag.Title</title>
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
</head>
<body>
<div id="header">header</div>
<div id="main">#RenderBody()</div>
</body>
</html>
Index method of HomeController:
public ActionResult Index()
{
if (Request.IsAjaxRequest())
{
ViewBag.Message = "partial";
return PartialView();
}
else
{
ViewBag.Message = "full";
return View();
}
}
Index.cshtml:
<script type="text/javascript">
$(function () {
$('#myLink').click(function () {
$.post(this.href, function (result) {
$('#main').html(result);
alert(result);
});
return false;
//$('#main').load(this.href);
//return false;
});
});
</script>
HomeController index. #ViewBag.Message
#Html.ActionLink("Index", "Index", new { controller = "Home" }, new { id = "myLink" } );
The problem is that in IE8 when the myLink link is clicked, it doesn't update the main div with only the partial html from Index.cshtml but the complete html including the layout. Ofcourse it works fine in FF, I mean why shouldn't it right? It seems Request.IsAjaxRequest() always evaluates to false in IE8. I understand that it is a result of a header X-Requested-With not being attached to a request in IE8. I don't have a lot of experience with web development -- is this a common issue and what is the (best) way to solve this?
UPDATE:
Yesterday I got it working normally in IE8, but when I tried it again this morning, the same problem was back. Now I don't think it has anything to do with the settings in IE8 anymore as I restored the settings to the default values. I tried examining the request with the fiddler tool. In order for me to be able to capture the traffic from localhost with fiddler, I added a period to the address: http://localhost.:3157/. So now the error occurs only when I use http://localhost.:3157/ (with period) and it works normally when I use http://localhost:3157/ (without period). I additionally tested the behavior in Chrome, Opera and Safari -- the ajax link works normally in these browsers. Note that I can get it working normally in IE8 when I attach a query parameter to the ajax link like so:
#Html.ActionLink("Index", "Index", new { controller = "Home", param = "param" }, new { id = "myLink" } )
I don't really want to do this. I'm running low on ideas here. I'm probably missing something that is blatantly obvious to a seasoned web developer =] Anybody recognize these symptoms?
You probably want to use the .live() method instead of .click():
$('#myLink').live('click', function () {
...
return false;
});
because you are replacing the DOM in the AJAX callback (the #main) which contains the link so you are killing the event handler you have assigned.
Also you have a typo in the jquery script inclusion in the <head>. You are missing a closing > after type="text/javascript":
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
So here's a complete working example:
_Layout.cshtml:
<!DOCTYPE html>
<html>
<head>
<title>#ViewBag.Title</title>
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
</head>
<body>
<div id="header">header</div>
<div id="main">#RenderBody()</div>
</body>
</html>
HomeController:
public class HomeController : Controller
{
public ActionResult Index()
{
if (Request.IsAjaxRequest())
{
ViewBag.Message = "partial";
return PartialView();
}
else
{
ViewBag.Message = "full";
return View();
}
}
}
Index.cshtml:
<script type="text/javascript">
$(function () {
$('#myLink').click(function () {
$.post(this.href, function (result) {
$('#main').html(result);
});
return false;
});
});
</script>
HomeController index. #ViewBag.Message
#Html.ActionLink("Index", "Index", new { controller = "Home" }, new { id = "myLink" } )
add
jQuery.ajaxSetup({
beforeSend: function(xhr) {
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
}
});
to make sure the correct header is attached.

"UpdatePanel" in Razor (mvc 3)

Is there something like UpdatePanel (in ASPX) for Razor?
I want to refresh data (e.g. table, chart, ...) automaticly every 30 seconds.
Similar to clicking the following link every 30 seconds:
#Ajax.ActionLink("Refresh", "RefreshItems", new AjaxOptions() {
UpdateTargetId = "ItemList",
HttpMethod = "Post"})
Edit:
I may should add that the action link renders a partial view.
Code in cshtml:
<div id="ItemList">
#Html.Partial("_ItemList", Model)
</div>
Code in Controller:
[HttpPost]
public ActionResult RefreshItems() {
try {
// Fill List/Model
...
// Return Partial
return PartialView("_ItemList", model);
}
catch (Exception ex) {
return RedirectToAction("Index");
}
}
It would be create if the PartielView could refresh itself.
You can try something similar to the following using Jquery (have not tested though)
<script type="text/javascript">
$(document).ready(function() {
setInterval(function()
{
// not sure what the controller name is
$.post('<%= Url.Action("Refresh", "RefreshItems") %>', function(data) {
// Update the ItemList html element
$('#ItemList').html(data);
});
}
, 30000);
});
</script>
The above code should be placed in the containing page i.e. not the partial view page. Bear in mind that the a partial view is not a complete html page.
My initial guess is that this script can be placed in the partial and modified as follows. Make sure that the ajax data type is set to html.
<script type="text/javascript">
setInterval(function()
{
// not sure what the controller name is
$.post('<%= Url.Action("Refresh", "RefreshItems") %>', function(data) {
// Update the ItemList html element
$('#ItemList').html(data);
});
}
, 30000);
</script>
Another alternative is to store the javascript in a separate js file and use the Jquery getScript function in ajax success callback.
Well, if you don't need the AJAX expierience than use the HTML tag:
<meta http-equiv=”refresh” content=”30; URL=http://www.programmingfacts.com”>
go here: http://www.programmingfacts.com/auto-refresh-page-after-few-seconds-using-javascript/
If someone wants the complete code for a selfupdating partial view have a look!
Code of the Controller:
[HttpPost]
public ActionResult RefreshSelfUpdatingPartial() {
// Setting the Models Content
// ...
return PartialView("_SelfUpdatingPartial", model);
}
Code of the Partial (_SelfUpdatingPartial.cshtml):
#model YourModelClass
<script type="text/javascript">
setInterval(function () {
$.post('#Url.Action("RefreshSelfUpdatingPartial")', function (data) {
$('#SelfUpdatingPartialDiv').html(data);
}
);
}, 20000);
</script>
// Div
<div id="SelfUpdatingPartialDiv">
// Link to Refresh per Click
<p>
#Ajax.ActionLink("Aktualisieren", "RefreshFlatschels", new AjaxOptions() {
UpdateTargetId = "FlatschelList",
HttpMethod = "Post", InsertionMode = InsertionMode.Replace
})
</p>
// Your Code
// ...
</div>
Code to integrate the Partial in the "Main"-View (ViewWithSelfupdatingPartial.cs):
#Html.Partial("_FlatschelOverview", Model)
The <meta refresh ..> tag in HTML will work for you. Its the best option
Traditional controls don't works in ASP MVC
You could do it using Jquery timers http://plugins.jquery.com/project/timers
Other option could be to use the Delay function
In your target is as simple as refresh the whole page, this SO link will be of your interest: Auto refresh in ASP.NET MVC
Hope It Helps.

Resources