MVC 4 - Unable to update a partial view via an Ajax call - asp.net-mvc

I have an MVC 4 view that contains a partial view. The partial view is included in the main view as follows:
<div id="PartialView">
#Html.Partial("_PhotoList", #Model)
</div>
My partial view looks as follows:
#model ExchangeSite.Entities.EstateSaleSellerListing
<div style="width: 1300px; height: 300px; overflow: auto">
#foreach (var photo in #Model.ImageList)
{
<a href="javascript:DeletePhoto(#photo.ImageId);">
<img src="#Url.Action("GetPhoto", new { id = photo.ImageId })" alt="" title="Click on the image to remove it" width="250" height="190"/>
</a>
}
</div>
<script>
function DeletePhoto(imageId) {
var Url = "/EstateSaleSellerListing/DeletePhoto";
$.get(Url, { imageId: imageId }, function (data) {
$("#PartialView").html(data);
});
}
</script>
As you can see, when a user clicks on an image, the DeletePhoto() method is called. It makes a call to an action method named DeletePhoto on the named controller. The action method deletes the photo, generates a new list of photos and updates the partial view. Everything works except the partial view is never updated.
My controller code is as follows:
public ActionResult DeletePhoto(int imageId)
{
var photo = this._systemLogic.GetItem<Photo>(row => row.ImageId == imageId);
this._systemLogic.DeleteItem(photo);
EstateSaleSellerListing listing = new EstateSaleSellerListing();
GetPhotoList(listing);
return PartialView(listing);
}
The EstateSaleSellerListing entity has a list of photo objects that get displayed in the partial view.
I don't have enough experience to know why my partial view isn't updating when the action method returns.

Try to move your javascript to your main page and change
return PartialView(listing);
to
return PartialView("_PhotoList", listing);

Check your cache settings in jQuery (it looks like you're using jQuery by the syntax anyway). And I think your second parameter is a bit off (not assigning it to data)... Try this
<script>
function DeletePhoto(imageId) {
var Url = "/EstateSaleSellerListing/DeletePhoto";
$.get(Url, { cache: false, data: { imageId: imageId }}, function (data) {
$("#PartialView").html(data);
});
}
</script>

You could also have the controller method render the partial view to string if it is being loaded in a partial.
Controller...
model.PartialViewContent=PartialToString("Partials/SmallerPart",model);
return PartialView("Partials/LargerPart",model);
View
$("#PartialView").html(data.PartialViewContent);
Fyi, PartialToString is not built into mvc. I had to hack that together

Related

model values are not showing in partial update view

In my web app I have a grid list. I select a row and then click the edit button to show a partial update view (which I use to add new data too) in a popup window. The view shows, but I don't have any values in the textboxes. I use devextreme components, but I think, my issue has nothing to do with it (maybe I'm wrong).
This is the onClick code:
function editrow_onClick() {
var key = $("#grid").dxDataGrid("instance").getKeyByRowIndex(selectedRowIndex);
$.ajax({
url: '/MasterData/Sender/UpdateSender/'+key,
}).done(function (response) {
var popup = $("#sender-popup").dxPopup("instance");
popup.option("contentTemplate", function (content) {
content.append(response);
});
popup.show();
});
}
If I click the edit button, I get the right url like /MasterData/Sender/UpdateSender/3.
The corresponding controller action looks like this:
[Route("{id}")]
public IActionResult UpdateSender(long SenderId)
{
return PartialView("NewSender", SenderRepository.GetSender(SenderId));
}
On top of the controller class I have the corresponging attribute: [Route("MasterData/[controller]/[action]")]
I testet id, the action is reached, but the SenderId is 0. I would expect f.e. 3. This should be causing the empty view, I think. Why is SenderId 0 (the default value)?
I post the update view too, maybe this is the source of the problem (don't bother the AddSender action, I plan to change it conditionally, if I get the update data working):
#model Sender
<form asp-action="AddSender" asp-controller="Sender" method="post">
#using(Html.DevExtreme().ValidationGroup()) {
#(Html.DevExtreme().Form<Sender>()
.ID("form")
.ColCount(1)
.Items(items => {
items.AddSimpleFor(m => Model.Name);
items.AddSimpleFor(m => Model.Address);
items.AddSimpleFor(m => Model.ContactPerson);
items.AddSimpleFor(m => Model.ContactEmail);
items.AddGroup().Items(groupItem => groupItem.AddSimple().Template(
#<text>
<div style="text-align: right">
#(Html.DevExtreme().Button().ID("save").Text("Mentés").Width(100).Type(ButtonType.Success).UseSubmitBehavior(true))
#(Html.DevExtreme().Button().ID("cancel").Text("Mégsem").Width(100).Type(ButtonType.Normal).OnClick("close_onClick"))
</div>
</text>));
})
.LabelLocation(FormLabelLocation.Top)
.FormData(Model)
)
}
</form>
<script>
function close_onClick() {
$("#sender-popup").dxPopup("hide");
}
</script>
[Route("{SenderId}")] public IActionResult UpdateSender(long SenderId) { return PartialView("NewSender", SenderRepository.GetSender(SenderId)); }
Try replacing id with SenderId.
Then action method will hit with the desired value.

PartialView redirects rather than inserts

I have a form and a partial view on my razor page, the idea being that if I change the dropdownlist, the Controller does some work and sets a ViewBag.ShowAlert (bool) that triggers the partial view to be displayed.
While this works, instead of just showing the code within the partial view, the partial view shows as a new view rather than on the same view.
Any idea why?
The view looks like this
#using (Html.BeginForm("AlterVote", "ChangeVoteType"))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h1>New voting preference</h1>
<hr />
<p>Please select the type of vote you wish to change to #Html.DropDownListFor(model=>model.SelectedType, ViewBag.myList as SelectList, "Voting type", new { onchange = "this.form.submit();"})</p>
<div id="partialDiv">
#if (ViewBag.ShowAlert)
{
#Html.Partial("VotingChange")
}
</div>
</div>
}
The controller handling the HttpPost is this
[HttpPost]
public PartialViewResult AlterVote(Dropdown dropType)
{
ChangeBoilerPlate(dropType.SelectedType);
dropType.CurrentType = VoteTypeNames[(int)HomeController.VoterModel.CurrentVoteType];
return PartialView("VotingChange", dropType);
}
I'm guessing that this is down to the initial view being a form, so the partial gets confused as to where to insert the view.
If I understand correctly, by the partial view shows as a new view you mean it comes with a html tag, body and the full layout again. To solve this, you need to set up the layout to null inside your partial view, like so:
#model YourNamespace.Dropdown
#{
Layout = null;
}
<!-- partial view html below -->
<div>
</div>
The div tag is just to illustrate.
While this might solve your problem, you might want to load the partial view without reloading the whole page again. This is possible using ajax, like so:
Main View
#using (Html.BeginForm("AlterVote", "ChangeVoteType"))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h1>New voting preference</h1>
<hr />
<p>Please select the type of vote you wish to change to #Html.DropDownListFor(model=>model.SelectedType, ViewBag.myList as SelectList, "Voting type", new { id = "vote"})</p>
<div id="partialDiv">
</div>
</div>
}
<script type="text/javascript">
$(document).ready(function () {
$('#vote').change(function() {
var selectedType = $(this).val();
$.post('yourserver/YourController/AlterVote', { "SelectedType": selectedType })
.done(function (data) {
$('#partialDiv').html(data);
})
.fail(function () {
console.log('Whoops, something went wrong!!!');
});
});
});
</script>
So I just added a javascript to listen to that same change event on your dropdrown, but instead of submitting the form, I just use ajax to load the partial view html without reloading the entire page.
Just fix the URL and remember to set up layout to null in your partial view. Also, you might want this javascript in a separate file, thus loading it with bundles.

Can you just update a partial view instead of full page post?

Is there a way to submit a partial view form in asp.net mvc without reloading the parent page, but reloading the partial view only to its new state? Similar to how knockout.js updates using data-bind.
My data table renders with a variable number of columns/names so I don't think knockout.js is an option for this one, so I am trying to use a partial view instead.
Not without jQuery.
What you would have to do is put your Partial in a div, something like:
<div id="partial">
#Html.Partial("YourPartial")
</div>
Then, to update (for example clicking a button with the id button), you could do:
$("#button").click(function () {
$.ajax({
url: "YourController/GetData",
type: "get",
data: $("form").serialize(), //if you need to post Model data, use this
success: function (result) {
$("#partial").html(result);
}
});
})
Then your action would look something like:
public ActionResult GetData(YourModel model) //that's if you need the model
{
//do whatever
return View(model);
}
Actually, if your Partial has a child action method, you can post (or even use an anchor link) directly to the child action and get an Ajax-like affect. We do this in several Views.
The syntax is
#Html.Action("MyPartial")
The Child Action is
public ActionResult MyPartial()
{
return PartialView(Model);
}
If your form posts to the child action
#using (Html.BeginForm("MyPartial"))
{
    ...
}
The Partial View will be updated with the partial view returned from the child action.
Jquery is still a legitimate way to update a partial. But technically, the answer to your question is YES.
As normal what I find when looking for things like this is people give too limited information so I will attempt to help here. The key is to set up a div with an ID you can append the return html to. Also when hitting your controller make sure it returns the partial. There are some potential problems with this method but on a good day it should work.
<div id="CategoryList" class="widget">
#{
Html.RenderPartial("WidgetCategories.cshtml");
}
</div>
function DeleteCategory(CategoryID) {
$.get('/Dashboard/DeleteWidgetCategory?CategoryID=' + CategoryID,
function (data) {
if (data == "No") {
alert('The Category has report widgets assigned to it and cannot be deleted.');
}
else {
$('#CategoryList').html(data);
}
}
);
}
[HttpGet("DeleteWidgetCategory")]
[HttpPost("DeleteWidgetCategory")]
public IActionResult DeleteWidgetCategory(string CategoryID)
{
string Deleted = CategoryModel.DeleteCategory(CategoryID);
if (Deleted == "Yes")
{
return PartialView("WidgetCategories");
}
else
{
return this.Json("No");
}
}
I would use the Ajax Form helper for such scenarios using a partial view and #html.RenderPartial("partialName")
partial helpers
In your Main View
<div id=SearchResult>
#Html.Partial("_NameOfPartialView", Model)
</div>
<input type="button" id="btnSubmit" value="Submit">
In your Javascript file
$('#btnSubmit').click(function () {
GetData(Id);
});
function GetData(Id){
$.ajax({
url: "/Home/GetEmployee/",
type: "get",
data: { Id:Id },
success: function (result) {
$('#SearchResult').html(result);
}
});
}
In your Home Controller
public ActionResult GetEmployee(int Id)
{
var employee= context.Employee.Where(x=> x.EmployeeId == Id)
return this.PartialView("_NameOfPartialView", employee);
}

ASP.NET MVC Refresh usercontrols

ASP.NET MVC
I have one page Index.aspx where I'm loading two usercontrols into divs. This is working fine. For the moment the usercontrols just shows data and thats working fine. But now I want to add a delete function in the usercontrols and then refresh the div in the Index.aspx page. Is this possible?
Index.aspx
<!-- Panel One -->
<div id="panel1">
<img src="/Content/ajax-loader.gif" alt="Loading..." />
</div>
<script type="text/javascript">
$('#panel1').load('../Reports/ReportOne')
</script>
<!-- Panel Two -->
<div id="panel2">
<img src="/Content/ajax-loader.gif" alt="Loading..." />
</div>
<script type="text/javascript">
$('#panel2').load('../Reports/ReportTwo')
</script>
ReportOne.ascx and ReportTwo
Just listing some data with a foreach. Here I want to add a deletebutton for each item in the lists.
Make your "delete" action into something like this:
[AcceptVerbs(HttpVerbs.Post), ValidateAntiForgeryToken]
public ActionResult Delete(int id) {
try {
// do what ever here in deleting the record etc
// ...
return null;
} catch (Exception ex) {
TempData[TempDataKeys.ErrorMessage] = "Error in deleting: " + ex.Message;
return RedirectToAction("List");
}
}
In you ascx/aspx, create a jQuery method to wrap your ajax call to the controller:
function deleteRecord(recordId) {
if (confirm("Are you sure that you want to delete this record?")) {
var token = $("input[name='__RequestVerificationToken']")[0].value;
url = '<%= Url.Action("Delete", "MyController") %>';
$.post(
url,
{ id: recordId, __RequestVerificationToken: token },
function(data) {
if (!data == "") {
// success - reload/refresh panel control
$('#panel1').load('../Reports/ReportOne');
} else {
// failed - handle error
}
}
);
}
}
You will need to put your AntiForgeryToken appropriately so the script can access it - you only need 1 for the whole page. Your delete link should then call to the javascript, instead of to the action in the controller directly:
Delete
When the user clicks on the delete button inside the user control you could invoke an action that will delete the necessary information from the database and return a partial view refreshing the control. So put a delete link inside the control:
<%= Html.ActionLink("Delete", "DeleteReportOne", null, new { id = "deleteReportOne" }) %>
and then inside the main page register the click callback for this link:
$(function() {
$('#deleteReportOne').click(function() {
$('#panel1').load(this.href);
});
});
You may use JQuery UI tabs to add and remove the content from the page
JQuery UI Manipulate tabs
JQuery Tabs and ASP.NET MVC Partial Views
you need to modify your user controls

Render an action that returns a partial view in a view

Suppose I have an action that returns an rendered asp.net mvc control and send it as a response for AJAX request.
I want to have the response of that action during the whole page is rendering in a view.
public class Controller
{
....
public ActionResult AjaxAction(string parameter)
{
return PartialView("~/Views/Controls/Control.ascx",parameter);
}
}
now in view that renders the whole page I want something like:
<%var par = "1";%>
<%= AjaxAction(par) %>
Depending on what you want to achieve partial requests may work for you. This is typically useful where your control is some form of 'widget'.
I would use the jQuery load function, fired when the document is ready, and load the partial view into a div.
$(function() {
$('#partialResult').load( '<%= Url.Action( "AjaxAction", "Controller", new { parameter = "1" } ) %>' );
}
<div id="partialResult">
</div>

Resources