MVC 3 Partial View within dialog not working - c#

I have a datatable webpage that shows a list of user in a datatable. On the user page there is a button create new user. On clicking this launches a modal jQuery dialog box for the user to enter details off the new user. There is a Cancel button which just closes the dialog box and a Save User button which on clicking calls DoSaveUser method in my controller. I can see from debugging that I get into the DoSaveUser method which should at the end return to a PartialView if the create user was successful saying User was saved. However my dialog were you enter details is not getting replaced with the Success message - even though the user is getting created - i.e - after I hit the save button - if I then cancel the dialog and refresh the original user page I can see the datatable updated with my new user.
Code on UserList page (there are more fields in the dialog than just forename but have removed them to make question have less code). So when CreateUser button is clicked my newUserDialog is launched.
<div id="newUserDialog">
#using (Html.BeginForm("DoSaveUser", "MyController", FormMethod.Post, new { id = "saveForm" }))
{
<div id="resultContainer">
<table class="ui-widget-content" style="width: 565px; margin-top: 10px;">
<tr>
<td style="width: 100px;">
</td>
<td class="label">
Forename :
</td>
<td class="value">
#Html.TextBoxFor(model => model.Forename, new { style = "width:150px" })
</td>
</tr>
</table>
<div class="ui-widget-content Rounded" style="width: 565px; margin-top: 10px; text-align: center;">
<input id="Cancel" type="button" class="dialog-button" value="Cancel" style="margin: 5px" />
<input id="DoSaveUser" type="submit" class="dialog-button" value="Save User" style="margin: 5px" />
</div>
</div>
}
Javascript code for Save User on the dialog being clicked - submit the form.
$(function () {
$('#saveForm').submit(function () {
var formData = $("#saveForm").serializeArray();
$.ajax({
url: this.action,
type: this.method,
data: formData,
dataType: "json",
success: function (result) {
$('#resultContainer').html(result);
}
});
return false;
});
});
Now in My DoSaveUser method in my controller which I can set a breakpoint and hit and see all the values being sent in correctly for the corresponding fields - once I have saved to the DB this is return.
return PartialView("UserSuccess", model);
And this is all that view contains in the cshtml..note what I wanted was the result container Div which contains all my textbox fields and labels to be replaced with User Created successfully. And then I will need an ok on this page which on clicking will close the dialog box and refresh the UserList page and show the datatable updated with the new user. However when I click save the textboxes just stay on the Div and the Div does not get changed - but if I then cancel the dialog and refresh the page I can see the datatable updated with my new user. Is there something I am missing? (note - i have added jquery.unobtrusive-ajax.js to my _Layout page)
#model MyProject.Models.UserModel
#{
ViewBag.Title = "UserSuccess";
}
<div id="resultContainer">
User Created Successfully
</div>

Are you sure that your initial html do have a #resultContainer div? If you don't the
$('#resultContainer').html(result);
line won't match anything. If you do on the other hand, you will get duplicate nested #resultContainer divs which is also an error (id must be unique).
The right way to do it is to add an empty div in your original html:
<div id="resultContainer"></div>
And in your view output just the content to go inside the div.
#model MyProject.Models.UserModel
#{
ViewBag.Title = "UserSuccess";
}
User Created Successfully

I have to say what you are doing is not a good way of using dialog and partial view in ASP.NET MVC applications. I can give you some simple code to show an idea:
If list.cshtml is a list of users page, and edit.cshtml is a partial view that has an edit form in.
On list page:
$(".grid-row .edit").click(function(){
editUser($(this).attr("data-id"));
});
function editUser(id){
var $dialog=$("#dialogEditUser");
if($dialog.length == 0){
$dialog=$("<div id='dialogEditUser'>").appendTo("body");
}
$dialog.dialog({
...
open:function(){
$dialog.load("/user/edit/"+id, function(){
//todo: handle form events
});
}
});
$dialog.dialog("open");
}
You can also make the open dialog function in a static method, like:
MvcSolution.Dialog = function (id, title, options) {
var $dialog = $("#" + id);
if ($dialog.length == 0) {
$dialog = $("<div id='" + id + "' class='dialog' title='" + title + "'></div>").appendTo("body");
}
$dialog.dialog(options);
$dialog.dialog("open");
};
You can find a good c# and js framework for MVC here

Related

How to handle jquery repeater html in mvc

this is my .cshtml page code,i use jquery repeater is in this code repeater is working fine but i want to add some modification in this repeater but i am stuck here. you can see my code.
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data", #class = "repeater" }))
{
<div data-repeater-list="">
<div data-repeater-item="">
<div class="col-lg-12 col-md-12 col-sm-12">
<input type="file" name="Docfiles" />
</div>
</div>
</div>
<input data-repeater-create type="button" value="Add" />
<button>Save</button>
}
#section Scripts{
<!-- Import repeater js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.repeater/1.2.1/jquery.repeater.js"></script>
<script>
$(document).ready(function () {
$('.repeater').repeater({
// (Optional)
// start with an empty list of repeaters. Set your first (and only)
// "data-repeater-item" with style="display:none;" and pass the
// following configuration flag
initEmpty: true,
// (Optional)
// "show" is called just after an item is added. The item is hidden
// at this point. If a show callback is not given the item will
// have $(this).show() called on it.
show: function () {
$(this).slideDown();
},
// (Optional)
// "hide" is called when a user clicks on a data-repeater-delete
// element. The item is still visible. "hide" is passed a function
// as its first argument which will properly remove the item.
// "hide" allows for a confirmation step, to send a delete request
// to the server, etc. If a hide callback is not given the item
// will be deleted.
hide: function (deleteElement) {
if (confirm('Are you sure you want to delete this element?')) {
$(this).slideUp(deleteElement);
}
},
// (Optional)
// Removes the delete button from the first list item,
// defaults to false.
isFirstItemUndeletable: true
})
});
</script>
}
i want to change html in this formate like this as shown in below screenshot.
Firstly,the name format is set in jquery.repeater.js,if you want to change it,you need to change jquery.repeater.js,here is a demo worked:
1.Add the jquery.repeater.js to your project.
I copy the js to my project like this:
2.Find setIndexes in the jquery and change var newName = groupName + '[' + index + '][' + name + ']' +like this(You can also change it to other format you want):
3.change your script src from cdnjs to your own project:
<script src="~/lib/jquery-repeater/jquery.repeater.js"></script>
4.Result:

Info Modal after Confirmation Modal in Razor Pages

I want to show an info modal that says "Record successfully deleted." after clicking the button inside a Confirmation Modal.
Here is my code to show the confirmation modal
Controller
public IActionResult Delete()
{
return PartialView("_ModalDelete");
}
_ModalDelete.cshtml
#using Data.ViewModels.Modal
#using (Html.BeginForm())
{
#await Html.PartialAsync("_ModalHeader", new ModalHeader { Heading = "Delete" })
<div class="modal-body form-horizontal">
Are you sure you want to delete this record?
</div>
#await Html.PartialAsync("_ModalFooter", new ModalFooter { SubmitButtonText = "Delete" })
}
Example Screenshot:
This seems to be okay on this part. No issues encounter. But after clicking the Delete button, it will show my modal like a whole view. See below:
Here is my code:
Controller - for post of data after clicking delete button
[HttpPost]
public async Task<IActionResult> Delete(int id)
{
try
{
var validationResult = await new RegionHandler(_regionService).CanDelete(id);
if (validationResult == null)
{
await _regionService.DeleteById(id);
return PartialView("_ModalInfo", new Tuple<string, string>(Constants.Message.Info, Constants.Message.RecordSuccessDelete));
}
ModelState.AddModelError(validationResult);
}
catch (Exception ex)
{
var exceptionMessage = await Helpers.GetErrors(ex, _emailService);
ModelState.AddModelError(new ValidationResult(exceptionMessage));
}
ModelState.AddModelError(string.Empty, "Invalid delete attempt.");
return PartialView("_ModalInfo", new Tuple<string, string>(Constants.Message.Error, ModelState.ToString()));
}
_ModalInfo.cshtml
#using Data.ViewModels.Modal
#model Tuple<string,string>
#await Html.PartialAsync("_ModalHeader", new ModalHeader { Heading = Model.Item1})
<div class="modal-body form-horizontal">
#Model.Item2
</div>
#await Html.PartialAsync("_ModalFooter", new ModalFooter { CancelButtonText = "OK", OnlyCancelButton = true})
With the submission of your form you are making a roundtrip to the server, which will issue a completely new html page (even if your html code is only partial).
To remove the question-modal and replace it with a message-modal in the original page (region-list), you will have to use javascript (for the post AND the replacement).
If you want to stick with the roundtrip, make the Delete method return a full html page, which integrates the message-dialog (like the region-list intergrates the question-dialog).
Finally found an answer with this. So basically I just revised everything so that the model validation from controller will still be there.
Heres my code:
For the table markup
<tr>
<td>
#Html.DisplayFor(modelItem => item.RegionName)
</td>
<td>
#Html.DisplayFor(modelItem => item.RegionCode)
</td>
<td>
#Html.DisplayFor(modelItem => item.RegionKey)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td class="text-center">
<a asp-action="Edit" asp-route-id="#item.RegionId"><i class="fa fa-edit text-info"></i></a>
<i class="fa fa-trash text-danger"></i>
</td>
</tr>
where it call a javascript function below:
#section Scripts{
<script type="text/javascript">
function showDeleteConfirmation(message, event, id) {
event.preventDefault();
showConfirmationModal(message).then(function () {
$("#id").val(id);
$("#formDelete").submit();
});
}
</script>
}
where showConfirmationModal() is a promise function that uses bootbox.js (library that wraps bootstrap modal for easier usage).
site.js
function showConfirmationModal(message, title = "Confirm", size = "medium", confirmText = "Yes", canceltext = "No") {
const deffered = $.Deferred();
bootbox.confirm({
title: title,
message: message,
size: size,
buttons: {
confirm: {
label: confirmText,
className: "btn-success"
},
cancel: {
label: canceltext,
className: "btn-danger"
}
},
callback: function (result) {
if (result) {
deffered.resolve(result);
} else {
deffered.reject(result);
}
}
});
return deffered.promise();
}
On callback, it will submit the hidden form below. Ofcourse don't forget to set the id to be deleted.
Hidden form for Delete action
<form method="post" asp-action="Delete" id="formDelete" class="hidden">
<input type="hidden" id="id" name="id" />
<input type="hidden" asp-for="Item1.RegionName" name="RegionName" />
<input type="hidden" asp-for="Item1.Page" name="Page" />
<input type="hidden" asp-for="Item1.SortBy" name="SortBy" />
<input type="hidden" asp-for="Item1.SortOrder" name="SortOrder" />
</form>
To show the Info Message(for success delete), I created a PartialView to make the modal show if theres a data set in a Temporary Data or TempData. This was added under the _Layout.cshtml page:
_ModalScriptsInit.cshtml
#using Data.Utilities
#{
var text = TempData[Constants.Common.ModalMessage];
if (text != null && !text.Equals(string.Empty))
{
<script type="text/javascript">
showDefaultModal("#text");
</script>
}
}
So in my controller once successfully delete I will just set the TempData with its key as shown below:
Controller
[HttpPost]
public async Task<IActionResult> Delete(int id, RegionSearchViewModel searchViewModel)
{
try
{
var validationResult = await new RegionHandler(_regionService).CanDelete(id);
if (validationResult == null)
{
await _regionService.DeleteById(id);
TempData[Constants.Common.ModalMessage] = Constants.Message.RecordSuccessDelete;
return RedirectToAction(nameof(List), searchViewModel);
}
ModelState.AddModelError(validationResult);
}
catch (Exception ex)
{
var exceptionMessage = await Helpers.GetErrors(ex, _emailService);
ModelState.AddModelError(new ValidationResult(exceptionMessage));
}
ModelState.AddModelError(string.Empty, "Invalid delete attempt.");
return RedirectToAction(nameof(List), searchViewModel);
}
I am not sure yet if this is the best way so far. Please give suggestion on how to improve this code. Thanks!

ASP MVC - Editor Templates issue (Sends always data from only first template)

I have a form/view which represents a strongly typed model which contains simple properties and an IEnumerable property. I use an editor template for the IEnumerable property of my model.
for (int i = 0; i < #Model.Items.Count(); i++)
{
#Html.EditorFor(model => #Model.Items[i])
}
Now, the template looks like the following:
#using (Html.BeginCollectionItem("Items"))
{
<table style="width: 100%">
<tr>
<td>
#Html.TextBoxFor(model => #Model.ID, new {id = "ID" })
</td>
<td>
#Html.TextBoxFor(model => #Model.Description, readonly="readonly", new {id = "Description" })
</td>
<tr />
<a role="button" id=getDescBtn>
</a>
</table>
}
And my template's script:
<script type="text/javascript">
$(document).ready(function() {
$("#getDescBtn").on('click', function (event) {
$.ajax({
url: '#Url.Action("LoadDescription")',
async: false,
cache: false,
data: {id: $("#ID").val()}
}).success(function (partialView) {
});
});
});
Now, My controller action looks like:
public ActionResult LoadDescription(string id)
{}
Now, Suppose I have two templates:
In the first one, the ID textbox contains the value of "1".
In the second one, the ID textbox contains the value of "2".
When I press the button in the first template, I get to the controller action twice, both with the value of "1" (from the first template).
When I press the button in the second template, I get to the controller action once, with the value of "1" (from the first template, although I pressed the button of the second template).
Now, what I'm trying to achieve is quite simple logically: press button in first template, get to controller action once with value of "1".
press button in secondtemplate, get to controller action once with value of "2".
Also, the action in controller is responsible to calculate value for description and then fill in the description field. What should the action method return (I don't think I should perform a post for the whole form), and how do I receive it within the success function while using Ajax?
Thanks for any help.
I think you need to use classes for your buttons and editors instead of ids. In your code you have multiple text boxes all with Id=ID and multiple buttons with id=getDescBtn. So $("#ID").val() will just give you the value of the first element with id="ID" which is your first textbox.
As for updating the description, you can have your action return the description value and then set the description text box on the success of your ajax call.
#using (Html.BeginCollectionItem("Items"))
{
<table style="width: 100%">
<tr>
<td>
#Html.TextBoxFor(model => #Model.ID, new {#class = "ID" })
</td>
<td>
#Html.TextBoxFor(model => #Model.Description, readonly="readonly", new {#class = "Description" })
</td>
<tr />
<a role="button" class="getDescBtn">
</a>
</table>
}
<script type="text/javascript">
$(document).ready(function() {
$(".getDescBtn").on('click', function (event) {
$.ajax({
url: '#Url.Action("LoadDescription")',
async: false,
cache: false,
data: {id: $(this).parent().find(".ID").val()}
})
.success(function (data) {
$(this).parent().find(".Description").val(data.description )
});
});
});
public JsonResult LoadDescription(string id)
{
//your logic here
return Json(new {description )});
}

How to get value entered in a text box from a view

My MVC view has a table with an editable field as follows.
<td>
<div class="view">
<%= Model.device_Url%>
</div>
<div class="edit">
<input type="text" name="deviceurl" id = "deviceurl" value="<%= Model.device_Url%>" />
</div>
</td>
The user has the option to edit then save the value entered in the above text box field.
<td class="options">
<div class="view">
Edit
</div>
<div class="edit">
Save
Cancel
</div>
</td>
I would like to call my controller /Live/Update and pass in the value changed in the text box in the URL.
How would I get the value entered inthe text box.
Do I need java script to do this?
You will need javascript unless you want to use a traditional submit.
The easiest approach would be to use jQuery and get the value with a line of code similar to this:
$("#deviceurl").val()
I would then make an ajax call to submit the value back to your controller's action. You also probably want to use the Url.Action helper to build the Url:
$.ajax(
url: '<%=Url.Action("Update")%>,
data : {deviceUrl : $("#deviceurl").val()},
success : function (result){
// handle logic when the update succeeds
}
);
Hope this helps
My advise will for you to use Html.ActionLink instead of using this Save
like this :
<%=Html.ActionLink("Save",
"Live", // <-- Controller Name.
"Update", // <-- ActionMethod
new { streamurl = deviceurl },
new { #class = "save refresh" }
)
%>

Problems with a JQuery dialog displaying a blank window when updating .html() inside with MVC

I'm having a problem with a JQuery dialog being empty when displayed. I know what the problem is but can't figure out how to fix it. I hope to find some help here.
Issue:
I have a page with a simple list of users. Every item/user on the list has an EDIT link. When clicked edit a dialog box pops up with details for that user. Great! Sounds simple enough.
So the user list initializes the partial view that'll be a dialog box:
#Html.Partial("EditUser", new User())
That pre-loads the partial view and the dialog is initialized with a regular:
$(function () {
$("#edit-user-dialog").dialog({
title: "Edit User",
autoOpen: false,
height: 500,
width: 600,
modal: true
});
});
So far so good...
The partial view itself is a regular page with Ajax form submit that allows me to submit modified user info. Everything associated to that popup, such as its DIV, connected JScripts must be contained within just so information could be easily found later. Here is the sample code of the Partial View that will be displayed as a dialog:
#model MyNamespace.User
<script src="#Url.Content("~/myUserEditScriptScripts.js")" type="text/javascript"></script>
<div id="edit-user-dialog" style="display: none">
#using (Ajax.BeginForm("SaveUserJson", "User", new { id = Model.Id }, new AjaxOptions
{
HttpMethod = "post",
OnSuccess = "editUserSuccess()",
}))
{
<div class="display-field">
#Html.DisplayFor(model => model.Name)
</div>
.
.
.
Various controls go here...
.
.
.
<p>
<input type="submit" value="Detach" />
</p>
}
</div>
Standard stuff so far...
So when the initial list of users is loaded the "Edit users" partial view gets pre-loaded on the page but it's not visible because the div is set to display: none and it's initialized as being a dialog popup.
Next when an "edit" link is clicked next to a specific user I would like that popup to be populated with the information of that selected user.
Ajax to the rescue!
On "Edit" link click I load the partial view with the selected user data:
function editUserLoad(userId) {
$.ajax({
url: '/User/EditUser/',
data: { id: userId },
type: 'post',
datatype:'html',
success: function (data) {
$("#edit-user-dialog").html(data);
$("#edit-user-dialog").dialog('open');
}
});
}
Works great! It grabs the selected userId, jumps to my action method that returns the partial view populated with the User data I want to display.
The problem is that the dialog is displayed empty ! Well I know why. It's empty because the dialog DIV is set to "display: none". But why ? Doesn't .dialog('open'); override display: none and doesn't it suppose to show the content of the dialog even if it was hidden ?
I tried to have .show separately but it didnt work.
Help ?
Could you try this approach. Just create an empty div like following
<script type="text/javascript">
$(function () {
$('#dialog').dialog({
autoOpen: false,
width: 400,
resizable: false,
title: 'Edit User',
modal: true,
open: function(event, ui) {
//Load the Edit User partial View
$(this).load("#Url.Action("action","controller",new {ID = user_id})");
},
buttons: {
"Close": function () {
$(this).dialog("close");
}
}
});
$('#my-button').click(function () {
$('#dialog').dialog('open');
});
});
</script>
<div id="dialog" title="Edit User" style="overflow: hidden;">
//return partial view
public ActionResult EditUserView(int id)
{
UserModel um = new UserModel(id);
return PartialView(um);
}
THERE is a very nice example here, which you can use to

Categories