Controller methods when submitting an AJAX request - c#

I have an MVC project that has a page with several forms on it. Most of the content on the page is rendered based on an initial form that a user submits. When a user updates information on that page I don't want the entire page to refresh I just need it to submit the form and stay on the page. I've tried to setup the form to submit with AJAX, but I don't know what to make the controller method return to accomplish this.
Form:
<div id="HeatNameDiv" title="Change Heat Name">
#using (Ajax.BeginForm("ChangeHeatName", "Home", new AjaxOptions(){UpdateTargetId = "HeatNameDiv"}))
{
<section>
Heat Name:<input type="text" name="heatName" value="#Html.ValueFor(x => x.heatname)" style ="width:100px"/>
Change to:<input type="text" name="updatedHeat" value="" style="width: 100px" />
<input type="submit" name="ChangeHeatName" value="Change" />
</section>
}
Current Controller:
public ActionResult ChangeHeatName(string heatName, string updatedHeat)
{
string user = User.Identity.Name;
HomeModel H = new HomeModel();
H.ChangeHeatName(heatName, updatedHeat, user);
return Content("Index");
}

It depends on what you want refreshed. Ajax.BeginForm expects an HTML fragment. So you need a partial that represents the heatNameDiv that you want to replace after submit:
public ActionResult ChangeHeatName(string heatName, string updatedHeat)
{
string user = User.Identity.Name;
HomeModel H = new HomeModel();
H.ChangeHeatName(heatName, updatedHeat, user);
return PartialView("NameOfPartialView", H);
}
I agree with Jeremy because Ajax.BeginForm is less flexible. I have tried hard to use it in the past, but the fact that it replaces the target element, instead of the innerHtml of the target, makes it difficult for many scenarios.
With $.ajax you can set url: '#(Url.Action("MyActionReturningAPartialView"))' and in the .success callback function(response) { $('#heatNameDiv').innerHtml(response); }
The action you call still returns a PartialView.

Related

MVC, how to post data to controller and redirect to aspx page

I have an MVC view where user can set a flag and post data to controller (post because I want to hidden query string)
After the controller have done his job I want to redirect to website home page that is an aspx page (my site is mixed aspx and MVC)
Is there a way to do that?
This is my view
#model MessaggiVM
<form role="form" class="form-inline" method="post" action="Messaggi/VaiAllaHome">
<button id="btnHome">Vai alla pagina iniziale</button>
<div class="form-group">
<label for="nascondi">hiding</label>
<input id="nascondi" type="checkbox" name="nascondi" value="true" />
</div>
<input type="hidden" name="elencoPost" value="#Model.Posts" />
#*#Html.ActionLink("Messaggi", "VaiAllaHome", new { posts = Model.Posts} )*#
</form>
And this the controller
[HttpPost]
public RedirectResult VaiAllaHome(bool? nascondi = false, IEnumerable<Messaggio> elencoPost = null)
{
// do something
return Redirect(Url.Content("~/"));
}
When I run this code controller action is executed without error but redirect is not done and browser remain on the view
Other problem is that elencoPost parameter is empty in the action but I'm investigating it
EDIT
Honestly I'm thinking to post data on input change and switch button for a simply link
EDIT 2:
found the reason: in default.aspx i have a auto-redirect to Message page :(
Try
return Redirect("~/home.aspx");
or
return Redirect(Url.Content("~/home.aspx")
You should be able to use Redirect with a relative url:
[HttpPost]
public RedirectResult VaiAllaHome(bool? nascondi = false, IEnumerable<Messaggio> elencoPost = null)
{
// do something
return Redirect("/home.aspx");
}
Try using a #Url.Content on your form tag
<form action="#Url.Content("~/Messaggi/VaiAllaHome/")">
Then in your Controller
[HttpPost]
public RedirectResult VaiAllaHome(bool? nascondi = false, IEnumerable<Messaggio> elencoPost = null)
{
// do something
return View(Url.Content("~/"));
//return RedirectToAction("Action", "Controller", new { routeParameter = value } /*e.g. "id = 1"*/);
}

html form posting to mvc controller

I am trying to set up a simple login html page, whose action is sent to mvc controller on another of my sites. I have no problem setting up the page to do the post, and in the mvc controller I have my method that reads the form post. The problem is that I am not seeing my fields from the html form in the form collection.
Is there something special that I need to do to read a form post within a mvc controller method, if so what is that?
The is the form action markup from my page
<form action="http://reconciliation-local.sidw.com/login/launch" method="post">
User Name <input type="text" id="username"/><br/>
Password <input type="text" id="password"/>
<input type="submit" value="launch"/>
</form>
The controller method
[HttpPost]
public ActionResult launch(FormCollection fc)
{
foreach (string fd in fc)
{
ViewData[fd] = fc[fd];
}
return View();
}
When I step through the controller method code, I am not seeing anything in the formcollection parameter.
Post Html To MVC Controller
Create HTML page with form (don't forget to reference a Jquery.js)
<form id="myform" action="rec/recieveData" method="post">
User Name <input type="text" id="username" name="UserName" /><br />
Password <input type="text" id="password" name="Password"/>
<input type="submit" id="btn1" value="send" />
</form>
<script>
$(document).ready(function () {
//get button by ID
$('#btn1').submit(function () {
//call a function with parameters
$.ajax({
url: 'rec/recieveData', //(rec)= Controller's-name
//(recieveData) = Action's method name
type: 'POST',
timeout: '12000', (optional 12 seconds)
datatype: 'text',
data: {
//Get the input from Document Object Model
//by their ID
username: myform.username.value,
password: myform.password.value,
}
});
});
});
</script>
Then in The MVC Controller
controller/action
| |
1. Create Controller named rec (rec/recieveData)
Create View named rec.cshtml
Here is the controller:
public class recController : Controller
{
// GET: rec
string firstname = "";
string lastname = "";
List<string> myList = new List<string>();
public ActionResult recieveData(FormCollection fc)
{
//Recieve a posted form's values from parameter fc
firstname = fc[0].ToString(); //user
lastname = fc[1].ToString(); //pass
//optional: add these values to List
myList.Add(firstname);
myList.Add(lastname);
//Importan:
//These 2 values will be return with the below view
//using ViewData[""]object...
ViewData["Username"] = myList[0];
ViewData["Password"] = myList[1];
//let's Invoke view named rec.cshtml
// Optionaly we will pass myList to the view
// as object-model parameter, it will still work without it thought
return View("rec",myList);
}
}
Here is the View:
#{
ViewBag.Title = "rec";
}
<h2>Hello from server</h2>
<div>
#ViewData["Username"]<br /> <!--will display a username-->
#ViewData["Password"] <!-- will display a password-->
</div>
If you posted some code it would be much easier to help you, so please edit your question...
Make sure that your form's action has the correct address, that your method is specifying POST (method="POST") and that the input fields under your form have name attributes specified.
On the server side, try making your only parameter a FormCollection and test that the fields in your form posted through the debugger. Perhaps your model binding isn't correct and the FormCollection will at least show you what got posted, if anything.
These are just common issues I've seen. Your problem could be different, but we need to see what you're working with to be able to tell.
Try something like this:
cQuery _aRec = new cQuery();
_aRec.Sqlstring = "SELECT * FROM Admins";
DataSet aDS = _aRec.SelectStatement();
DataTable aDT = aDS.Tables[0];
foreach (DataRow aDR in aDT.Rows){
if (txtAdminUsername.Text == aDR[0].ToString()){
if (txtAdminPassword.Text == aDR[1].ToString()){
Session["adminId"] = aDR[0];
Response.Redirect("Admin.aspx");
return;
}
}
}
Make sure that your FormCollection object properties for username and password are defined properly.
I had to use the name attribute on the text tag, and that solved my problem, is now working like a charm.
You have to use Ajax to do that.. Whenever you want to "submit" from client side, you should use Ajax to update the server
Step 1 - you redirect your Ajax call to your action, but with your list of parameters in the query-string appended
$.ajax(url: url + "?" + your_query_string_parameter_list_you_want_to_pass)
Step 2 - add optional parameters to your Controller-action with the same names and types you expect to get returned by the client
public ActionResult MyControllerAjaxResponseMethod(type1 para1 = null,
type2 para2 = null,
type3 para3 = null, ..)
Know that the optional parameters have to be initialized, otherwise the Action itself will always ask for those
Here's where the "magic" happens though --> MVC will automatically convert the query-string parameters into your optional controller-parameters if they match by name
I was also looking for a good answer for this, --> i.e. - one that doesn't use q-s for that usage, but couldn't find one..
Kinda makes sense you can't do it in any other way except by the url though..

MVC4 Ajax form in partial view returns whole page when inside kendo window

I've searched and searched and for the life of me cannot figure out what I'm doing wrong. I have a Kendo UI window like so:
<a id="#(item.POD_ID)" class="k-button btn-reminder" title="Add Reminder" onclick="$('#windowR#(item.POD_ID)').data('kendoWindow').open();"><span class="icon-reminder icon-only btn-reminder"></span></a
#(Html.Kendo().Window()
.Name("windowR" + item.POD_ID)
.Title("Set Reminder")
.Content("loading...")
.LoadContentFrom("_LoadReminder", "Purchasing", new { id = item.POD_ID })
//.Iframe(true)
.Draggable()
//.Resizable()
.Modal(true)
.Visible(false)
.Width(200)
.Height(80)
.Events(events => events
.Close("onCloseReminder")
.Open("onOpenReminder")
.Deactivate("function() { this.refresh();}")
.Activate("function(){ $('#empNumBox').focus(); }")
)
)
And, if the window is an Iframe, all of this works just fine, however I cannot have it as an Iframe, because that means reloading all of the scripts and styles within it and more difficult to reference parent.
So this window, loads content from the partial view like so:
#using (Ajax.BeginForm("SetReminders", "Purchasing", new AjaxOptions { UpdateTargetId = "result" }))
{
<div id="result"></div>
<input type="number" id="empNumBox" name="empNum" style="width: 70px" class="k-textbox" required autofocus="autofocus" value="#(ViewBag.EMP_NUM)"/>
<input type="hidden" value="#ViewBag.POD_ID" name="podID" id="POD_ID_Form_Field"/>
<input type="submit" id="submitReminder_button" style="width:auto;" class="k-button submitReminder_button" value="Remind" />
}
That partial view also renders fine. Here is the problem though, when you submit the ajax form, and the kendo window is not an iframe, it will render the whole page as whatever the controller returns (and I have tried several things, you can see in the commented out code below:
[HttpPost]
public ActionResult SetReminders(int empNum, int podID)
{
//some database stuff that works fine
string response;
if (existingReminder == 0)
{
//more db stuff that also works fine
db.SaveChanges();
response = "Success!";
}
else
{
response = "Reminder exists.";
//return PartialView("_LoadReminder", new string[] { "Reminder already exists!" });
}
// $('#submitReminder_button').closest('.k-window-content').data('kendoWindow').close();
//alert('Hello world!');
//return Content("<script type='text/javascript/>function(){alert('Hello world!');}</script>");
return PartialView("_SubmitSuccess");
//return Json(response);
//return Content(response, "text/html");
}
If anyone is curious, all that the _SubmitSuccess contains is the word "Success!".
Here's an example that I found with the ajax response being put in a div, which I followed:
http://pratapreddypilaka.blogspot.com/2012/01/htmlbeginform-vs-ajaxbeginform-in-mvc3.html
It seems the real issue here is the Kendo window, but I have yet to find something on their forums about this, doesn't seem that there's a lot of examples of using a kendo window to load a partial view that submits an form via ajax and returns a different partial view to be loaded within the same window and does not use an iframe.
Any suggestions welcome, even about other parts of the code, I'm always looking to improve.
Try changing the return type of SetReminders() to PartialViewResult

New to ASP.NET MVC, having trouble with render action containing a form

I am used to ASP.NET web forms, and am slowly learning ASP.NET MVC.
My website has a little login form on the homepage. My natural thought is that this login form may be useful in other places, and it is not the primary action of the homepage, so I want to separate it off into a partial view. And because it is related to accounts, I want the login in my AccountController not my HomepageController.
Login form is a pretty basic strongly typed partial view:
#model Models.Account.AccountLogin
<h2>Login Form</h2>
#using (Html.BeginForm("_Login", "Account")) {
#Html.ValidationSummary()
<div>
<span>Email address:</span>
#Html.TextBoxFor(x => x.EmailAddress)
</div>
<div>
<span>Password:</span>
#Html.PasswordFor(x => x.Password)
</div>
<div>
<span>Remember me?</span>
#Html.CheckBoxFor(x => x.RememberMe)
</div>
<input type="submit" value="Log In" />
}
</div>
On the homepage, I have this:
#Html.Action("_Login", "Account")
Finally, in the account controller, this:
[HttpGet]
public PartialViewResult _Login()
{
return PartialView();
}
[HttpPost]
public PartialViewResult _Login(AccountLogin loginDetails)
{
// Do something with this
return PartialView();
}
Now when I load my homepage, it looks OK and contains the form. When I click the Log In button, it takes me to myurl/Account/_Login, which contains the form, but not within the _Layout master page, just basic plain HTML and it doesn't do anything at all when I click Log In.
I am pretty sure that I have just missed some fundamental aspect of what I am supposed to be doing here, can someone please point me in the right direction?
It's because you're returning a partial view, which strips away the master page and just returns the main content. Often actions starting with an underscore are used for partials (e.g. ajaxing in a bit of a page, but not the full page). It sounds like you want a full action, and not a partial, so
[HttpPost]
public ActionResult Login(AccountLogin loginDetails)
{
// Do something with this
return View();
}
The issue here is that you are doing a fullpage postback.
You have two options, really.
Firstly, you can use a full page postback, and then call Html.Partial to display your Partial.
Something like
[HttpGet]
public ActionResult Login()
{
return View();//this typically returns the view found at Account/Index.cshtml
}
And then create a View along the lines of
#{
ViewBag.Title = "Index";
}
<h2>Title</h2>
#Html.Partial("PartialNameGoesHere")
Your partial is then rendered where indicated, but this is done when the page loads (if you look at the generated HTML, it appears exactly as though you had written it inline).
Or you can use jQuery/AJAX to load the partial on demand. Let's say you have a homepage of some description
public ActionResult Home()
{
return View();
}
public ActionResult Login()
{
return PartialView("_Login");
}
Create the view
#{
ViewBag.Title = "Index";
}
<h2>Home</h2>
<div>
<p>Hey welcome to my pretty awesome page!</p>
</div>
Show me the login!
<div id="container">
</div>
You can then load the PartialView into the container div whenever you need it, using some JS.
$(function() {
$('.my-login-link').click(function() {
$.ajax({
url: 'account/login',
success: function(data) {
$('#container').html(data);
}
});
return false;//cancel default action
});
});
In that instance, the page loads as normal without the login part. When the user clicks the link, the Login on the controller Account is called using AJAX/jQuery. This returns the HTML of the PartialView, which you can then add to the page using jQuery in the Success handler.

Save State of Search

I have a web page that builds a table of search results. the user can then edit those items. When the user is returned to the page it returns to it's unsearched state (as it is designed).
I want to have them return to the query. how can i save that page state?
#model List<MyNamespace.Models.MyModel>
#{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
#using (Ajax.BeginForm("Search", "MyController",
new AjaxOptions
{
HttpMethod = "GET",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "searchResults"
}))
{
<input type="text" name="q" data-autocomplete="#Url.Action("SearchProviders", "MyController")" />
<input type="submit" value="Search" />
}
<div id="searchResults" />
Controller Action:
public PartialViewResult Search(string q)
{
var jobs = MyRepository.GetJobsByQuery(String.Format("DataProvider='{0}'", q));
return PartialView("_MyPartialRowset", jobs);
}
I'd suggest having your search form submit using HTTP GET; the search parameters/terms could be included in the query string of the search results page, like this:
/Search?q=cthulhu
Then, make all of your edit links so that they have a returnUrl in the query string:
/Things/235/Edit?returnUrl=%2FSearch%3Fq%3Dcthulhu
When the save or cancel completes, return to the page specified in returnUrl. That way, no matter where the edit was opened from, you can use the same logic to return to the previous page.
As part of this, I'd also make the search results page is not cached.
Update:
If your search is done through AJAX, then the easiest way for you to preserve the search parameters to auto-populate when the user comes back is to place the search parameters in a cookie.

Categories