ASP.Net MVC Ajax RenderPartial not rendering correctly - asp.net-mvc

I have an AJAX form which returns a partial view, but instead of the target div getting updated, when I submit, only the partial view is shown. As far as I can tell, I have everything set up the way it's supposed to be, what's going wrong?
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ApplianceSurvey.Models.Item>" %>
<% using (Ajax.BeginForm("AddSurveysAJAX",
new AjaxOptions { UpdateTargetId = "SurveyListContent", InsertionMode = InsertionMode.Replace }))
{ %>
<%= Html.Hidden("itemID", Model == null ? ViewData["itemID"] : Model.ItemID) %>
<%= Html.ListBox("SurveysLst", ViewData["Surveys"] as MultiSelectList)%>
<input type="submit" value=">>>" />
<%= Html.ListBox("SelSurveysLst", ViewData["ItemSurveys"] as MultiSelectList)%>
<% } %>
and in the controller:
[AcceptVerbs(HttpVerbs.Post)]
public PartialViewResult AddSurveysAJAX(FormCollection formValues)
{
//do stuff
return PartialView("ItemSurveys");
}

Related

How to prevent a page gets refreshed?

I have DropDownList and a submit button on my page. DropDownListhas list of data from the database, and while selecting value from the dropdown and then clicking on submit button, I am getting number of records of selected dropdown list value in partial view of the main view page. My code is giving proper output. I have bind View to controller through model. Using html.hiddenfor.
But whenever I click on submit button as usual my whole page gets refreshed. But I need to refresh only partial view rather than whole page.
This is my code which is working properly. But by this code my whole page is getting refreshed. And I want to prevent it. :
view:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<ApricaCRMEvent.Models.CRM.DatabaseEntities.CRM_Doctor_Request>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
MDLNoDDLIndex
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<script type="text/javascript">
function TestFun() {
var mdlno = $("#ddlMDLNo").val();
var txtmdlno = document.getElementById("Request_For_Id");
txtmdlno.value = mdlno;
}
</script>
<div>
<h2>Search by MDLNo</h2>
<% using (Html.BeginForm())
{ %>
Select MDLno
<%= Html.DropDownList("ddlMDLNo", ViewData["MDLno"] as SelectList, "--Select One--", new { onchange = "TestFun()" })%>
<%: Html.HiddenFor(model => model.Request_For_Id) %>
<input type="submit" value="search" name="SearchMDLNo" id="btnclick" />
<% } %>
</div>
<div id="showtable"> //partial view
<% if (ViewBag.load == true)
{ %>
<%Html.RenderAction("MDLNoDataList"); %>
<% } %>
</div>
</asp:Content>
Controller:
// Search by mdl no
public ActionResult MDLNoDDLIndex()
{
ViewData["MDLno"] = new SelectList(CRMSearchReportDL.getAllMDLno(), "Request_For_Id", "Request_For_Id");
ViewBag.load = false;
return View();
}
[HttpPost]
public ActionResult MDLNoDDLIndex(CRM_Doctor_Request model)
{
ViewData["MDLno"] = new SelectList(CRMSearchReportDL.getAllMDLno(), "Request_For_Id", "Request_For_Id",model.Request_For_Id);
ViewBag.load = true;
return View();
}
public ActionResult MDLNoDataList()
{
List<CRM_Doctor_Request> drlist = new List<CRM_Doctor_Request>();
return PartialView(drlist);
}
[HttpPost]
public ActionResult MDLNoDataList(CRM_Doctor_Request model)
{
return PartialView(CRMSearchReportDL.getMDLNoWiseDetails(model.Request_For_Id));
}
You can use jQuery to do this for you. Capture the form submit in jQuery and instead of performing a full form post through the browser, submit your form data to a controller action using jQuery's .ajax() method.
Something like this:
$.ajax({
url: urlToControllerAction,
data: {
ddlMDLNo: ddlMDLNo,
Request_For_Id: Request_For_Id
},
type: 'POST',
success: function (results) {
var partialData = $(results);
$('#showtable').html(partialData);
},
error: function (xhr, ajaxOptions, thrownError) {
// do something
}
});

asp.net mvc Ajax.BeginForm clone

I'm using asp.net mvc ajax.
The partial view is using Ajax.BeginForm (just an example):
<div id="divPlaceholder">
<% using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "divPlaceholder" })) { %>
... asp.net mvc controls and validation messages
<input type="submit" value="Save" />
<% } %>
</div>
After update, if validation fails, the html is:
<div id="divPlaceholder">
<div id="divPlaceholder">
...form
</div>
</div>
I don't like that the returned html is inserted, instead it should replace original div.
Probably on POST I should not render <div> around form in partial view or render the div without id.
What else can I do in this situation?
I was thinking that maybe I should write a helper, something like Ajax.DivBeginForm, which will render form inside div on GET and hide the div on POST.
Can somebody provide a good advice how to write such helper (Ajax.DivBeginForm)?
I'd like it to work with using keyword:
<% using (Ajax.DivBeginForm(new AjaxOptions { UpdateTargetId = "myId" })) { ... }%>
My solution. Please comment if something is wrong.
public class DivMvcForm : MvcForm
{
private bool _disposed;
private MvcForm mvcForm;
private ViewContext viewContext;
public DivMvcForm(MvcForm mvcForm, ViewContext viewContext) : base(viewContext)
{
this.mvcForm = mvcForm;
this.viewContext = viewContext;
}
protected override void Dispose(bool disposing)
{
if (!_disposed)
{
_disposed = true;
mvcForm.EndForm();
viewContext.Writer.Write("</div>");
}
}
}
Helper
public static class AjaxHelperExtensions
{
public static MvcForm DivBeginForm(this AjaxHelper ajaxHelper, AjaxOptions ajaxOptions)
{
var tagBuilder = new TagBuilder("div");
if (ajaxHelper.ViewContext.HttpContext.Request.RequestType == "GET"
&& string.IsNullOrWhiteSpace(ajaxOptions.UpdateTargetId) != true)
{
tagBuilder.MergeAttribute("id", ajaxOptions.UpdateTargetId);
}
ajaxHelper.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag));
var theForm = ajaxHelper.BeginForm(ajaxOptions);
return new DivMvcForm(theForm, ajaxHelper.ViewContext);
}
}
And how it works
<% using (Ajax.DivBeginForm(new AjaxOptions { UpdateTargetId = "divPlaceholder" })) { %>
... controls
<% } %>
Result - when ModelState is invalid the partial view returns div without id.
I'm going to take a little different approach here, rather than getting your original solution to work, I'd recommend using the pattern normally followed in this scenario and not using a helper. I realize this is a bit later than the original post, but for future use by anyone : )
If your partial view has a form, then you will keep posting, and returning a form in a form in a form in a form, etc. so you want to have your PARENT contain BeginForm, the div, and renderpartial
using (Ajax.BeginForm("Index", "ProjectManager", new AjaxOptions() ....
<div id="divPlaceholder">
Html.RenderPartial(....)
</div>
If you want to encapsulate this logic in say, an "Order" partial view that is displayed on a Customer screen, then you have two options.
1. Include the BeginForm on the parent Customer view (which reduces code reusability as any view that wants to include the "Order" partial view must include the ajax wiring.
Or
2. You have two partial views for order. One is OrderIndex.ascx (or cshtml if razor) and one is OrderIndexDetail.ascx (or whatever naming convention you decide)
OrderIndex contains your Ajax.beginform and OrderIndexDetail has no form, only the partial view details.
Option 2 is more code (ok, literally about 30 more seconds of coding to move the ajax.beginform into another view) but increases code reusability.
You can handle submit form yourself:
<div id="divPlaceholder">
<% using (Html.BeginForm("action", "controller", FormMethod.Post, new { id = "submitForm"})) { %>
... asp.net mvc controls and validation messages
<input type="submit" value="Save" />
<% } %>
</div>
and write some javascript as:
$('#submitForm').submit(function() {
$.post('post-to-this-url',
data: { foo: formvalue1, bar: formvalue2},
function(data) {
// update html here
});
return false;
})

UserControl-like behavior in ASP.NET mvc

Decided to learn ASP.NET MVC and instantly got stuck on something simple.
In Web Forms user controls allowed to separate application into components based on functionality and facilitated reuse. It seems partial views are supposed to do something similar in ASP.NET MVC, but either I am getting this wrong, or each visible page is handled by single controller and it is not possible to delegate certain page portions to separate controllers without hard-coding these controller relationships.
RenderAction can render a partial view and insert resulting HTML in the page, but if we want this view to be refreshed when the user clicks on some link within this view together with the entire page, we need all the partial view links to refer to the parent controller?
For example:
Home\Index.aspx:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">Home</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
...
<% Html.RenderAction("Index", "Posts"); %>
...
Posts\Index.aspx:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<BlogEngine.Models.PostsViewModel>" %>
<% foreach(var item in Model.Posts){ %>
<p class="postMeta"><%: string.Format("{0} {1}", item.CreatedAt, item.CreatedBy) %></p>
<h1><%: item.Title %></h1>
<div><%: item.Content %></div>
<% } %>
<% if (Model.CurrentPage > 0){ %>
<%: Html.ActionLink("Newer posts", "Index", "Home", new { page=Model.CurrentPage - 1}, null) %>
<%} %>
<% if (Model.CurrentPage + 1 < Model.TotalPages) { %>
<%: Html.ActionLink("Older posts", "Index", "Home", new { page=Model.CurrentPage + 1}, null) %>
<% } %>
PostsController:
public class PostsController : Controller
{
private const int PostsPerPage = 2;
private readonly IPostRepository _postRepository;
public PostsController()
{
...
}
public ActionResult Index(int page = 0)
{
var model = new PostsViewModel();
int totalPages = 1;
model.CurrentPage = page;
model.Posts = _postRepository.GetPosts(page, PostsPerPage, out totalPages);
model.TotalPages = totalPages;
return PartialView(model);
}
}
There's got to be a better way than this?
I don't know if I understand correctly but you could load this Partial View in a using Ajax (by jQuery), and when you need to refresh only this part of content you reload the element. Something like this:
In Javascript:
function LoadComments(page) {
//It'll return a partial view
$("#comments").load("<%=Url.Action("Posts", "Index")%>?page=" + page);
}
$(document).ready(function() {
LoadComments(0);
});
Inside of yoru PartialView you need to render a javascript code to call the "reload" of the next (page) content, so call LoadComments(index-page)...
Look the Ajax APi of jQuery: http://api.jquery.com/category/ajax/
Cheers

How to bind list to a controller

How to bind a list to a controller?
Code in my controller, HTTPGET and HTTPPOST :
public ActionResult Client(string id)
{
List<Customer> Contacts = WebService.GetContactsOfClient(id);
return View(Contacts);
}
[HttpPost]
public ActionResult Client(List<Customer> custs)
{
// custs = null!!! Why??
return View();
}
Code in my view :
<% using (Html.BeginForm("Client", "Formulaire", FormMethod.Post, new { id = "form" })) { %>
<% foreach (var item in Model) { %>
<%:item.MiseAjour %><br />
<% } %>
<input type="submit" />
<% } %>
Thank you all...
If you want to get some values back in your POST action you need to POST them which is achieved using input fields:
<% using (Html.BeginForm() { %>
<%= Html.EditorForModel() %>
<input type="submit" value="OK" />
<% } %>
This outlines what you're trying to achieve.
Model Bind to a List<> when Posting JavaScript Data Object
If you have specific questions, post them
Your view is not rendering any html input elements which are required if you want the model binder to put your model back together on the post. See this answer here which shows binding to a collection and posting to back. Also check out this post for binding to a dynamic list.
Solution for me :
<legend>Contacts</legend>
<% for (int i = 0; i < Model.Contacts.Count; i++) { %>
<%: Html.EditorFor(model => model.Contacts[i],"Contact") %>
<% } %>
With this, I bind my list to controller!
Thank you all!!

strongly-typed partial views MVC RC1

having a problem passing ViewData.Model to the partial views. It always is defaulting to null even if I equate it to a result query. I cannot access the strongly typed data because the Model is null. My current code is this,
ViewPage
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% Html.RenderPartial("header", this.ViewData.Model); %>
<% Html.RenderPartial("test", this.ViewData.Model); %>
<div id="userControls">
</div>
</asp:Content>
UserControl - header
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<testMVCProject.Models.information>" %>
<h2>
ACReport</h2>
<p>
id:
<%= Html.Encode(Model.id) %>
</p>
<p>
type:
<%= Html.Encode(Model.type) %>
</p>
UserControl - test
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<testMVCProject.Models.information>" %>
<% using (Ajax.BeginForm(
"pressureV2",
"Home",
new { id = ViewData.Model.id },
new AjaxOptions
{
UpdateTargetId = "userControls",
HttpMethod = "GET"
},
new { #id = "genInfoLinkForm" }))
{%>
<%= Html.SubmitButton("hey", "Lol") %>
<%} %>
Controller
public ActionResult header(int id)
{
var headerResults = from c in db.information
where c.id == id
select new information
{
id = c.id,
type = c.type
};
ViewData.Model = headerResults.FirstOrDefault();
return View(ViewData.Model);
}
public ActionResult pressureV2(int id)
{
var pressureVResults = from c in db.pressure_volume_tests
where c.id == id
select new pressureVT
{
bottomCVP = c.bottom_CVP,
topCVP = c.top_CVP
};
ViewData.Model = pressureVResults.FirstOrDefault();
return View(ViewData.Model);
}
In the comments you have said that the view is not strongly typed. Because of that:
<% Html.RenderPartial("header", this.ViewData.Model); %>
<% Html.RenderPartial("test", this.ViewData.Model); %>
will not work. If you strongly type your view to testMVCProject.Models.information and then pass an instance of that type from your constructor it will work.
Controller:
public ActionResult ShowAView()
{
Return View("WhateverYourViewIsCalled", new information());
}
You have a misunderstanding of the use of Html.RenderPartial helper.
When you use the RenderPartial you will show the view without requesting the model from the controller.
So you have to refactor your ViewPage and pass the good Model to your usercontrols:
Exemple:
Controller:
ActionResult MainView()
{
var mainviewobj = new MainViewObject();
var headerResults = from c in db.information
where c.id == id
select new information
{
id = c.id,
type = c.type
};
mainviewobj.info = headerResults.FirstOrDefault();
return view(mainviewobj);
}
View Code:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% Html.RenderPartial("header", this.ViewData.Model.info); %>
<% Html.RenderPartial("test", this.ViewData.Model.info); %>
<div id="userControls">
</div>
</asp:Content>
View Code Behind
public partial class MainView : ViewPage<MainViewObject>
{
}
Now the Model will not be null in your usercontrol.
But remember the usercontrol rendering partially dun execute the code in the controller
So you dun need the public ActionResult header(int id) in your Controller
Hope this helps.
Have you tried making the ViewPage generic as well?
The Controller doesn't get called when you RenderPartial - it is bypassed and the view is rendered directly. So whatever you want to pass in as a model needs to be done from the calling View.
I found this worked for me, reference the partial as you do, like so.
...form
#Html.Partial("_AboutYou", Model.AboutYou);
..end form
within the partial view at the top...
#model <namespace1>.<namespace2>.<namespace3>.CustomerInfo.AboutYou
#{
ViewData.TemplateInfo.HtmlFieldPrefix = "AboutYou";
if (this.ViewContext.FormContext == null)
{
this.ViewContext.FormContext = new FormContext();
}
}
I believe the problem might be that you're missing an element in the form with the name "id" so the parameter of the Action method is never populated with a value?
That way the query would always return null with the FirstOrDefault, hence the null Model.
Just my guess...

Resources