ASP.net MVC - How to setup a modal? - asp.net-mvc

I am really unsure how to do approach modal dialogs in ASP.NET MVC:
The situation is as follows: In my home/index action method, I check if the user has already accepted the terms and conditions. If not, I want to show a dialog to prompt the user for a confirmation.
Now I am really unsure how to approach this in MVC:
The possibilities I see:
Store a TaCConfirmNeeded property in ViewBag, in my view notice that the viewbag contains this token, display a jquery modal dialog with a form to confirm the terms and cond., and call account/confirmTA from this form.
Create a View in my shared folder, that uses my common layout, and is styled like a modal dialog, with a form which sends to account/confirmTA.
Is there a better/easier possibility?

This is how I implement a Modal Pop-Up in MVC. Hope it can help you.
Create a partial view (example):
#model CodeFirst.Models.FriendsInfo
<div>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">FriendsInfo</h4>
</div>
<hr />
<dl class="dl-horizontal">
<dt>
#Html.DisplayNameFor(model => model.Name)
</dt>
<dd>
#Html.DisplayFor(model => model.Name)
</dd>
<dt>
#Html.DisplayNameFor(model => model.Mobile)
</dt>
<dd>
#Html.DisplayFor(model => model.Mobile)
</dd>
<dt>
#Html.DisplayNameFor(model => model.Address)
</dt>
<dd>
#Html.DisplayFor(model => model.Address)
</dd>
</dl>
The controller it's gonna look like:
public ActionResult Details(int Id)
{
FriendsInfo frnds = new FriendsInfo();
frnds = db.FriendsInfo.Find(Id);
return PartialView("_Details",frnds);
}
Later put this on your _Layout:
<div id='myModal' class='modal'>
<div class="modal-dialog">
<div class="modal-content">
<div id='myModalContent'></div>
</div>
</div>
</div>
And your gonna need this script with a little jQuery to call it with AJAX from your view:
<script>
var PostBackURL = '/Home/Details';
$(function () {
// Use your logic, to call this function and replace the parameters like the User.ID
debugger;
var id = User.Id;
var options = { "backdrop": "static", keyboard: true };
$.ajax({
type: "GET",
url: PostBackURL ,
contentType: "application/json; charset=utf-8",
data: { "Id": id },
datatype: "json",
success: function (data) {
debugger;
$('#myModalContent').html(data);
$('#myModal').modal(options);
$('#myModal').modal('show');
},
error: function () {
alert("Dynamic content load failed.");
}
});
});
//$("#closebtn").on('click',function(){
// $('#myModal').modal('hide');
$("#closbtn").click(function () {
$('#myModal').modal('hide');
});
</script>

Related

ASP.NET MVC delete method pass an Id / model to the controller

Using Razor pages for my views, I can't find a way to pass an Id / bounded model to my controller.
I have created a delete template view with my model, added a delete action method to my controller, but I can't figure out how to pass any parameters.
#model AdventureWorks.Models.HumanResources.Department
#{
ViewBag.Title = "Delete";
}
<h2>Delete</h2>
#using (Html.BeginForm("DeleteConfirmed", "Department", FormMethod.Post))
{
#Html.AntiForgeryToken()
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Department</h4>
<hr />
<dl class="dl-horizontal">
<dt>
#Html.DisplayNameFor(model => model.Name)
</dt>
<dd>
#Html.DisplayFor(model => model.Name)
</dd>
<dt>
#Html.DisplayNameFor(model => model.GroupName)
</dt>
<dd>
#Html.DisplayFor(model => model.GroupName)
</dd>
<dt>
#Html.DisplayNameFor(model => model.ModifiedDate)
</dt>
<dd>
#Html.DisplayFor(model => model.ModifiedDate)
</dd>
</dl>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Delete" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Controller
public ActionResult DeleteConfirmed(Department department)
{
return ViewDepartments();
}
The Department object that is returned, is a new object with no properties set.
Could you advise me, how to pass at least an Id of the to be deleted object?
I managed to get the model with the form on my create and update method, but I can't figure out, how to do the same on delete.
You can add the parameters you want to pass in Html.BeginForm.Here is a demo:
#using (Html.BeginForm("DeleteConfirmed", "Department",new { Id=Model.Id}, FormMethod.Post))
{
...
}
result:
And you don't need to add #Html.AntiForgeryToken(),because your form method is post.
DisplayFor will not do the Model binding.
Assuming Id is a key of Department, add
#Html.HiddenFor(model => model.Id)
inside of Html.BeginForm.
Inside of you delete action use department.Id to find and delete the item.
You have to pass some value to your controller.
#using (Html.BeginForm("DeleteConfirmed", "Department", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(m => m.Id) // Use valid expression for id property
...
}
And change signature of DeleteConfirm method to
public ActionResult DeleteConfirmed(int id) // Use valid id property type
{
// Delete object
}
That should do the trick.

Why I get error when I submit login form using jQuery Post?

I have this partial view:
#model GeomindEnterprise.Models.LoginViewModel
<div class="row">
<div class="col-md-6 col-sm-6 col-xs-6">
<!-- /SOCIAL LOGIN -->
#using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "sky-form", role = "form" }))
{
<fieldset class="nomargin">
<div class="row">
<div class="col-md-10 col-md-offset-1">
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<label class="input margin-bottom-10">
<i class="ico-append fa fa-envelope"></i>
#Html.TextBoxFor(m => m.UserName, new { #placeholder = "Email" })
#Html.ValidationMessageFor(m => m.UserName, "", new { #class = "text-danger" })
</label>
<label class="input margin-bottom-10">
<i class="ico-append fa fa-lock"></i>
#Html.PasswordFor(m => m.Password, new { placeholder = "Password" })
#Html.ValidationMessageFor(m => m.Password, "", new { #class = "text-danger" })
</label>
<label class="form-group">
#Html.CheckBoxFor(m => m.RememberMe, new { #class = "col-md-1" })
#Html.LabelFor(m => m.RememberMe)
</label>
<footer>
<button type="submit" onclick="myFunction()" class="btn btn-default noradius pull-right"><i class="fa fa-check"></i> OK, LOG IN</button>
</footer>
</div>
</div>
</fieldset>
}
</div>
</div>
When I click button submit, this javascript method is called:
function myFunction() {
debugger;
jQuery.ajax({
type: "POST",
url: '#Url.Action("Login", "Account")',
contentType: "application/json; charset=utf-8",
data: jQuery('form').serialize(),
datatype: "json",
success: function (data) {
debugger;
jQuery('#myModalContent').html(data);
},
error: function () {
alert("Dynamic content load failed.");
}
});
}
The javascript method above calls this action:
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
//some logic
}
When the acction Login is called I get this error:
The required anti-forgery form field "__RequestVerificationToken" is not present.
Any idea why I get this error?And how to fix it?
Remove the contentType: "application/json; charset=utf-8", ajax option, so that you use the default "application/x-www-form-urlencoded; charset=UTF-8" which you need when using .serialize() (note that the token is included in the request when using .serialize())
As a side note, you should be handling the forms .submit() event so you can validate the form before submitting. Remove the onclick="myFunction()" from your submit button and change the script to
$('form').submit(function(e) {
e.preventDefault();
if (!$(this).valid) {
return; // cancel the ajax call and display error messages
}
... make ajax call
});
You also have datatype: "json",, but the fact you also have $('#myModalContent').html(data); suggests that your controller method returns html (a PartialViewResult), not json, so it should be datatype: "html", (or just omit that option and the $.ajax() method will work it out)
What you want to do is.
contentType: "application/json; charset=utf-8"
And by doing that (which changes the kind of post request being made), to get the Json content of the actual data property to bind correctly to your T model type DO NOT JSON.stringify() or jQuery('form').serialize() the data.
Remove the #Html.AntiForgeryToken() from your form. it will work for now.How ever it will open you for attacks.
Here is the article on anti forgery token to secure yourself.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks

Modal Delete Button Not Working asp.net

I am making a page that stores clients. Clients can have domains and contacts and jobs.
Each contact/domain/job has edit/delete functionality.
I am using MVC 4 ASP.NET c#
each time you wish to edit/delete it launches a modal form.
The delete view for contact and domain is exactly the same except for the fields that it displays. The domain delete function does not fire anything when it is in partial view. But it succeeds when it is navigated to in the url as a regular view. the contact delete works fine in the partial view.
#model STClient.Models.Domain
#{
ViewBag.Title = "DeleteDomain";
}
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"></script>
#using (Html.BeginForm("DeleteDomain", "Client", FormMethod.Post)) {
<div class="modal-header">
<h2>Are you sure you want to delete?</h2>
</div>
<div class="modal-body">
<fieldset>
<div class="display-label">
<h3>
#Html.HiddenFor(model => model.server.ID)
#Html.HiddenFor(model => model.ID)
#Html.DisplayNameFor(model => model.Name):
#Html.DisplayFor(model => model.Name)
</h3>
</div>
<div class="display-label">
<h5>
#Html.DisplayNameFor(model => model.Registrar):
#Html.DisplayFor(model => model.Registrar)
</h5>
</div>
<div class="display-label">
<h5>
#Html.DisplayNameFor(model => model.PrimaryDNS):
#Html.DisplayFor(model => model.PrimaryDNS)
</h5>
</div>
<div class ="display-label">
<h5>
#Html.DisplayNameFor(model => model.SecondaryDNS):
#Html.DisplayFor(model => model.SecondaryDNS)
</h5>
</div>
</fieldset>
</div>
<div class="modal-footer">
<a class="btn" href="">Cancel</a>
<input class="btn btn-danger" type ="submit" value="Delete" />
</div>
}
this is on the details page where the delete link is for the domain.
<div class="modal fade" id="deleteDomain-modal"></div>
<script type="text/javascript">
$(function () {
$(".deleteDomain").click(function () {
$.ajax({
url: "/Client/DeleteDomain",
type: "GET",
data: {id: $(this).attr('id')},
dataType: "html",
success: function(e)
{
$("#deleteDomain-modal").html(e);
}
});
$("#deleteDomain-modal").modal();
});
});
</script>
And finally in the Client Controller
public ActionResult DeleteDomain(int id)
{
Domain domain = db.Domains.Find(id);
if (domain == null)
{
HttpNotFound();
}
return PartialView(domain);
}
[HttpPost, ActionName("DeleteDomain")]
public ActionResult DeleteDomainConfirmed(int id)
{
Domain domain = db.Domains.Find(id);
Server server = db.Servers.Find(id);
db.Domains.Remove(domain);
db.SaveChanges();
db.Servers.Remove(server);
db.SaveChanges();
LogDeleteDomain(domain, server);
return RedirectToAction("Index");
}
I think I had a similar problem. The reason was that parameter value was send as string and not as integer. I had to cast the value. So in your script code you may try to change the line:
data: {id: $(this).attr('id')},
to:
data: {id: parseInt($(this).attr('id'))},
That solved my problem.

JQuery dialogs don't work after ajax partial view reload

I am manipulating a table of data in a View. When the user clicks on the data name, a dialog pops up to allow him to edit the data. When he clicks, delete, a dialog prompts him to make sure, then deletes the row. When he chooses to create new row, a dialog pops up to allow him to enter the new information. In all 3 cases, after the action is complete, the PartialView "_Content" reloads the content <div />.
This all works fine the first time, after the entire page loads. But after the PartialView reloads (after one of the actions), the "Edit" dialog no longer works, though the other 2 do. I can rig the page to reload everything after each action, of course, but that's slower and doesn't make sense in an Ajax world. If I put the JQueryUIHelper for the edit dialog in the partial view, again, it works the first time, but the second time, the form opens up inline on the page rather than in a dialog. I also tried this using JQuery and JQueryUI directly and got the same error. I have been researching this and experimenting for days.
UPDATED 4/1/13:* I added some $.click() callbacks to the link classes. They don't work after the page does the partial refresh. I guess what's happening is that the scripts lose their "connection" to the objects in the content <div> when the content reloads.
I am using MVC4, Razor, and JQueryUI via the JQueryUIHelper extension. The code for the View and PartialView is below.
Are there any ideas??
Here's my View
#model IEnumerable<AttributeLookup>
#{
ViewBag.Title = "Attributes";
}
<h2>
Attributes</h2>
#if (ViewBag.Error != null)
{
<div class="message-error">#ViewBag.Error</div>
}
<div id="content">
#Html.Partial("_Content", Model)
</div>
<div style="padding-top: 12px;">
#Ajax.ActionLink("New", "Create", new { }, new AjaxOptions {
HttpMethod = "Get",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "createContent"
}, new { id = "createLink" })
</div>
#using (Html.JQueryUI().Begin(new Dialog()
.Title("Confirm Delete")
.AutoOpen(false)
.Modal(true)
.CloseOnEscape(true)
.ConfirmAjax(".deleteLink", "Yes", "No",
new AjaxSettings { Method = HttpVerbs.Post, Success = "content" })))
{
<div>
Are you sure you want to delete this attribute?
</div>
}
#using (Html.JQueryUI().Begin(new Dialog()
.Title("Create Attribute")
.AutoOpen(false)
.Width(500)
.TriggerClick("#createLink")
.Modal(true)
.CloseOnEscape(true)
.Button("OK", "save")
.Button("Cancel", "closeDialog")))
{
<div id="createContent" />
}
#using (Html.JQueryUI().Begin(new Dialog(new {id = "editDialog"})
.Title("Edit Attribute")
.AutoOpen(false)
.Width(500)
.TriggerClick(".editLink")
.Modal(true)
.CloseOnEscape(true)
.Button("OK", "save")
.Button("Cancel", "closeDialog")))
{
<div id="editContent" />
}
#section Scripts {
<script type="text/javascript">
var success = function(data) {
$(window.document.body).html(data);
};
var content = function(data) {
$("#content").html(data);
};
var closeDialog = function() {
$(this).dialog('close');
};
var saveCreate = function() {
$("#createForm").submit();
$(this).dialog('close');
};
var saveEdit = function() {
$("#editForm").submit();
$(this).dialog('close');
};
$(".editLink").click(function () { alert("edit clicked"); });
$(".deleteLink").click(function () { alert("delete clicked"); });
</script>
}
Here's the PartialView
#model IEnumerable<AttributeLookup>
#if (ViewBag.Error != null)
{
<div class="message-error">#ViewBag.Error</div>
}
<table id="attribute">
<tbody>
<tr>
<th style="width: 250px;">
#Html.DisplayNameFor(model => model.Name)
</th>
<th style="width: 50px;">
#Html.DisplayNameFor(model => model.Units)
</th>
<th style="width: 30px;">
Contrained
</th>
<th style="width: 400px;">
#Html.DisplayNameFor(model => model.Description)
</th>
<th>
 
</th>
</tr>
#{ int count = 0; }
#foreach (var item in Model)
{
string type = count % 2 == 0 ? "normal" : "alt";
<tr class="#type">
<td>
#Ajax.ActionLink(#Html.DisplayFor(modelItem => item.Name).ToHtmlString(), "Edit",
new { id = item.AttributeLookupID }, new AjaxOptions
{
HttpMethod = "Get",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "editContent"
}, new { #class = "editLink", title = "Edit attribute" })
</td>
<td>
#Html.DisplayFor(modelItem => item.Units)
</td>
<td>
#if (item.AttributeConstraints != null && item.AttributeConstraints.Any())
{
#Html.Raw("X")
}
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td>
#Html.ActionLink("Delete", "Delete", new { id = item.AttributeLookupID }, new { #class = "deleteLink" })
</td>
</tr>
count++;
}
</tbody>
</table>
Here's the Partial for the Edit form. The Create form is similar:
#model AttributeLookup
#using (Ajax.BeginForm("Edit", "AttributeLookup", new AjaxOptions {
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "content"
}, new {id = "editForm"}))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>AttributeLookup</legend>
#Html.HiddenFor(model => model.AttributeLookupID)
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Units)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Units)
#Html.ValidationMessageFor(model => model.Units)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.AttributeConstraints, "Constraint")
</div>
<div class="editor-field">
#Html.DropDownList("ConstraintTypeID")
#Html.DropDownList("SecondaryID")
</div>
</fieldset>
}
I found a solution. First, I removed the TriggerClick from the Helper:
#using (Html.JQueryUI().Begin(new Dialog(new {#id = "editDialog"})
.Title("Edit Attribute")
.AutoOpen(false)
.Width(500)
// deleted --> .TriggerClick(".editLink")
.Modal(true)
.CloseOnEscape(true)
.Button("OK", "saveEdit")
.Button("Cancel", "closeDialog")))
{
<div id="editContent" />
}
And then I explicitly added it to my <scripts>:
$("body").on('click', ".editLink", function () { $("#editDialog").dialog("open"); });
Now it works fine.
I wonder why it works for the other two, but not the edit one? I suspect it has to to with mistakes startingfrom the id. Try taking away id=editdialog. This might be a quickfix. If this doesnt work, keep reading.
The #dialog usually hides due to jqueryUi things that go on at document.ready or page load in the background.
I'm not sure exaclty when it happens, but you'd want to repeat those steps after the reload happens.
At the end of the document in a part thats not reloaded do something like...
<script>
$("body").ajaxComplete( reHideDialog())
function reHideDialog(){
$("#dialog").css('display','none');
}
</script>
when they click the edit link, jqueryui should automatically set the #dialog css display to display:absolute as it renders it in a popup.

Get response as json after a post

I don't know if this is possible or not. I am working with asp.net mvc3 form. I am posting a form to a action and i want to get the response as json.
for example-
#using (Html.BeginForm("Action", "Controller", FormMethod.Post, new { Class = "formValidation", enctype = "multipart/form-data" }))
{
<dt>
<label>
Ad Image:
</label>
</dt>
<dd>
<input id="bannerImage" name="bannerImage" type="file" class="fileupload" />
</dd>
<dt>
<label>
JS Code:
</label>
</dt>
<dd>
#Html.TextAreaFor(m => m.JsCode, 10, 50, new { })
</dd>
<input type="submit" class="button red" value="Update Banner" />}
This is the form. And after submit I want to do something like
public ActionResult Action(Model editModel, HttpPostedFileBase file){
//do something
return Json(new{type="success"});
}
Then receive this from the form page and take some action. Is it possible?
if not please can you give me some hints to do this otherwise.
Use Ajax form instead of Html form. You can subscribe to OnSuccess javascript event and get output in format you like and also in json and process it there.

Resources