I use partial view for small model inside other view model. so i send changes of it by grabbing model data from wrapper form and using serializeArray(). then return PartialViewResult from action and finally fill partial view div container by returned result. this is my code:
var modelStr = $("#[wrapperFormName]").serializeArray();
$.ajax({
type: "POST",
url: targetUrl,
cache: false,
data: modelStr,
success: function (sucResult) {
$('#pa_Cnt').html(sucResult);
},
fail: function (result) {
alert("Fail");
}
});
and render partialview in view as this:
#using (Html.BeginForm("[ActionName]", "[CtrlName]", FormMethod.Post, new { id = "[wrapperFormName]", #enctype = "multipart/form-data" }))
{
<div id="[partialcontainerName]">
#Html.Partial("[partialViewName]", [partialViewModelName])
</div>
}
One of issue is after update partial view with returned result don't work any of jQuery event handlers that bind to elements inside the partial and i know event handlers must be declare in main view and not in partial and handlers must be delegated.
Second issue is updated result has new values but some of elements in partial view show old values and i set cache of ajax to false as cache of action with [OutputCache(Duration = 0)].
I'm confusing. Can anyone help me.
Your first issue is because you must re-add your event handers. I assume you are adding your event handlers within $(document).ready or an equivalent when the page loads. After you've refreshed your partial using $.ajax, the original elements that had event handlers no longer exist - their instances have been replaced and therefore the event handlers won't fire. You need to re-add the event handlers as part of the success callback after the line:
$('#pa_Cnt').html(sucResult);
Not sure about the second issue..
I found it. Thanks from #David for first issue. I separate internal actions of delegated events to functions that pointed with variable names and attach delegate events to them after update html of partial with returned result. this is a simple sample:
var sampleHandler = function() { //some code }
and then in ajax success:
success: function (sucResult) {
$('#pa_Cnt').html(sucResult);
$("[parentClassNameSelector]").on("click", '[childSelector]', sampleHandler);
}
About second issue ModelState of MVC is Guilty. :) specially in elements that rendered by mvc helpers. So i decide to do this in controller action.
if (ModelState.IsValid) { ModelState.Clear(); }
I don't know if this is good or has any other issue. For now it was solved my problem. I'm waiting for new comments and advises. Thanks so much.
Related
I have a tabstrip that is dynamically populated with a set of partial views. Each of these partial views is an entry form, and some of them have differing Entity Framework data models behind them.
I would like to POST the model to the server with two arguments (a targeted tab index and the model data) whenever a different tab is selected. (To save the tab data)
My issue is that clicking on the tab links seems to be a 'get' action rather than a 'post' action, and I'm having trouble figuring out how to submit data both comprehensive and isolated enough. (comprehensive being the model and isolated being the model associated with a PARTICULAR partial view) I assume I could use JQuery to find and execute the click method of update buttons on the partial view, but that wouldn't preserve a target index.
Is the best method to find a way to uniquely identify the form itself and subsequently post it? Anyone have a hint for me here?
I am not sure what the best method is. What I do is wrap the code in my partial with
#using (Html.BeginForm("Action", "Controller"))
{
}
and then just having a submit button click event. That posts back just the information from that partial. If you wanted to send multiple partials to the same action then I would use a hidden field that is set when the tabs are clicked and you should be able to pull that index using a Request.Form["FieldName"]. Hopefully that helps.
Edit:
You can also try an ajax call back to the server
$.ajax({
url: "#Url.Action("Action", "Controller")",
type: 'post',
data: {id: 'hiddenfield', data: 'data', etc},
dataType: 'json',
contentType: "application/json",
success: function (result) {
(do something)
}
});
to send the model this way you will need to add those fields to the data row. If there is a lot of data I would recommend stringifying it. You can put this call in the submit button click events.
Use ajax call as mentioned. It does not matter whether the element is on parent or partial page. Once the html is rendered, any element on the DOM can be referenced.
So the design ideal is to have one page with a couple different 'widgets' in this MVC app. Each 'widget' should be able to submit information back to itself and reload only itself. Simple in web forms, not so much with MVC it seems
First, we have our main page controller, nothing special
public ActionResult Index()
{
return View();
}
Next, we have our main page View. Note that I have tried both Action and RenderAction and there is no change in behavior
#Html.Action("Index", "Monitor", new { area = "Statistics" });
<div id="messages">
#Html.Action("Index", "Messages", new { area = "Data"});
</div>
#section Script {
<script src="#Url.Content("~/Scripts/jquery-1.9.1.min.js")" type="text/javascript"></script>
<script type="text/javascript">
$('#filter').click(function () {
$.ajax({
method: 'POST',
url: '#Url.Action("Index", "Messages", new { area = "Data"})',
success: function(data){
$('#messages').html(data);
}
});
return false;
});
</script>
The Index ActionResult in the Messages Controller:
public ActionResult Index()
{
var model = GetMessages();
return PartialView(model);
}
For the sake of brevity, going to skip the whole of Monitor Index View, and only give a brief version of Messages Index View
#using (Html.BeginForm("Index", "Messages", FormMethod.Post))
{
//Some fields to limit results are here, with style classes
<button type="submit" id="filter">Filter</button>
}
#foreach(var item in Model)
{
//Display results
}
Upon loading the main page, all looks good. The fields to limit results are displayed, as well as messages. I can enter something into the fields, click Filter, and am returned to the main page but! ...the fields have lost their style classes and the messages are unfiltered.
Strange, but more strange is if I again enter information in the fields and click Filter, this time I am not taken to the main page, but get only the Partial View of the Messages Index displayed and the messages are not filtered.
I can't say that the filtering not working is related to this issue or not, but the non-consistent behavior of clicking Filter is the part that bothers me. Anyone like to point out what I am doing wrong in here?
You probably should be using Ajax.BeginForm rather than Html.BeginForm in your widgets. That will let the widgets manage their own posts:
<div id="messages">
#using (Ajax.BeginForm("Index", "Messages", new AjaxOptions { UpdateTargetId = "messages" }))
{
// fields content
}
// other widget content
</div>
The "bizarre" behavior you're seeing is happening because on page load the submit event for your #filter button is being hijacked using jQuery, but after the first replacement of the widget content the #filter submit event is no longer being hijacked so when you click it the whole page is submitted. If you don't want to use Ajax.BeginForm you'll need to use $.on rather than $.click to sign up events, as it will handle events for matching elements which are created after the event sign up script has run.
I have a view with DropDown List, on change of this dropdown list i get the id and fill partial view using Jquery Ajax like this:
$.ajax({
url: '/Edit/Fill',
type: 'POST',
async: true,
data: { ID: ID },
success: function (data) {
$('#Par').html(data);
},
I have a button in my partial view, that saves my data, i want to return to the same page after saving.
[HttpPost]
public PartialViewResult Index(FormCollection All)
{
//My Code
Return PartialView();
}
i also tried to return the same partial view, didn't work??
i want to stay in the same page after the button submit in the Partial view
Any Suggestions?
Your ajax method points to /Edit/Fill, yet your action method is named Index. Don't you mean /Edit/Index? The rest of the code looks fine.
Option1 : if your partial view is not complex view, avoid returning partial view... instead try to return json data from your Ajax call, and bind the json data to parent view using Jquery.
Option2: When you hit save, instead of form submit try to use Ajax call to save your data.
Option 3: a form submit requires the page to reload, so on page load collect drop-down id and do your Ajax call to load your partial view. (you might have to use session data to load right values in your partial view)
Here's the situation (using MVC 2.0):
I'm trying to build a feature to allow a user to preview changes they make to their bio/profile without actually committing their changes first. User fills out a form, clicks a "Preview" button and see what their changes look like. One difficulty is the front-end has a different master-page, so we need to render the whole view, not just a control.
Here's the approach I took:
Asynch post the serialized form to a controller action
Manipulate the model to flesh out the collections, etc. that don't get posted
Return the front-end view, passing it this modified model
Catch the response to the asynch method, wrap it in an iframe and write that to a lightboxed div on the page
Code I'm using... Controller action (the BuildPreview method just alters the model slightly)
[HttpPost]
[Authorize]
public ActionResult PreviewProfile(PersonModel model)
{
return View("Person", PeopleService.BuildPreview(model));;
}
HTML/Jquery stuff:
<script type="text/javascript">
$(document).ready(function () {
$("#previewButton").click(function (e) {
$.post("/PreviewProfile", $("#bioForm").serialize(), function (response) {
$("#previewFrame").html(response);
$("#holdMyPreview").modal({
overlayClose: true,
escClose: true,
autoResize: true,
}, "html");
});
});
});
The modal method is just a basic lightbox-esque thing.
Running into two problems:
EDIT - removed this, I was accidentally pulling a child control
The iframe isn't rendering the html (perhaps because it's not valid b/c it's missing html/body/head tags?). If I just drop the response direcltly into the div, without the iframe, it works... albiet with the wrong stylesheet. If I try to insert it into iframe it just treats it as an empty page, just the html, head and body tags show up.
Any thoughts?
Sam
PS: Tried this over at MSDN forums (http://forums.asp.net/t/1675995.aspx/1?Rendering+a+view+into+a+string+) and it didn't get anywhere, figured I'd see if SO has any brilliance.
so, just massage the response when you get it back, add the missing html/body/head
$.post("/PreviewProfile", $("#bioForm").serialize(), function (response) {
response = "<html><body>"+response+"</body></html>";
$("#previewFrame").html(response);
$("#holdMyPreview").modal({
overlayClose: true,
escClose: true,
autoResize: true,
}, "html");
});
I'm preparing an application I wrote in ASP.Net MVC for some light Ajax-y stuff. Basically, I want users to be able to go to different parts of the page without it reloading.
To do this I want to be able to reload the body of my page.
My site master is broken down into a head body and foot div. I want to be able to use something like $("body").load(whateverlink) to refresh the body, but in my case doing this causes the website to be rendered inside the body.
How can I do this successfully?
EDIT: The page is made up of views, not partialviews. In theory I could go and convert all my pages to partials but I'm looking for a way around that if possible.
Thanks
You can get your controllers to return partial views, using JQuery to do a request and update a div with your page content:
JQuery:
function navigate(url){
$.ajax({
url: "/Home/Index",
cache: false,
success: function(html){
$("#content").html(html);
}
});
}
Controller:
public class HomeController : Controller
{
public void Index()
{
return this.PartialView();
}
}
There is a helpful article on BrightMix which might help. It basically renders a partial to a string, which you could then return as part of a ContentResult.