how to call controller from button click without using ajax mvc - asp.net-mvc

I'm new to web programming in general so this is probably a really simple question. I couldn't find anything on the web however.
What I want to do is call my controller with the typed search string and return the results from a database and paginate the results. Right now I am using a function that is called when the button is pressed. The function looks like so:
function SubmitSearch() {
var searchBox = document.getElementById('searchBox');
var searchButton = document.getElementById('SearchButton');
$.post("MyController/MyAction/",
{
searchString: searchBox.value,
page: null
}, function(result) {
$('#searchResults').html(result);
searchButton.value = "Search";
});
}
What happens is my controller is called, and my searchResults div is populated with the results and paginated. The user can click any search result returned to view the details.
The problem is when the user clicks the browsers 'back' button, the page returns to the state before the search was entered, and this is because of the ajax call. What I want to do is, call the controller and have the page load like google would. Instead of using a PartialView, I would use a View (my guess).
How would I call the controller and have the page RELOAD with the results. I must be missing something fundamental because this definitely seems like it should be easy.

If you don't want to use AJAX then you need to place your text field in a form element on your page, something like:
<form action="MyController/MyAction/" method="get">
<input id="SearchBox" name="SearchBox" type="text" />
<button type="submit">Search</button>
</form>
Then in your controller return the view with the list of results.
You probably also want to look into RESTful URLs and the PRG (Post, Redirect, Get) pattern to maintain the integrity of the back button and enable correct bookmarking of pages etc.

I think you might actually be looking for an AJAX History library to help when the Back button is pressed rather than altering your app. Take a look at this blog post.

Aspx:
<% using (Html.BeginForm<MyController>(m => m.MyAction(null)) { %>
<%= Html.TextBox("q"); %>
<% } %>
// Listing
Controller:
public class MyController : Controller
{
public ActionResult MyAction(string q)
{
var repository; // instance of your repository.
if (String.IsNullOrEmpty(q))
{
return View(repository.GetAllBlogs());
}
return View(repository.SearchBlogs(q));
}
}

Related

ASP.NET MVC. Specific URL for partial views

I'm new to ASP.NET MVC. So my question may seem to be little bit naive. Anyway I've spent hours searching for any information on my topic, but no result. So I would be very grateful for your help.
So this is my problem.
In my Index view I have a div, where I put contents of different Partial Views depending on the link that user clicks.
Here's the code.
Index.cshtml:
<div id="dynamicContent"></div>
About Cbsr Agent
Application Areas Of CBSR
JavaScript:
function updateContent(contentUrl) {
$.ajax({
url: contentUrl,
type: "GET",
success: function (data) {
$('#dynamicContent').html(data);
}
});
}
Controller:
public class AgentController : Controller
{
//Index action
public ActionResult DynamicContent(string name)
{
return PartialView(String.Format("Partial/" + name));
}
}
So, everything works fine. When user clicks the link, the appropriate partial view is loading into the div.
The problem is that in adrees bar of a browser i get the following URL: example.com/Agent# whatever link i click.
So my question: Is there any way to generate the unique URL for each partial view? For example: example.com/agent/partial/AboutCbsrAgent. And is it possible to make so that when I paste this link into the browser's address bar, the whole view and NECESSARY partial view will be displayed?
Thank you in advance for your help!
You can create two separate actions in your AgentController, for the two URLs, and pass name of the partial view you want to render. Something like:
public ActionResult AboutCbsrAgent()
{
ViewBag.MyPartialView = "AboutCbsrAgent";
....
return View("Index");
}
Then in your Index.cshtml:
<div id="dynamicContent">
#Html.Partial(ViewBag.MyPartialView)
</div>
You'll probably need to adjust the paths, but you get the idea.
If you want to avoid the # in your url use:
About Cbsr Agent
If you know your users are mainly FF, Chrome, IE9 <, or you don't care if the browser doesn't support it, you can use history.pushState
Although you will still have to find a solution for loading the correct content if the user revisists that url (with pushState)

MVC controls not working properly without page refresh

I've got an MVC controller that can be called via form submission in a couple different places. The controller then renders a view whose primary purpose is to allow the user to send the document or post it to an external site, as well as fill in text fields that will be used in the notification email.
I am performing validation on these fields - the user can enter custom subject/body text. If they do not, they will receive a popup alert and can either return to the form or submit it using default text indicated in the placeholder value.
The problem is that when the user first reaches this page and clicks the send button, no input in the textboxes is actually registering and it gives the empty string notification regardless of what is actually in the fields; however, if I hit F5 and try again, the input works perfectly.
I feel like this has something to do with the form submissions that initially call this controller being done via POST action, whereas it seems to work fine with the GET on page refresh. I just can't figure out how to either get the content to respond properly when the controller is called via POST, or how to submit the form without posting the data.
Thanks in advance for reading and any help.
Here is the calling controller:
public ActionResult Index(FormCollection collection)
{
//modelbuilding code
return View (Model);
}
The code that calls the controller always uses this format: (in this case, it would be called from the Recipients/Index view.
#using(Html.BeginForm("Index", "Distribution", FormMethod.Post )) {
//form values
<input type="submit" data-role="button" value="Done"/>
}
Here is the relevant part of the view and the JS validation function:
<div id="SubjectTemplate">
<p>Subject: <input id="emailSubjectTextBox" name="EmailSubject" placeholder="#EmailSubject" /></p>
</div>
Send Notification
<script>
function validateInput() {
var possibleErrors = [];
if (!(document.getElementById('emailSubjectTextBox').value)) {
possibleErrors.push('#incompleteEmailSubject' + '\n');
}
//more validation that works the same way and has the same problem
if (possibleErrors.length > 0) {
if (confirm(possibleErrors))
{
window.location.href = '#Url.Action("Send")'
}
}
else {
window.location.href = '#Url.Action("Send")'
}
}
</script>
I'm not sure I fully understand your question, but generally speaking you should not use the same action for POST and GET.
Even more importantly, you should not be using POST if your action does not have some kind of side effect. If all you are doing with your form submission is making some kind of choice then you should be using GET.
See the following post for more information and examples of how to perform ajax GET requests using jQuery: http://www.jquery4u.com/ajax/key-differences-post/
Regardless of what you are trying to do, it is very good practice that POST calls perform some action, and then redirect to a GET action which returns to the user.
[HttpPost]
public ActionResult Index(FormCollection collection)
{
//do whatever you need to save the record
return RedirectToAction("Index")
}
[HttpGet]
public ActionResult Index()
{
//modelbuilding code
return View (Model);
}
Not only does this help your controller adhere to a RESTful methodology, it also stops the user getting that annoying 'Are you sure you want to resubmit this page' if they happen to press f5
Hope this helps.
I found the problem resulted from jQueryMobile automatically utilizing AJAX to post forms. I solved this by including new {data_ajax = "false"} to the Html.BeginForm statements.

How to implement a form button which doesn't change the page

I have a view with the following code:
#using (Html.BeginForm("GenerateQrCode", "QrCodeGenerator", FormMethod.Post ))
{
<input type="submit" value="Generate" />
}
It's just a submit button, which calls the code in my controller:
public void GenerateQrCode()
{
}
Is it possible for a method in my controller to return a value from the form, but without going to a different page? Because I notice that currently, on pressing the form button it tries to navigate to a non-existing 'GenerateQrCode' page (the same name as the controller method).
UPDATE:
Something I've tried is making the controller method return an ActionResult, and return a 'RedirectToAction', and simply calling the same view. However, I also had code in this method 'ViewBag.Message = "myMessage"; and then in my view I had the code '#ViewBag.Message', so I hoped that the view would update with the ViewBag message property, but it doesn't appear so.
The version of Html.BeginForm you're using tells the submit button to post to the GenerateQrCode action. Perhaps you could try another overload of Html.BeginForm that better suits your purposes?
Using javascript:
Handle the click event.
In the handler, prevent the default action and stop the event propagation.
Make and AJAX call to the server with the form data.
Get the response and take further actions.
So if I have this right, you want to submit an action without actually taking into account the response from the server. Sounds like you need jQuery post:
$.post(url, $("form selector").serialize(), function () {
// This is where you put a callback function.
});
That is all you need. This will post the data. What you can do is call this from a button click event instead of a form submit button. Or, you can override the submit event on the form and put this as your first line of code:
e.preventDefault();
where e is your event arguments. This will prevent the default action from occurring, which in this case is the submission of the form and the loading of the response.
The simplest method of doing this was simply to use the RedirectToAction method, specifying the name of the controller in the parameters. I also used the TempData variable to pass the results (in this case just a string value) back to the view, and into a ViewBag variable.
public ActionResult QrCodeGenerator()
{
ViewBag.Message = TempData["Message"];
return View();
}
public ActionResult GenerateQrCode()
{
TempData["Message"] = "myMessage";
return RedirectToAction("QrCodeGenerator");
}

View Master Page and PostBack

I have a dropdown list on my master page that needs to postback after being changed. After the postback, whatever page initiated the postback needs to be re-displayed.
My question is where do I handle this? Obviously I do not want to have to modify every Action in my project... My guess is to maybe postback to some other fixed action and have that action redirect back to the page that is the referrer. Am I correct? Any thoughts?
Thanks.
Jason
In Site.Master, I ended up wrapping the dropdown within its own form that posted back to a dedicated controller/action.
<% Using Html.BeginForm("ChangeRole", "Home")%>
<div id="roleSelector">Change Role: <%=Html.DropDownList("Role", DirectCast(ViewData.Item("Roles"), SelectList), New With {.onchange = "this.form.submit();"})%></div>
<% End Using%>
In the controller I used the following code to change the mode and then redirected back to the referring URL.
<AcceptVerbs(HttpVerbs.Post)> _
Public Function ChangeRole() As ActionResult
Me.CurrentUser.SetRole(DirectCast([Enum].Parse(GetType(Models.ApplicationRoles), Me.Request.Item("Role")), Models.ApplicationRoles))
Return Redirect(Request.UrlReferrer.ToString())
End Function
I am unsure if this is the recommended way but I have been unable to think of another solution.
When you post back from the dropdown list change what are you doing? Can you maybe handle this in a jQuery call thus eliminating the need to re-display the page at all?
Calls to Action Methods can be asynchronous as griegs says, as such, you can post whatever information you need from the radio buttons to an action method without needing to reload the page.
If you need to update a part of the page, you can replace it with the contents of a rendered action method. If you use the jQuery ajax methods, you can post specific information to your methods.
For example, something like this:
$(document).ready(function()
{
$("#myRadioButton").change(function()
{
//Post to your action method, with the value of the radio button, function to call on success
$.post('yourActionMethodUrl', $(this).val(), function()
{
//Update some part of the page
});
});
});
This is based on memory, so you may need to check the syntax.

asp.net mvc actionlink shows address in FF, cannot get button to function

I'm currently in the process of learning ASP MVC and am running into a few issues.
First, when I use
<%=Http.ActionLink("Add / Modify", "AddModify" %>
it will show as Add / Modify (/Home/AddModify) in Firefox and Add / Modify in IE. It is doing that to all links in FF and none in IE. Anyone know what reasoning is for that?
Edit: What is displayed in the browser (FF in this case) is "Add / Modify (/Home/AddModify)" while in IE shows just "Add / Modify".
Here is a screenshot of what I see on my site in FireFox: http://img6.imageshack.us/img6/1331/19748435.png
You can see how it shows the text and the appropriate link afterwards (only populated in Database with /).
Also, I am trying to have buttons (both standard and image) on my site which will link to new pages, while also performing hidden tasks (saving data, etc...). Anyways, When I do the following:
<form method="post" action="/Home">
<input type="submit" value="AddModify">
</form>
and the controller has a simple
[ActionVerbs(HttpVerbs.Post)]
public ActionResult AddModify()
{
return View();
}
And I still cannot get that function to call, yet when I do http://localhost:port/Home/AddModify, the function calls and I can get to that page. I am doing it this way because there may be code that has to execute before redirecting to that page, rather than just a direct link to that page. I have tried with and without the ActionVerbs line, I have tried this form of the Html Form:
<% using (Html.BeginForm()) { %> ... <%}%>
and still nothing. I have also tried no form and still nothing, but here's something that may affect this...I am using a master page with everything inside a content place holder inside a form that uses runat="server". Would that matter? So its Master Page -> form (masterform runat server) -> ContentPlaceHolder -> form (for postback and action) -> submit button. Any help would be greatly appreciated.
If I am thinking correctly, your form action should be calling the name of the action method:
<form method="post" action="/Home/AddModify">
<input type="submit" value="AddModify">
</form>
The ActionLink would be the same way.
Otherwise you will need to modify your routes to go to that action method by default.
Let's do this in two parts
1 I think your ActionLink should be:
<%=Http.ActionLink("Add / Modify", "AddModify", "Home")
...to force routes.
First parameter: text shown
Second parameter: action name
Third parameter: controller name
2 Change your submit button to: (I assume we're currently looking at your "index" action from your "Home" controller)
<form method="post" action="/Home">
<input type="submit" value="AddModify" name="ModifyBtn" >
</form>
Then in your Home controller:
edit:
//GET
public ActionResult Index()
{
return View();
}
/edit
[ActionVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection form, string ModifyBtn, string OtherBtn)
{
if (ModifyBtn!=null)
{
//do stuff
return RedirectToAction("AddModify");
}
if (OtherBtn!=null)
{
//do stuff
return RedirectToAction("OtherAction");
}
return View();
}
edit:
I think you're trying to submit directly to another Action. The best way is to handle the POST method inside your code then redirect to another action. That way, you can use
<% using (Html.BeginForm()) { %>
without trouble.
<form method="post" action="/Home">
Will create a form with a href of /Home, this will only call the AddModify action if the AddModify action is default on that route.

Resources