mvc3 ajax.actionlink coding for model failure - ajax

I'm using an ajax actionlink to allow the user to delete a record in the model (database table).
User clicks on delete link,
JQuery dialog opens to ask for confirmation. User confirms they want to delete, actionlink calls relevant method on controller.
Method tries to delete relevant record in database but fails, for example, database is down for some reason.
Because I'm not updating an element on the page (I suspect onSuccess will fire?), how can I convey that the record has not been deleted?
So really I'm asking how to pass a return value from the method to the Ajax ActionLink, or force the onFailure to fire.
I suspect I can have a hidden field and update that using UpdateTargetId, and then call a function onSuccess to check the value - but Is this the best way or will this even work?

You can use OnSuccess and OnFailure properties in AjaxOptions:
<p>
#Ajax.ActionLink("Click Me", "About", new AjaxOptions { OnFailure = "OnFailureFunc", OnSuccess = "OnSuccessFunc" })
</p>
<script type="text/javascript">
function OnFailureFunc() {
alert("Error");
}
function OnSuccessFunc() {
alert("Success");
}
</script>

Related

Best Practice for showing Page after Post

I have a View with a Form that calls a controller action Post Method to "Complete" a Package. It then needs to refresh the page its on as that contains information that will be updated, both within the view itself and also within a partial. It does use two different Controllers in different MVC Areas.
The Post works correctly and the redirect is issued, but the page is not refreshed.
I have read that instead, I should use OnSuccess within the Ajax call that calls Complete, but I thought that was for in page calls, not ones that navigate to different pages.
View Form
#using (Ajax.BeginForm("Complete", "Packages", new { Area = "Core" },
new AjaxOptions
{
HttpMethod = "POST"
}))
{
Core(Area) Packages Controller
[HttpPost]
public ActionResult Complete(int ID)
{
// Update code
// Refresh the full page
return RedirectToAction("Summary", new { Area = "Control", id = packageBuilder.CurrentPackage.ID });
}
Control (Area) Packages Controller
[HttpGet]
public ActionResult Summary(int id)
{
// Get Model
return View("Summary", model);
}
Any pointers would be warmly welcomed.
Thanks,
Chris.
The reason that your page is not refreshed after you submit the form and the redirect is not issued in the browser, is that you are submitting the request over AJAX. This is a request issued by the browser behind the scenes.
If you want to submit the form and for the page to be refreshed, I'd recommend changing your code from Ajax.BeginForm(... to Html.BeginForm(... and then it will load the page and perform the redirect as expected.
I am not quite sure how your ajax calls are structured, but if you are using the MVC Ajax helper you can just call `location.reload(); in the OnComplete method, like so:
#using (Ajax.BeginForm(new AjaxOptions{OnComplete = "javascriptfunction"}))
{
//Data and submit button
}
<script>
function javascriptfunction(){
location.reload();
}
</script>

Ajax.BeginForm with OnComplete always updates page

I have simple ajax form in MVC. In AjaxOptions there is OnComplete set to simple javascript function which does one thing - returns false.
#using (Ajax.BeginForm("Action", "Controller", new AjaxOptions { UpdateTargetId = "DivFormId", HttpMethod = "Post", OnComplete = "preventUpdate" }))
function preventUpdate(xhr) {
return false;
}
The problem is, that page is already updated. E.g. in one case controller returns partial view after postback, in other case it returns some Json object. I want it to update page when partial view is returned, and to show dialog window when json is returned. Unfortunately when json is returned, it clears the page (update it with json) even when OnComplete function returns false as MSDN says: To cancel the page update, return false from the JavaScript function.
How to prevent page update depending on received response?
Thank you!
----- UPDATE -------
So far I found following solution. When I don't specify UpdateTargetId, I can do manually with the response what I want. But it is still not documented behaviour with return false.
Use OnSuccess and get rid of UpdateTargetId. Like this:
#using (Ajax.BeginForm("Action", "Controller", new AjaxOptions { HttpMethod = "Post", OnSuccess = "foo" }))
{
...
}
and then:
function foo(result) {
if (result.SomePropertyThatExistsInYourJsonObject) {
// the server returned a JSON object => show the dialog window here
} else {
// the server returned a partial view => update the DOM:
$('#DivFormId').html(result);
}
}

MVC3 & Razor: How to structure forms & actions to allow for postback-like functionality?

I have a view with a drop down list. The default value for this is stored in a session variable. However, the user change change this, in which case new data is entered.
I have a change handler on the drop down:
#using (Html.BeginForm())
{
#Html.DropDownListFor(model => model.SelectedID,
new SelectList(Model.SelectValues, "Key", "Value",
Model.SelectedID), "", new { onchange = "this.form.submit()" });
... more fields ...
<input type="submit" name="Save" />
}
[HttpPost]
public ActionResult Index(ViewModel vm)
{
... decide if I update my data or save the changes ...
}
I tried wrapping the select in a separate form tag, but then the value of my SelectedID not updated in my view model.
How can I determine when the form is posted from a drop down change, and when it is posted from a button click?
If you don't want to reload the entire page when the user changes the selection of the dropdown you could use AJAX to silently trigger a request to a different controller action that will do the necessary updates. For example:
#Html.DropDownListFor(
model => model.SelectedID,
new SelectList(Model.SelectValues, "Key", "Value"),
"",
new {
id = "myddl",
data_url = Url.Action("update")
}
)
and then in a separate javascript file:
$(function() {
$('#myddl').change(function() {
var form = $(this).closest('form');
$.ajax({
url: $(this).data('url'),
type: 'POST',
data: form.serialize(),
success: function() {
alert('update success');
}
});
});
});
and finally you could have a controller action responsible for the update:
[HttpPost]
public ActionResult Update(ViewModel vm)
{
... this will be triggered everytime the user changes some value in the
droipdown list
}
The simplest way would be to simply attach some behavior to those element's events and set a hidden field with the event target (which by now, should sound very familiar to __EVENTTARGET).
Like so:
$('#someButton').click(function()
{
$('#someHiddenField').val('someButton');
});
$('#someDropDown').change(function()
{
$('#someHiddenField').val('someDropDown');
});
And then your action method could inspect this value and act appropriately.
HOWEVER
It sounds like you're thinking in an outmoded concept for MVC. If you really needed some new information, you should consider using some Ajax and then having one of your action methods return a partial view if you want to update part of the page.

Can One Link Invoke Two Ajax Updates?

I have an MVC 3 page that has two partial views, one for Items in Bucket A, and one for Items in Bucket B (simplified for discussion... there's significant logic to rendering each bucket, and that logic is different between the buckets).
I have a link on the page that lets me move an item from Bucket A to Bucket B. Once that link is clicked, I have to refresh the partial views for Items in Bucket A, and the partial view for Items in Bucket B.
I can refresh one or the other using Ajax, like this:
#Ajax.ActionLink("Move to B", "_BucketB", "Home", new { item = Model.Item },
new AjaxOptions()
{
UpdateTargetId = "divForBucketB",
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace
})
How can I approach the problem of also refreshing divForBucketA when the ActionLink is clicked?
UPDATE
The HTML that goes into divForBucketA needs to be generated using the appropriate View and Controller. The changes to the div contents are too significant to be processed on the client in JavaScript (other than perhaps invoking another Ajax call... can that be done?)
This is how you could do it with jQuery. Obviously you would need to fix the Url.Action calls and this does assume that the BucketA controller method returns a PartialView.
$(document).ready(function() {
$('#mybutton").click(function() {
$.get(#Url.Action("Index", "BucketA"), function (data) {
$('#bucketA').html(data);
});
$.get(#Url.Action("Index", "BucketB"), function (data) {
$('#bucketB').html(data);
});
e.preventDefault();
});
});
You could use the AjaxOptions OnComplete or OnSuccess (depending on your needs) to specify a Javascript function to call after the Ajax call finishes to perform any additional processing (like updating the other bucket).

Ajax form and UpdateTargetId after submitting data when ModelState is Invalid

On my view, I have 2 partial views.
1st partial view (PV1): user can type an item in a textbox and submit through an ajax form.
2nd partial view (PV2): user can see a list of items previously submitted.
The PV1 uses UpdateTargetId on a div on the PV2 because we would like to update our list with the newly added item.
Everything works well when items submitted on the PV1 are valid. It doesn't work when ModelState.IsValid == false when ajax form is submitted. It doesn't work because the UpdateTargetId is located on the PV2, and I need to update the PV1 for showing the ModelState Errors. So we encounter with duplicate of the PV1 on the PV2!
Below is another stackoverflow post on a similar problem but no solutions has been provided.
ASP.NET MVC AJAX change UpdateTargetId if ModelState is invalid
I think a Json alternative may be a solution but I'm wondering if we can adapt the standard Ajax form method to suit our need here?
Instead of using UpdateTargetId, you could try using OnComplete:
#using (Ajax.BeginForm(new AjaxOptions { OnComplete = "complete" }))
{
...
}
and inside this handler test whether there is an error in the resulting view:
function complete(result) {
var isError = $('span.field-validation-error', result.responseText).length > 0;
if (isError) {
// there was an error => we update the container of the form
$('#frmContainer').html(result.responseText);
} else {
// no error => we hide validation errors and update the result container
$('#frm .field-validation-error').hide();
$('#frm .input-validation-error').removeClass('input-validation-error');
$('#result').html(result.responseText);
}
}

Resources