How to update underlying ViewModel property when deleting a Photo using an Ajax.ActionLink?
-
27-10-2019 - |
Question
My situation is this:
I have this ViewModel:
public class RealtyViewModel
{
public RealtyViewModel()
{
Realty = new Realty();
Photos = new Collection<File>();
}
public Realty Realty { get; set; }
public Collection<File> Photos { get; set; }
}
I pass this RealtyViewModel
to my Edit.cshtml
view. Inside the Edit view I call a Photos.cshtml
partial view. The Photos partial view also uses the same @model RealtyViewModel
.
Now, inside the Photos.cshtml
partial view I do an AJAX request to delete a photo:
@Ajax.ImageActionLink
(@Url.Content(Model.Photos[i].Path), @Localization.Delete, "640", "480",
"DeletePhoto", new {realtyId = Model.Realty.Id, photoId = Model.Photos[i].Id},
new AjaxOptions()
{
Confirm = @Localization.DeleteConfirmation,
HttpMethod = HttpVerbs.Post.ToString(),
OnComplete = string.Format("deletePhotoFromPage('{0}')",
Model.Photos[i].Id),
OnSuccess = "LoadCycle",
UpdateTargetId = "myDiv",
InsertionMode = InsertionMode.Replace
}, new {data_photoId = Model.Photos[i].Id})
I run this code:
[HttpDelete]
public ActionResult DeletePhoto(string realtyId, string photoId)
{
Realty realty = DocumentSession.Load<Realty>(realtyId);
realty.Photos.Remove(photoId);
File photo = DocumentSession.Load<File>(photoId);
// Deletes the file in the database
DocumentSession.Advanced.DatabaseCommands.Delete(photoId, null);
// Deletes the file in the disk
System.IO.File.Delete(Server.MapPath(photo.Path));
return new EmptyResult();
}
The problem is: my current realtyViewModel
that I passed to the Edit view still references the photos I have deleted using the AJAX calls. Then when I try to save an updated model, it saves everything again holding the old references to the photos I have just deleted.
How can I update my model ( remove the deleted photos from [ model.Realty.Photos
] ) so that it reflects the current state of my Edit view?
Note: now it's working because I'm using the Session
object to store the Ids of deleted photos, but it's not the way I think it should be. There must be a beautiful solution to this that just doesn't come to my mind...
A beautiful solution would be: after a success deletion, the Ajax call should return the deleted photo Id so that I could remove it from [ model.Realty.Photos
]. Then, when I tried to save an edited Realty, it would reflect the changes correctly.
Solution
After a discussion on chat it seems that you have hidden fields in your DOM that you need to remove:
@for (int i = 0; i < Model.Realty.Photos.Count(); i++)
{
@Html.HiddenFor(
m => m.Realty.Photos[i],
new { data_photoid = Model.Realty.Photos[i] }
)
}
Now you could have your controller action return the id of the photo that has to be deleted using JSON for example instead of an empty result:
[HttpDelete]
public ActionResult DeletePhoto(string realtyId, string photoId)
{
...
return Json(new { photoId = photoId });
}
and on the client:
function deletePhotoFromPage(result) {
...
$(':hidden[data-photoid="' + result.photoId + '"]').remove();
}
and also you should use the OnSuccess
option instead of OnComplete
in your Ajax link options:
OnSuccess = "deletePhotoFromPage"
instead of:
OnComplete = string.Format("deletePhotoFromPage('{0}')", Model.Photos[i].Id),
OnComplete
could be invoked even in case of error.