I have a Controller which has a Create method to handle HttpPost data from a form. The page containing the form is accessed by the URL
CallOutcome/Call?orderId=114565
When the form is submitted, I do a db insert & create a view model object which is returned to the view to display the form again. This works fine, however the URL has now changed to the name of my action method:
CallOutcome/Create
How can I make it show the original URL? The desired result would be like that it worked like a postback, i.e. reshowing the same page and URL.
This is my (simplified) action method, which returns a CallDetailsViewModel object to a view named 'Call':
[HttpPost]
public ActionResult Create(GGAP_CallOutcome callOutcome)
{
if (ModelState.IsValid)
{
callRepository.SaveCallOutcome(callOutcome);
return View("Call", new CallDetailsViewModel{
CustomerOrder = new CustomerOrder{},
CallOutcome = new CallOutcome{},
Task = new Task{}
});
}
}
not many responses! too close to christmas maybe?
For the record, I used RedirectToRoute:
return RedirectToRoute(new
{
controller = "CallOutcome",
action = "Call",
orderId = Convert.ToInt32(callOutcome.OrderId)
});
Which does exactly what I wanted.
Related
I have my site like http://mysite.com/ and on the index page i have search box and for the result i am using jqgrid. When user click row in the jqgrid row I am taking data from cells and do ajax call to server and fetch json data and once data arrived I hide the search box and jqgrid and show another div which is I kept for result. In short, user will be on the same page just div's hide/show.
Now I have seen history api and used pushState and popstate so my url becomes in the addressbar like http://mysite.com/controller/action/para1/para2 (here para1 and para2 are the parameters i am passing to action). Everything is ok so far.
Now the problem is if I copy this URL "http://mysite.com/controller/action/para1/para2" and if I open this with let's say different browser and hit enter it display just json data. So, I am confused that how to handle when user directly use that url in controller.
I was thinking to check in the controller action if the request is AJAX then return json data otherwise full page, is that right approach? OR something on the client side we have so that it load the same way as earlier.
Thanks
if I copy this URL "http://mysite.com/controller/action/para1/para2" and if I open this with let's say different browser and hit enter it display just json data.
it only display json data because its ajax call only so how to deal with that so that it also display the same page even user directly access the url.
I think what you're looking for is Request.IsAjaxRequest():
public class FooController : Controller {
public ActionResult GetFoo(int id) {
var model = _fooService.Get(id);
if (Request.IsAjaxRequest())
return PartialView("_Foo", model);
return View("Foo", model);
}
}
Note: It's recommended to use WebAPI controllers to handle only json data. So if the user got there by typing the url the mvc controller will handle it and if you need to get the json data for that view you could call the webapi controller.
Use a separate controller or action method for AJAX and for Views. The View controller should match the URL. The Ajax controller should be the less "pretty" URL since it's behind the scenes.
You need to set up a routing definition in global.asax (MVC 3) or App_Start/RouteConfig.cs (MVC 4) to handle the parameters if you haven't already done that.
routes.MapRoute(
"MyRoute",
"MyUrlController/{action}/{para1}/{para2}",
new
{
action = "Index",
para1 = UrlParameter.Optional,
para2 = UrlParameter.Optional
}
);
Then in the View controller:
public ActionResult Index(string para1 = "Default Value", string para2 = "Default Value")
{
// ...Handle parameters...
return View("_MyView", viewModel);
}
Returning a View object type is the key. The History API URL doesn't get it's data from the same AJAX source controller which returns a PartialViewResult.
In asp.net mvc3,
I am using a javascript API to dynamically render a user interface. Part of the input section is going to be dependent on how many items the user wants to enter data for. As a result, something like this wont work
#(Html.EditorFor(m => m.P[5].C.Description))
because that cannot be done during runtime. What type of process would I use to call that helper during runtime with AJAX? Would I have a controller action which only returned that information which was called using $.ajax()? Would it be in a different place than a controller action?
At run time you could perform an ajax get to a controller action that will render a view as a string, which in turn could be inserted / appended into the DOM.
Create a new action result that returns JSON as per below:
return new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new { html = this.RenderPartialViewToString("YourPartialView", model) }
};
Note, the above makes use of the following controller extension:
public static string RenderPartialViewToString(this Controller controller, string viewName = null, object model = null)
{
if (string.IsNullOrEmpty(viewName))
{
viewName = controller.ControllerContext.RouteData.GetRequiredString("action");
}
controller.ViewData.Model = model;
using (var sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
For further reading regarding this extension method: http://craftycodeblog.com/2010/05/15/asp-net-mvc-render-partial-view-to-string/
All that would remain would be to perform a get passing a parameter signifying the number of items to render and append the returned content into your view. Perhaps something like:
$.getJSON('url', numberofitems, function (data) {
$('#somecontainer').html(data.html);
});
If you are pulling HTML and inserting it into the DOM, you don't have to go via JSON.
Just have your action return a PartialView. It's already in the form of Html, and ready to be inserted into your DOM
JS
$.getJSON('/someurl/GetMyView',{count:10}, function (data) {
$('#target').html(data);
});
Controller:
[HttpGet]
public ActionResult GetMyView(int count)
{
MyModel model = //Get the model from somewhere
return PartialView(model);
}
View:
#model MyModel
<div>
#Model.SomeProperty
<div>
If I understand you correctly, you want to dynamically insert fields on the client to allow users to add N-number of fields without having a bazillion pre-rendered fields on the form and you are trying to use ajax to do this?
I'm sure you could do it, by rendering the html on the server and pushing it up to the client... have you considered dynamically adding the to the page via javascript? Unlike Webforms, MVC does not care what elements were on the page when it was rendered, it only cares about the data it receives in the HttpPost.
I have a controller with an Index method that has several optional parameters for filtering results that are returned to the view.
public ActionResult Index(string searchString, string location, string status) {
...
product = repository.GetProducts(string searchString, string location, string status);
return View(product);
}
I would like to implement the PRG Pattern like below but I'm not sure how to go about it.
[HttpPost]
public ActionResult Index(ViewModel model) {
...
if (ModelState.IsValid) {
product = repository.GetProducts(model);
return RedirectToAction(); // Not sure how to handle the redirect
}
return View(model);
}
My understanding is that you should not use this pattern if:
You do not need to use this pattern unless you have actually stored some data (I'm not)
You would not use this pattern to avoid the "Are you sure you want to resubmit" message from IE when refreshing the page (guilty)
Should I be trying to use this pattern? If so, how would I go about this?
Thanks!
PRG Stands for Post-Redirect-Get. that means when you post some data to the server back, you should redirect to a GET Action.
Why do we need to do this ?
Imagine you have Form where you enter the customer registration information and clicking on submit where it posts to an HttpPost action method. You are reading the data from the Form and Saving it to a database and you are not doing the redirect. Instead you are staying on the same page. Now if you refresh your browser ( just press F5 button) The browser will again do a similar form posting and your HttpPost Action method will again do the same thing. ie; It will save the same form data again. This is a problem. To avoid this problem, We use PRG pattern.
In PRG, You click on submit and The HttpPost Action method will save your data (or whatever it has to do) and Then do a Redirect to a Get Request. So the browser will send a Get Request to that Action
RedirectToAction method returns an HTTP 302 response to the browser, which causes the browser to make a GET request to the specified action.
[HttpPost]
public ActionResult SaveCustemer(string name,string age)
{
//Save the customer here
return RedirectToAction("CustomerList");
}
The above code will save data and the redirect to the Customer List action method. So your browser url will be now http://yourdomain/yourcontroller/CustomerList. Now if you refresh the browser. IT will not save the duplicate data. it will simply load the CustomerList page.
In your search Action method, You dont need to do a Redirect to a Get Action. You have the search results in the products variable. Just Pass that to the required view to show the results. You dont need to worry about duplicate form posting . So you are good with that.
[HttpPost]
public ActionResult Index(ViewModel model) {
if (ModelState.IsValid) {
var products = repository.GetProducts(model);
return View(products)
}
return View(model);
}
A redirect is just an ActionResult that is another action. So if you had an action called SearchResults you would simply say
return RedirectToAction("SearchResults");
If the action is in another controller...
return RedirectToAction("SearchResults", "ControllerName");
With parameter...
return RedirectToAction("SearchResults", "ControllerName", new { parameterName = model.PropertyName });
Update
It occurred to me that you might also want the option to send a complex object to the next action, in which case you have limited options, TempData is the preferred method
Using your method
[HttpPost]
public ActionResult Index(ViewModel model) {
...
if (ModelState.IsValid) {
product = repository.GetProducts(model);
TempData["Product"] = product;
return RedirectToAction("NextAction");
}
return View(model);
}
public ActionResult NextAction() {
var model = new Product();
if(TempData["Product"] != null)
model = (Product)TempData["Product"];
Return View(model);
}
I am trying to pass a random string from my Controller to the View.
Here is my Controller code:
[HttpPost]
public ActionResult DisplayForm(UserView user)
{
//some data processing over here
ViewData["choice"] = "Apple";
return RedirectToAction("Next", "Account");
}
Now I want to pass that data value "Apple" to my view Next.cshtml which is created as follows:
//View: Next.cshtml
#{
ViewBag.Title = "Thanks for registering";
Layout = "~/Content/orangeflower/_layout.cshtml";
}
<p>Your favorite fruit is:</p>#ViewData["choice"]
But I am not able to see my data in the browser when the project runs.
Here is the snapshot:
1) On debug, the controller showing the value:
2) The browser view doesn't show the value "Apple"
3) On further debug to my Next.cshtml View:
Why is the value not getting passed to the View correctly. Both my controllers for Next and DisplayForm are within the same Controller AccountController.cs , still value not getting displayed.
Can someone help me solve this ?
You are not rendering a view, you are redirecting. If you wanted to pass some information tyo the view you need to return this view after adding it to ViewData:
[HttpPost]
public ActionResult DisplayForm(UserView user)
{
//some data processing over here
ViewData["choice"] = "Apple";
return View();
}
If you want to pass a message that will survive after a redirect you could use TempData instead of ViewData.
[HttpPost]
public ActionResult DisplayForm(UserView user)
{
//some data processing over here
TempData["choice"] = "Apple";
return RedirectToAction("Next", "Account");
}
then inside the Next action you could fetch the data from TempData and store it inside ViewData so that the view can read it.
You are performing a post - redirect - get. The ViewData is being set for this request, which returns a redirect, clearing the ViewData, then another request happens which does not have the data. Use TempData instead and it will be added to the ViewData automatically on the next request.
I'm trying to call an action in a separate controller with an actionlink.
The problem is that both the [HttpGet] and the [HttpPost] action gets called, and since the post-method returns the view from which the action is called, nothing gets displayed.
Get method:
[HttpGet]
public ActionResult View(int id, int index)
{
var form = formService.GetForm(id);
var pageModel = new PageViewModel();
var page = form.Pages.ElementAt(index);
ModelCopier.CopyModel(page, pageModel);
ModelCopier.CopyModel(form, pageModel);
return View(pageModel);
}
Post Method
[HttpPost]
public ActionResult View(PageViewModel pageViewModel)
{
if (!ModelState.IsValid)
{
return RedirectToAction("Details", "Forms", new { id = pageViewModel.FormId });
}
var pageToEdit = pageService.GetPage(pageViewModel.PageId);
ModelCopier.CopyModel(pageViewModel, pageToEdit);
pageService.SavePage();
return RedirectToAction("Details", "Forms", new {id = pageViewModel.FormId});
}
How it's called from the View (from a view returned by another controller):
#Html.ActionLink("View", "View", "Pages", new { id = Model.FormId, index = item.Index-1 }, null)
What am I doing wrong here? I essentially want it to work as an update/edit function. And the view returned contains a simple form for the viewmodel.
An action link issues a GET request. You will have to implement some JavaScript function that captures the url and parameters, and dynamically creates and submits a new form with a POST method, or does an Ajax POST. You could write your own HTML Helper, to wrap this functionality, but the default functionality of clicking an <a> tag (which is what is generated by a Html.ActionLink) will issue a GET request.
I don't think you'll be able to use an action link - see this question
The options are to use jQuery to post data or swap to a simple form and submit