MVC - HttpPost issue with Ajax - ajax

I have 2 HttpPost. One is called by Json. And another is called when user submits the page.
When User clicks Delete button on page, i call DeletePhone method which deletes the records but problem is it also calls the another [HttpPost](in below code 1st one).
How to stop calling another [HttpPost]?
[HttpPost]
public ActionResult Phones(Phones model)
{
....
}
[HttpPost]
public JsonResult DeletePhone(int documentid)
{
string phoneName = Session["PhoneName"].ToString();
bool result = settings.deletePhone(schemaName);
return Json(result, JsonRequestBehavior.AllowGet);
}

I think the problem is that you are taking your delete button as input type submit that is why it is
submitting the form..Just take it as input type button..

Related

Retaining failed validation data

I've got a requirement to keep and display an incorrect entry on the view. It isn't possible to go to the next page without passing all validation.
For example, the use has to enter a date in text field in a certain format. Currently if the model binding fails it doesn't keep the invalid date text entry. I'd like to keep t and display it back to user with a vanadium failed message.
I'd like to know if this is achievable without creating a data holder type which temporarily hold the entered game and parsed value.
Yes, it is possible. Because you haven't posted any code, I'll just give you an example of how this can be achieved using server side validation.
Here is the [HttpGet] action method that serves up the form allowing the user to enter data.
[HttpGet]
public ActionResult Create()
{
// The CreateViewModel holds the properties and data annotations for the form
CreateViewModel model = new CreateViewModel();
return View(model);
}
Here is the [HttpPost] action method that receives and validates the form.
[HttpPost]
public ActionResult Create(CreateViewModel model)
{
if (!ModelState.IsValid)
{
return Create(); // This will return the form with the invalid data
}
// Data is valid, process the form and redirect to whichever action method you want
return RedirectToAction("Index");
}
You can also use return View(model); in the [HttpPost] action method instead of return Create();.

MVC3: PRG Pattern with Search Filters on Action Method

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);
}

How do I perform error handling in ASP.NET MVC 3 controller?

I have an Account controller which have:
LoginForm (get action)
Login (post action)
RegisterForm (get action)
Register (post action)
In another controller's index action i use render them as:
Html.RenderAction("RegistrationForm", "Acount");
Html.RenderAction("LoginForm ", "Acount");
Everything works ok and I can register a new user, login and validate with unobtrusive validation.
The problem is when do some back-end validation in Register/Login action and if there is an error I don't know how to transfer the error to be rendered.
I've tried with PRG pattern and it works ok. I get the error displayed on the form with the preserved data, but PRG is not the way to do it.
What is an alternative solution to this problem without using ajax to validate or move those methods in the controller where the RegistrationForm/LoginForms are used?
I want to skip using TempData due to session usage in the background.
EDIT CODE SAMPLE:
class AccountController : SomeBaseController{
[HttpGet]
public PartialViewResult RegistrationForm()
{
return PartialView(new RegisterUser());
}
[HttpPost]
public ActionResult RegisterUser(RegisterUser user)
{
if (ModelState.IsValid)
{
var _user;// create domain user from Register user Model;
var _validationOutput = _userService.DoSomeAwsomeServerSideValidation(_user);// do some custom validation
if (_validationOutput.IsFault)
{
// we preseve tempdata in base controller OnActionExecuted
_validationOutput.ErrorMessages.ForEach(x => ModelState.AddModelError(_validationOutput.ErrorCode, _validationOutput));
// redirect to home controller custom error occured
return RedirectToAction("Index", "Home", user);
}
return RedirectToAction("RegistrationInfo");
}
return RedirectToAction("SomeUserInfoAction");
}
}
class HomeController : SomeBaseController {
Index(){
return View();
}}
HomeControllerMarkup {
#{Html.RenderAction("RegistrationForm", "Acount");}
#{Html.RenderAction("LoginForm", "Acount");}
}
You can manually add errors to your ModelState within your post controller using:
ModelState.AddModelError("", #"You didn't perform task XYZ");
You should then be able to return the view and display the errors in a validation summary:
#Html.ValidationSummary(false, "Login was unsuccessful because...")

Using ViewData to pass string from Controller to View in ASP.NET MVC3

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.

gets called from separate controller (ASP.NET MVC3)

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

Resources