ASP.NET MVC Beta Ajax upgrade problem - asp.net

I been waiting for sometime now to bring my Asp.net Preview 4 project up to snuff, totally skipping Preview 5 just because I knew I would have some issues.
Anyhow, here is the question and dilemma.
I have a few areas on the site which I have an ajax update type panel that renders content from a view using this technique found here. AJAX Panels with ASP.NET MVC
This worked fine in preview 4 but now in the beta I keep getting this ..
Sys.ArgumentNullException: Value cannot be null Parameter name eventObject
It has been driving me nuts...
My code looks like this
<% using (this.Ajax.BeginForm("ReportOne", "Reports", null, new AjaxOptions { UpdateTargetId = "panel1" }, new { id = "panelOneForm" })) { } %>
<div class="panel" id="panel1"><img src="/Content/ajax-loader.gif" /></div>
<script type="text/javascript">
$get("panelOneForm").onsubmit();
</script>
so basically what its doing is forcing the submit on the form, which updates panel1 with the contents from the view ReportOne.
What am I missing? Why am I getting this error? Why did they go and change things? I love MVC but this is making me crazy.

Unfortunately, just calling submit() won't fire the onsubmit event so the MVC Ajax script won't run. When the browser calls onsubmit() for you (because the user clicked the submit button), it actually provides a parameter called event (which you can see if you look at the Html outputted by the Ajax helper).
So, when you call onsubmit() manually, you need to provide this parameter (because the MVC Ajax code requires it). So, what you can do is create a "fake" event parameter, and pass it in to onsubmit:
<% using (this.Ajax.BeginForm("ReportOne", "Reports", null, new AjaxOptions { UpdateTargetId = "panel1" }, new { id = "panelOneForm" })) { } %>
<div class="panel" id="panel1"><img src="/Content/ajax-loader.gif" /></div>
<script type="text/javascript">
$get("panelOneForm").onsubmit({ preventDefault: function() {} });
</script>
The important part is the { preventDefault: function() {} } section, which creates a JSON object that has a method called "preventDefault" that does nothing. This is the only thing the MVC Ajax script does with the event object, so this should work just fine.
Perhaps a longer term fix would be if the MVC Ajax code had a check that simply ignored a null event parameter (wink #Eilon :P)

Having some irritating problems relating to this issue. Hope someone here can help me out.
var event = new Object();
function refreshInformation(){
document.forms['MyForm'].onsubmit({preventDefault: function(){} });
}
This is my current code, it works fine for updating the the form. Problem is the "var event" disrupts all other javascript events, if I have for example this:
<img src="myimg.gif" onmouseover="showmousepos(event)" />
its not the mouse event that's sent to the function, instead it's my "var event" that I must declare to get the onsubmit to function properly.
When using only onsubmit({preventDefault: function(){} } without the "var event" I get the Sys.ArgumentNullException: Value cannot be null Parameter name eventObject
I've also tried using submit() this does a full postback and totally ignores the ajaxform stuff...at least in my solution.
Hmm...I realize this might be a little confusing, but if someone understands the problem, it would be great if you had a solution as well. =)
If you need more info regarding the problem please just ask and I'll try to elaborate som more.

I believe that calling someFormElement.onsubmit() simply invokes the event handlers registered for that event. To properly submit the form you should call someFormElement.submit() (without the "on" prefix).
I don't think we changed anything in the AJAX helpers' behavior between ASP.NET MVC Preview 4 and ASP.NET MVC Beta.
Thanks,
Eilon

Related

asp.net mvc - ajax form (Ajax.beginform) in partial view redirects to show json response when the partial view is rendered via ajax

I have a partial view with an ajax form
#using (Ajax.BeginForm("SaveSettings", "Config", new AjaxOptions
{
HttpMethod = "Post",
OnSuccess="settingsUpdateSucces"
}, new { enctype = "multipart/form-data", id = "SaveSettings" }))
{
#Html.HiddenFor(m => m.Id)
//other fields go here
<button id="btnSaveSettings" type="submit" >Save Settings</button>
}
This partial view and the form works in one scenario but not the other.
Let me explain both scenarios
Scenario 1:
The partial page is rendered using "Html.Partial" in an asp.net page
relevant parts of the page
#{
ViewBag.Title = "Edit";
Layout = "~/Layout/V1.cshtml";
}
<!--other non-relevant markup and code here-->
<div>
<h3>Settings</h3>
#Html.Partial("_Settings")
</div>
In this scenario the ajax form works without any problems and the page is not redirected.
This code has been running for over 6 months and no issues whatsoever.
Scenario 2
Now, I am trying to get the same partial to work on another new page.
This is a new page - which works like a wizard.
So, in one of the steps a partial page is added (using Html.Partial). This page has a dropdown, when selected, another partial page is rendered via ajax.
One of the selection loads the above mentioned "_Settings" partial page using this code
function loadPartial(id) {
$.get('/Config/_Settings?sid=' + id, function (data) {
$('#partialSettingsPlaceHolder').html(data);
});
}
The partial page and form is loaded fine, but when I submit a redirect happens and the JSON returned by the ajax form is shown.
I am unable to understand why this is happening in scenario 2.
PS:
I already searched for similar issues and the answers mention that this happens when the required js files - jquery, "jquery.validate.unobtrusive.min.js", "jquery.unobtrusive-ajax.js" - are not referenced and downloaded.
Please note that in both scenarios, jquery, "jquery.validate.unobtrusive.min.js", "jquery.unobtrusive-ajax.js" are referenced and downloaded in the main page - ie the page containing the partial page.
I think your issue could caused by submitting handler function for ajax form only binding at page loaded or document ready event of page which contain ajax form. Since your partial page is adding dynamic via ajax, so the dynamic added ajax form will be full submitted as a normal form.
You could try below work-around solution.
Manually adding submitting event handler function for newly added form, then inside this handler function, we do submitting via ajax instead of full submit.
function loadPartial(id) {
$.get('/Config/_Settings?sid=' + id, function (data) {
var placeholder = $('#partialSettingsPlaceHolder');
placeholder.html(data);
$('form', placeholder).on('submit', submitHandler);
});
}
function submitHandler(event) {
event.preventDefault();
event.stopImmediatePropagation();
// validation code here depend on validation plugin you are using, for example:
// if (!$(this).valid()) return false;
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize()
}).done(function (data) {
// your code in case of success
}).fail(function (jqXHR, textStatus) {
// your code in case of fail
});
return false;
}
Of course, this is just a work-around solution. If you want to do it in more formal way, I suggest you to study auto generated source code for ajax form and aspx page (for example using Developer Tool of browsers).
The reason why your second scenario is not working is that you are loading and adding your form dynamically to our page after the initial page load.
if you will take a look on jquery unobtrusive ajax code you will find that section which is doing few calls like $(document).on(...). That is basically adding listeners directly to html elements like form or input right after page is ready. But because of that those click events are not being attached to elements which will be appended to page later. Unfortunarelly I cannot see in that script any possibility to reinitialise it. So maybe your only option might be to create script which can be called after adding your form and will do the same steps as the original version. That way ajax behaviour should remain the same.
Another option might be to render the form without ajax but hide it with css? That is very dependent on your page styling etc. That way event listeners will get applied and you could then only show the form instead of appending it as a fresh node

Reload PartialView from jQuery in ASP.NET MVC 2 application?

I'm trying to use jQuery to load a PartialView. It does this fine at the first loading of the page. But then I need to be able to reload the PartialView when a save button is pressed. I get a reload, but this time the PartialView is all I get back. I.e. I don't get the PartialView loaded as a part of the main page, but rather as a page of its own. What am I doing wrong?
Here are the relevant parts of the jQuery in the View:
$.get('<%=Url.Action("GetTasks", "Timesheet", new {id = DateTime.Today.ToShortDateString() }) %>', function (data) {
$('#tasksDiv').html(data);
}); //This part works fine on first load of the page
$('#savenewtask').click(function (event) {
event.preventDefault();
$.get('<%=Url.Action("GetTasks", "Timesheet", new {id = DateTime.Today.ToShortDateString() }) %>', function (data) {
$('#tasksDiv').html(data);
});
}); //This only loads the PartialView, but not as part of the main page...
The button and the div to load in:
<p>
<input type="button" value="Spara" id="savenewtask" />
</p>
<div id="tasksDiv">
</div>
UPDATE:
It actually worked, I had just confused the two input fields I have on the page. But I'll rephrase the question to a simple one: Is this the best way to do this sort of thing with PartialViews, or should I go about it another way? (I.e. I was just trying to figure out a way to achieve what I wanted without knowing if it is the "best practice" way of doing it).
I have typically used the load method, which sets the innerHtml.
var url = '<%=Url.Action("GetTasks", "Timesheet", new {id = DateTime.Today.ToShortDateString() }) %>'
$("#tasksDiv").load(url);

ASP.NET MVC Ajax.ActionLink's weird behavior

I'm doing the simplest ajax request possible:
public ActionResult SayHello()
{
return Content("YYAAAY");
}
//////////
<div id="Div1">
<%= Ajax.ActionLink("SAY HELLO", "SayHello", new AjaxOptions { UpdateTargetId = "Div1" })%>
</div>
It works when I start an empty ASP.NET MVC project, but when I use it in my current project, it displays the whole page recursively instead of YYAAAY phrase only.
Where might be the problem?
I suspect you have an unrelated javascript error that is causing it to use the default action (link) instead of retrieving the content via AJAX. Use Firefox/Firebug and examine the console or turn on script debugging in IE and see.

asp.net mvc JavaScript in View User Controls rendered through regular browser request and AJAX request

I have this code in some of my ASCX files:
<%=Html.ActionLink(Resources.Localize.Routes_WidgetsEdit, "Edit", "Widget",
new { contentType = Model.ContentType, widgetSlug = Model.Slug, modal=true},
new
{
rel = "shadowbox;height=600;width=700",
title = Resources.Localize.Routes_WidgetsEdit,
#class = "editWidget"
})%>
Take note of that rel="shadowbox..." there. This is to wire up ShadowBox Lightbox clone for this ActionLink.
This works fine when user requests a page containing this User Control thru normal browser request. But I also render/build those View User controls trough AJAX requests. For instance, I would make request to /Widget/RenderToString/... using jQuery .ajax() method and it would return HTML code for that control. This works fine and it renders the code fine. I would then insert (append) the result to a DIV in a page from where the AJAX request was made. This also works fine and the returned HTML gets appended. The only problem is - ShadowBox is not wired up. Even though the code for it gets rendered.
It seems it requires page reload (F5) every time to wire ShadowBox up. Since I am doing AJAX GET and instant append to get rid of having to make a server roundtrip, I would also want ShadowBox to wire up without doing refresh.
Can someone help me with that? Thank you
UPDATE:
Yes, I have this in my Site.Master head:
<script src="<%=Url.Content("~/Scripts/shadowbox-build-3.0rc1/shadowbox.js") %>" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
// insert functions calls here that provide some default behaviour
externalLinks();
});
Shadowbox.init({
language: "en",
players: ["img", "html", "iframe"],
onClose: function() { location.reload(true) }
});
</script>
How do I init the Shadowbox again after AJAX call?
There are many shadowbox plugins... which one are you using? (I can't give you exact code without it.) In any case I imagine you have something in your $(document).ready(function () { ... }); that tells shadowbox plungin to bind itself. You need to call that again after the AJAX call.
Just found the solution here
// call this after adding the new HTML to the page
// set up all anchor elements with a "editWidget" class to work with Shadowbox
Shadowbox.setup("a.editWidget", {});

ASP.NET MVC Submitting Form Using ActionLink

I am trying to use link to submit a form using the following code:
function deleteItem(formId) {
// submit the form
$("#" + formId).submit();
}
Basically I have a grid and it displays a number of items. Each row has a delete button which deletes the item. I then fire the following function to remove the item from the grid.
function onItemDeleted(name) {
$("#" + name).remove();
}
It works fine when I use a submit button but when I use action link the JavaScript from the controller action is returned as string and not executed.
public JavaScriptResult DeleteItem(string name)
{
var isAjaxRequest = Request.IsAjaxRequest();
_stockService.Delete(name);
var script = String.Format("onItemDeleted('{0}')", name);
return JavaScript(script);
}
And here is the HTML code:
<td>
<% using (Ajax.BeginForm("DeleteItem",null, new AjaxOptions() { LoadingElementId = "divLoading", UpdateTargetId = "divDisplay" },new { id="form_"+stock.Name }))
{ %>
<%=Html.Hidden("name", stock.Name)%>
<a id="link_delete" href="#" onclick="deleteItem('form_ABC')">Delete</a>
<% } %>
</td>
My theory is that submit button does alter the response while the action link simply returns whatever is returned from the controller's action. This means when using submit the JavaScript is added to the response and then executed while in case of action link it is simply returned as string.
If that is the case how can someone use action links instead of submit buttons.
UPDATE:
Seems like I need to perform something extra to make the action link to work since it does not fire the onsubmit event.
http://www.devproconnections.com/article/aspnet22/posting-forms-the-ajax-way-in-asp-net-mvc.aspx
My guess is the MS Ajax form knows how to handle a JavaScriptResponse and execute the code whereas your plain old Action link, with no relationship to the AjaxForm, does not. I'm pretty sure the MS ajax library essentially eval()s the response when it sees the content type of javascript being sent back.
Since you have no callback in your deleteItem() method there is no place for the script to go. To fix you'll have to manually eval() the string sent back which is considered a bad practice.
Now I'm not familiar with the MS Ajax library to be certain of any of this but what your doing is possible. I'd do things differently but don't want to answer with a "my way is better" approach ( especially because your blog has helped me before ) but I'd like to show this can be easier.
I'd ditch the form entirely and use unobtrusive javascript to get the behavior you want. IN psuedo jqueryish ( don't know ms ajax ) code:
function bindMyGrid() {
$('.myDeleteLink').onclicksyntax( function() {
//find the td in the row which contains the name and get the text
var nameTdCell = this.findThisCellSibling();
//do an ajax request to your controller
ajax('myUrl/' + nameTdCell.text(), function onSuccessCallback() {
//get the tr row of the name cell and remove it
nameTdCell.parent().remove();
});
});
}
This also gains the benefit of not returning javascript from your controller which some consider breaking the MVC pattern and seperation of concerns. Hope my psuedo code helps.
Try without the UpdateTargetId property in the AjaxOptions (don't specify it)
new AjaxOptions() { LoadingElementId = "divLoading" }
What about just change look of a standard or using some css class? It'll look like a link and you'll avoid some problems you get with anchors - user will be able to click on it by a mouse wheel and open that link in a new tab/window.

Resources