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);
Related
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
I've been looking for the solution and I haven't find a way to get my head around it. So I hope you could give me some clues to achieve that.
Basically I need to change a value of a _Layout from its rendered PartialView. I use to do this using webforms .aspx master pages and FindControl method but I cannot find a solution to do this in MVC Razor engine.
My Layout page has an ActionLink and a div tag place-holder to display the partial-views, Now I need to know how to change the value of Text1 from the partial-view pages within the DIV tag:
Is JavaScript the only way that I can do this ?
<input id="Text1" type="text" />
<div>
#Ajax.ActionLink("Personal Info", "Personal", "Portal", new { area = "Resume" },
new AjaxOptions { UpdateTargetId = "result", HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
OnBegin = "blockUi",
OnSuccess = "onTabChanged(this, 'Personal Information')"
},
new { #class = "text-strong" })
</div>
<div id="result">#RenderBody()</div>
Appreciate your contributions in advance.
Javascript is the way this is handled I think.
You might be able to do some trickery with controllers and the ViewBag (like how the page title is set with the ViewBag in a default MVC project).
You could also maybe set it to some global variable or something, and have your partial view change that variable.
Both those solutions though would require a page reload.
But using javascript is probably the best, you could do it in the onTabChanged function.
<script>
function onTabChanged(param1, param2) {
var el = document.getElementById("Text1");
el.value = "Whatever you want here";
}
</script>
I think the easiest way is using a ViewBag that you play around with in your controller/view/partial view.
In WebForms you can use the FindControl method because a PostBack was made. So the entire page was rendered again.
In the example you posted, I assumed that the request made by Ajax.ActionLink that update the div result, returns a view that may use the same Layout, but is in another context so you don't have access to the same input text from the rendered page where Ajax.Action link was triggered.
So, if you have multiples Ajax.ActionLink that updates the <div id="result">, you need to handle the success method on onTabChanged, like #Kyle Gobel suggested.
I am in the process of putting a new site together which will make use of AJAX to pull through page content should the user have javascript enabled.
So, I am in the situation whereby every Action Method requires a check to see if the request was through AJAX or not, which is straightforward. If the request was through AJAX then I can return a partialview, if not then a full view can be returned.
With this pattern though, I'll need to create a View and a PartialView for every page on the site. The only real difference between them is going to the inclusion of the masterpage.
Am I missing a trick here is is this doubling up of views the only way to go?
Thanks
EDIT - a bit more info
Lets say I had a page that could get accessed through /site/test. Somewhere in my JS I would add a hash to the url like so #/site/test. JS would then watch for any hash changes and load the partial views as needed. If JS was not available though, an entire view would need to be returned.
So for each page I would need the view, which would then include a call to RenderPartial which would load up the partial view which would actually contain the page content. So, for every page there are two files. It just seems there should be a cleaner way of doing this.
Sergio, yes you are missing a trick!!
You should organise your page so that the static content in it is just that - static. This static page then calls the partial(s) that give the dynamic content. this would typically be used in the main page as such (i'm using jquery as per microsofts adopted stance on ajax now):
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>My Header</h2>
<%--lots of stuff omitted--%>
<div id="dynamicList"><%Html.RenderPartial("List"); %></div>
<%--also lots missed out here--%>
<input type="button" id="btnRefresh" value="refresh" />
</asp:Content>
this means that the partial would always be rendered in the initial request. subsequent refreshes would call the partial method in the controller and repopulate the 'dynmaicList' div along the lines of:
<script type="text/javascript">
// you might have a click or similar here to invoke the partial refresh
$(function() {
//click event (or some other 'change' event)
$('#btnRefresh').click(function() {
dynamicList();
});
});
function dynamicList() {
// where action/controller retruns a partialview result
var url = '<%= Url.Action("List", "MyController") %>';
// this is merely a wrapper method around jquery $ajax
SendAjax(url, formParams(), beforedynamicListQuery, dynamicListResponse);
}
function beforedynamicListQuery() {
$("#dynamicList").fadeTo('slow', 0.5);
}
function dynamicListResponse(data) {
if (data.length != 0) {
if (data.indexOf("ERROR:") >= 0) {
$("#dynamicList_errmsg").html(data);
}
else {
var selector = "#dynamicList";
$(selector).fadeTo('slow', 1, function() {
$(this).html(data);
});
}
}
}
</script>
anyway, that's my take on it!! ;)
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", {});
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