I have creatd a partial view and inside it I am using AJAx.BeginForm. In Post Edit Action Method, I am adding VIEWDATA Like this
if (ModelState.IsValid)
{
service.SaveAccount(account);
TempData["message"] = "Account has been updated successfully!";
AccountInfo accountInfo = new AccountInfo();
accountInfo.AccountStatuses = service.GetAccountStatuses();
accountInfo.AccountTypes = service.GetAccountTypes();
accountInfo.CreditTerms = service.GetCreditTerms();
return View("DisputeSubscriber", accountInfo);
}
else
{
return PartialView("_UpdateAccountDetails", account);
}
and redirecting to same partial view. In partial view, I have added like this:
#if (TempData["message"] != null)
{
<div class="Message">
I am here.
#TempData["message"]
</div>
}
but this message is not shows. this message is also inside AJAX.BeginForm. Please suggest
Do I need to redirect main view instead of partial view or there is something I am missing
You seem to be using TempData and not ViewData which is not quite the same. Also you mentioned that you are using an Ajax.BeginForm to invoke this controller action. Since this is an AJAX call make sure that you have specified an UpdateTargetId in your AjaxOptions so that the resulting partial is injected somewhere into the DOM:
#using (Html.BeginForm(new AjaxOptions { UpdateTargetId = "foo" }))
{
...
}
<div id="foo"></div>
Related
I have a scenario where I have a view with a partial that is loaded via $.get. The partial has the following code:
#model MvcApplication1.Models.CmaPartialModel
#using (Ajax.BeginForm("TestPost", new AjaxOptions { HttpMethod = "Post" }))
{
#Html.ValidationSummary()
for(var i = 0; i < Model.DataItemsWithLabels.Count; i++)
{
#Html.LabelFor(m => m.DataItemsWithLabels[i].DataName,Model.DataItemsWithLabels[i].DataName)
#Html.TextBoxFor(m => m.DataItemsWithLabels[i].DataValue)
#Html.ValidationMessageFor(m => m.DataItemsWithLabels[i].DataValue,"data value error")
#Html.TextBoxFor(m => m.DataItemsWithLabels[i].DataName)
#Html.ValidationMessageFor(m => m.DataItemsWithLabels[i].DataName,"data name error")
}
<input type="submit" value="Save" />
}
My controller action is:
[HttpPost]
public ActionResult TestPost(CmaPartialModel model)
{
if (ModelState.IsValid)
{
// code removed for quesiton
}
else
{
ModelState.AddModelError("E!", "Want to display this!");
}
return PartialView("Transaction", model);
}
Everything is working as expected in terms of client-side validation.
However, the errors that I have added in the controller are not displayed.
What am I doing wrong?
EDIT
I have altered the controller action to inlcude: ViewBag.Error = "error message";
And the partioal view to include #ViewBag.Error - This is not upating either. Is it perhaps an issue with AJAX?
The first parameter of AddModelError is important here. It is used to determine what part of your model the error applies to.
You specified E! which, given it contains something that isn't a valid C# identifier, probably doesn't map to any part of your model!
If you want to add a general error then use string.Empty as the first parameter. You should find that it displays in your validation summary.
Thaks to Dean for his help. Just wanted to make it clear that I was not using Ajax.BeginForm correctly. My view should have looked like this:
<div id="form">
#using (Ajax.BeginForm("TestPost", new AjaxOptions { HttpMethod = "Post", UpdateTargetId = "form" ))}
{
// form stuff here
}
<div>
The form was not updating with anything - not just errors as I had no UpdateTargetId
I cannot get the partial view to update. If I refresh the page manually, I do see the incremented count. I tried similar approach without partial view inside the countDiv with action returning a random integer and the countDiv was getting updated just fine, so its something about the partial view:
Main view:
#using (Ajax.BeginForm("AddPositive", new RouteValueDictionary { { "id", Model.Id } },
new AjaxOptions() { UpdateTargetId = "countDiv"}))
{
<div>
<input type="submit" value="For" />
</div>
}
<div id="countDiv">
#Html.Partial("PollCounts")
</div>
PollsCounts partial view:
#model MyProj.Models.Poll
<div>Positive: #Model.PositiveCount</div>
<div>Negative: #Model.NegativeCount</div>
Action:
public PartialViewResult AddPositive(int id)
{
Poll poll = db.Polls.Find(id);
db.Entry(poll).State = EntityState.Modified;
poll.PositiveCount++;
db.SaveChanges();
return PartialView("CountsPartial", poll);
}
look in your action, you're returning the countsPartial instead of the pollsCount partial view
I've looked over a bunch of other reports of this, but mine seems to be behaving a bit differently. I am returning PartialViewResults for my child actions, so that's not the source of the recursion. Here's a dumbed down version of what I have.
// The Controller
[ChildActionOnly]
public ActionResult _EditBillingInfo()
{
// Generate model
return PartialView(model);
}
[HttpPost]
public ActionResult _EditBillingInfo(EditBillingInfoViewModel model)
{
// Update billing informatoin
var profileModel = new EditProfileViewModel()
{
PartialToLoad = "_EditBillingInfo"
};
return View("EditProfile", profileModel);
}
[ChildActionOnly]
public ActionResult _EditUserInfo()
{
// Generate model
return PartialView(model);
}
[HttpPost]
public ActionResult _EditUserInfo(EditUserInfoViewModel model)
{
// Update user informatoin
var profileModel = new EditProfileViewModel()
{
PartialToLoad = "_EditUserInfo"
};
return View("EditProfile", profileModel);
}
public ActionResult EditProfile(EditProfileViewModel model)
{
if (String.IsNullOrEmpty(model.PartialToLoad))
{
model.PartialToLoad = "_EditUserInfo";
}
return View(model);
}
// EditProfile View
#model UPLEX.Web.ViewModels.EditProfileViewModel
#{
ViewBag.Title = "Edit Profile";
Layout = "~/Views/Shared/_LoggedInLayout.cshtml";
}
<div>
<h2>Edit Profile</h2>
<ul>
<li class="up one"><span>#Ajax.ActionLink("Account Information", "_EditUserInfo",
new AjaxOptions { UpdateTargetId = "EditProfileDiv", LoadingElementId = "LoadingImage" })</span></li>
<li class="up two"><span>#Ajax.ActionLink("Billing Information", "_EditBillingInfo",
new AjaxOptions { UpdateTargetId = "EditProfileDiv", LoadingElementId = "LoadingImage" })</span></li>
</ul>
<img alt="Loading Image" id="LoadingImage" style="display: none;" src="../../Content/Images/Misc/ajax-loader.gif" />
<div id="EditProfileDiv">
#Html.Action(Model.PartialToLoad)
</div>
</div>
The partial views are both forms for updating either the user information or billing information.
I debugged through this and found what is happening, but cannot figure out why. When a user browses to EditProfile, it load up with the _EditUserInfo partial and the form is there for editing. When you change some info and submit the form it hangs and you get a StackOverflowException in the EditProfile view on the call to #Html.Action(). What happens is on the initial visit to EditProfile, the #Html.Action calls the HttpGet version of _EditUserInfo. You make some changes to the user info and click submit. Once the information is updated the EditProfile view is returned again, but this time #Html.Action calls the HttpPost version of _EditUserInfo which updates the user information again, returns the EditProfile view again and the #Html.Action calls the HttpPost version of _EditUserInfo... You get where this is going. Why after form submission does it call the post version and not the get version like it did for the initial visit to EditProfile?
Thanks for any help!
I might be getting this a bit wrong, it's been a long day so, but in EditProfile you set PartialToLoad (if it's empty) to "_EditUserInfo", then in _EditUserInfo you set it again to _EditUserInfo, won't this create a loop that behaves as what you are experiencing?
Problem
I have Telerik TabControl and each tab content is a partial view. Everything works smoothly when request is GET:
//
// GET: /ProductVersion/Translations
public ActionResult Translations(Guid id)
{
VersionEditTabViewModel model = CreateTranslationsViewModel(id);
return PartialView("Translations", model);
}
Now the problem is that on some tabs I have a Form that has controls that trigger submit event.
[HttpPost]
public ActionResult Translations(Guid id)
{
FormCollection formCollection = new FormCollection(Request.Form);
string message = string.Empty;
int languageId = int.Parse(formCollection["TranslationsLanguageList"]);
string action = formCollection["TranslationAction"];
if(action == Constants.translation_save)
{
_translationModel.SaveTranslations(formCollection);
message = "Translation information saved";
}
else if (action == Constants.translation_language_changed)
{
/*
PROBLEM: causes whole page to render, not partial
*/
return PartialView("Translations", model);
}
return RedirectToAction( ... updates the complete page not only partial ...);
}
My question is: how to render partial from the POST method? Because now with that source code tab content will be loaded to the WHOLE page, not inside tab.
Solution
I had to put DIV outside of the Ajax.Form and also I had incorrect submit on my DropDownList. What I did was that I created hidden submit button with Id and then I used jQuery to execute it's click event.
For additional reference, please refer to this question on SO:
MVC - Using Ajax to render partial view
This shows a complete implementation of the Ajax.BeginForm with surrounding DIV and inner form controls. You should be able to place this entire setup (DIV + Form + HTML Form Elements) in the Telerik Tab, like this:
<% Html.Telerik().TabStrip()
.Name("TabStrip")
.Items(tabstrip =>
{
tabstrip.Add()
.Text("Your Tab Text")
.Content(() =>
{%>
<div id="containerDiv" align="left">
<% using (Ajax.BeginForm("Example", "Controller/Action", new AjaxOptions { UpdateTargetId = "containerDiv" })){ %>
<%-- Render Partial here -->
<% } %>
</div>
<%});
Hope that helps.
I did my trough ajax form:
using (Ajax.BeginForm("*ActionName*", new { *parameter = ID* }, new AjaxOptions { UpdateTargetId = (*div i will update*), OnSuccess = "*JavaScript that executes on success*", OnComplete = "s*ame as on success*", InsertionMode = InsertionMode.Replace }))
and then i have
return PartialView("*PartialViewName*", model);
in post Action
And it works just fine, on post, action returns partial view and then ajax form replaces the content of the div specified in the UpdateTargetId with InsertionMode.Replace
I have a partial view which has a Ajax.BeginForm, with a UpdateTargetID set. When the validation on the form fails the update target id is replaced with the validation errors, but when there are no validation errors users should be redirected to a new page.
The code in my Partial view is
<div id="div_UID">
<% using (Ajax.BeginForm("FindChildByUID", new AjaxOptions { UpdateTargetId = "div_UID" } ))
{%>
<p>
<label>UID:</label>
<%= Html.TextBox("UID") %>
</p>
<input type="submit" value="Continue" />
<% } %>
</div>
</pre>
The code in my controller is as follows
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult FindChildByUID(Student student)
{
Student matchingStudent = _studentService.FindChildByUID(student.UID);
if (matchingStudent == null)
{
ModelState.AddModelError("UID", String.Format("No matching child found for the entered UID: {0}", student.UID));
return PartialView();
}
else
{
// full view
return RedirectToAction("ConfirmChildDetails", matchingStudent);
}
}
So, for I have been unsuccessful to display the full view on it's own, as it always seems to dipslay the full view in the UpdateTargetID div specfied in the Ajax.BeginForm.
Any suggestions on how I can get this to work?
Thanks
What your AJAX post is doing is making a request and waiting on a response that contains html to input onto the page. The configuration is such that whatever html is returned will be injected into the div you've named "div_UID".
I typically avoid scenarios like this and use traditional posting if a redirect is required upon a successful outcome of the POST.
I imagine you could do it like this using jQuery to submit rather than the Ajax.BeginForm (or just set a callback function for your Ajax.BeginForm):
function SubmitForm(form) {
$(form).ajaxSubmit({ target: "#div_to_update", success: CheckValidity });
}
function CheckValidity(responseText) {
var value = $("#did_process_succeed").val();
if (value == "True") {
window.location.replace("url_of_new_action_here");
}
}
You just have to have a hidden field in your partial view called "did_process_succeed" and set the value of True or False based on some logic in your controller.
There are likely other ways as well. Perhaps someone else will chime in. I hope this helps for now.