asp.net 4.0 MVC 3 ajax form in Overlay - asp.net-mvc

I am interested in creating an AJAX form submit in a jQuery overlay. I am not sure how to approach this, do I just toss a partial view into the overlay?
I want to pass to the server the data in the form of a model so I can save it the the data base, I need to be able to create some sort of indication as to whether or not the request succeed. Can anyone guide me through this?
I am kinda new with AJax.

You could use jQuery UI Dialog. For example let's suppose that you have a view model:
public class MyViewModel
{
public string Foo { get; set; }
[Required]
public string Bar { get; set; }
}
and a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Modal()
{
return PartialView(new MyViewModel());
}
[HttpPost]
public ActionResult Modal(MyViewModel model)
{
if (!ModelState.IsValid)
{
return PartialView(model);
}
return Json(new { success = true });
}
}
In this example the Index action will serve the main view which will simply contain a link allowing to show the form as a modal dialog.
Here's the Index.cshtml view:
#Ajax.ActionLink(
"show form in modal",
"modal",
new AjaxOptions { OnSuccess = "onModalLoad" }
)
<div id="modal"></div>
and the Modal.cshtml partial which will contain the form:
#model MyViewModel
#using (Ajax.BeginForm(new AjaxOptions { OnSuccess = "onSubmitSuccess" }))
{
<div>
#Html.LabelFor(x => x.Foo)
#Html.EditorFor(x => x.Foo)
#Html.ValidationMessageFor(x => x.Foo)
</div>
<div>
#Html.LabelFor(x => x.Bar)
#Html.EditorFor(x => x.Bar)
#Html.ValidationMessageFor(x => x.Bar)
</div>
<button type="submit">OK</button>
}
The last step is to wire everything using javascript. Here are the 2 callbacks used:
var onModalLoad = function (result) {
$('#modal').html(result).dialog();
}
var onSubmitSuccess = function (result) {
if (!result.success) {
$('#modal').html(result);
} else {
alert('thanks for submitting');
$('#modal').dialog('close');
}
};
and that's it.
Don't forget to reference the jquery-ui and jquery.unobtrusive-ajax scripts to your page:
<script src="#Url.Content("~/Scripts/jquery-ui-1.8.11.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>

Related

MVC BeginCollectionItem

I'm having some issue getting my partial view BeginCollectionItem to save to the database. I have a form which has a dynamic number of "sections" that can be added to the page, and within each of these fields there is a text box where the user can enter the section name.
As far as I can tell the BeginCollectionItem within the partial view is working properly, however I cannot post the info to the database. In my other forms I have used a [bind()] to send the data to the database, is it possible to get this into a list and then post that via a bind?
I've included my code below:
The Model:
namespace project.Models.SetupViewModels
{
public class SOPTopTemplateBuilderViewModel
{
public List<Section> Section { get; set; }
}
public class Section {
public int SectionId { get; set; }
public string SectionText { get; set; }
public string TopTempId { get; set; }
}
}
cshtml:
#model IEnumerable<project.Models.SetupViewModels.Section>
#using (Html.BeginForm("SOPTopTemplateBuilder", "Setup", FormMethod.Post))
{
<div class="main-holder" id="theform">
#foreach(var item in Model)
{
#Html.Partial("_SectionCreator", item)
}
</div>
<button id="add" type="button">Add</button>
<div class="form-group submit-row">
<div class="col-12 float-to-right">
<input type="submit" class="btn btn-default" value="continue" />
</div>
</div>
}
#section Scripts {
<script>
$(document).ready(function () {
var url = '#Url.Action("AddSection")';
var form = $('form');
var recipients = $('#theform');
$('#add').click(function() {
$.post(url, function(response) {
recipients.append(response);
// Reparse the validator for client side validation
form.data('validator', null);
$.validator.unobtrusive.parse(form);
});
});
});
</script>
}
Partial View:
#model project.Models.SetupViewModels.Section
#using HtmlHelpers.BeginCollectionItemCore
#using (Html.BeginCollectionItem("Section"))
{
<div class="new-section">
<div>
<p>New Section</p>
#Html.HiddenFor(m => m.SectionId, new { #class="id" })
#Html.EditorFor(m => m.SectionText, new { #class = "form-control limit-form"})
</div>
</div>
}
Controller:
[HttpPost]
public PartialViewResult AddSection()
{
return PartialView("_SectionCreator", new Section());
}
[HttpGet]
public ActionResult SOPTopTemplateBuilder(){
List<Section> model = new List<Section>();
return View(model);
}
[HttpPost]
public ActionResult SOPTopTemplateBuilder(IEnumerable<Section> soptop)
{
if (ModelState.IsValid)
{}
return View(soptop);
}
Your use of Html.BeginCollectionItem("Section") perpends Section[xxxx] to the name attribute (where xxxx is a Guid) so that you generating inputs with
<input name="Section[xxxx].SectionId" .... />
which posts back to a model containing a collection property named Sections.
Since you already have a model with that property, you can change the POST method to
[HttpPost]
public ActionResult SOPTopTemplateBuilder(SOPTopTemplateBuilderViewModel soptop)
other options include
Using your existing POST method and omitting the "Section" prefix
using Html.BeginCollectionItem("") which will generate
name="[xxxx].SectionId"
Changing the POST method signature to public ActionResult
SOPTopTemplateBuilder(IEnumerable<Section> section) (where the
name of the parameter matches the name of the prefix)
Using a BindAttribute to 'strip' the prefix from the form values
public ActionResult SOPTopTemplateBuilder([Bind(Prefix = "Section")]IEnumerable<Section> soptop)
As a side note, your editing data, so you should always use a view model (say public class SectionViewModel) rather than using data models in your view. - What is ViewModel in MVC?

Validate JQuery UI modal form within another form in MVC 4

I have a form in MVC 4 which contains several fields and, depending on the value of a combo, I need to open a modal dialog form and load into that one 3 additional fields that will impact against the same entity that I'm creating/editing in the main form.
For this modal dialog I'm using the one from jQuery UI.
Now, what I need to do is to validate (Required) the fields within the modal dialog in order to allow the user to retain the entered values which will be submited later by the main form.
My problem is how to perform the validation of those 3 fields from within the modal form (because they wouldn't be able to submit the main form until dialog is closed).
Any hints or ideas?
Regards,
Cesar.
You could use AJAX to submit the form modal to the server. The modal form will have of course a separate view model associated with it. Let's exemplify:
Main view model:
public class MyViewModel
{
[DisplayName("select a value")]
public string SelectedValue { get; set; }
public IEnumerable<SelectListItem> Values { get; set; }
public string SomeOtherProperty { get; set; }
}
Modal dialog view model:
public class DialogViewModel
{
[Required]
public string Prop1 { get; set; }
[Required]
public string Prop2 { get; set; }
[Required]
public string Prop3 { get; set; }
}
Then you could have a controller containing 4 actions:
public class HomeController : Controller
{
// Renders the main form
public ActionResult Index()
{
var model = new MyViewModel
{
Values = new[]
{
new SelectListItem { Value = "1", Text = "item 1" },
new SelectListItem { Value = "2", Text = "item 2" },
new SelectListItem { Value = "3", Text = "item 3" },
}
};
return View(model);
}
// Processes the submission of the main form
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return Content(
string.Format(
"Thanks for filling out the form. You selected value: \"{0}\" and other property: \"{1}\"",
model.SelectedValue,
model.SomeOtherProperty
)
);
}
// Renders the partial view which will be shown in a modal
public ActionResult Modal(string selectedValue)
{
var model = new DialogViewModel
{
Prop1 = selectedValue
};
return PartialView(model);
}
// Processes the submission of the modal
[HttpPost]
public ActionResult Modal(DialogViewModel model)
{
if (ModelState.IsValid)
{
// validation of the modal view model succeeded =>
// we return a JSON result containing some precalculated value
return Json(new
{
value = string.Format("{0} - {1} - {2}", model.Prop1, model.Prop2, model.Prop3)
});
}
// Validation failed => we need to redisplay the modal form
// and give the user the possibility to fix his errors
return PartialView(model);
}
}
Next you could have a main view (~/Views/Home/Index.cshtml):
#model MyViewModel
#using (Html.BeginForm())
{
<div>
#Html.LabelFor(x => x.SelectedValue)
#Html.DropDownListFor(x => x.SelectedValue, Model.Values, new { id = "ddl" })
</div>
<div>
#Html.LabelFor(x => x.SomeOtherProperty)
#Html.TextBoxFor(x => x.SomeOtherProperty, new { id = "otherProperty" })
#Html.ActionLink(
"click here to open a modal and help you fill the value",
"Modal",
"Home",
null,
new { id = "showModal" }
)
</div>
<button type="submit">OK</button>
}
<div id="modal"></div>
and a partial view to contain the modal form (~/Views/Home/Modal.cshtml):
#model DialogViewModel
#using (Ajax.BeginForm(new AjaxOptions { OnSuccess = "handleModalSubmit" }))
{
<div>
#Html.LabelFor(x => x.Prop1)
#Html.EditorFor(x => x.Prop1)
#Html.ValidationMessageFor(x => x.Prop1)
</div>
<div>
#Html.LabelFor(x => x.Prop2)
#Html.EditorFor(x => x.Prop2)
#Html.ValidationMessageFor(x => x.Prop2)
</div>
<div>
#Html.LabelFor(x => x.Prop3)
#Html.EditorFor(x => x.Prop3)
#Html.ValidationMessageFor(x => x.Prop3)
</div>
<button type="submit">OK</button>
}
OK, now all that's left is write some javascript to make the whole thing alive. We start by making sure that we have included all the required scripts first:
<script src="#Url.Content("~/Scripts/jquery-1.7.1.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery-ui-1.8.20.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
and then write our own:
$(function () {
$('#showModal').click(function () {
$.ajax({
url: this.href,
type: 'GET',
cache: false,
data: { selectedValue: $('#ddl').val() },
success: function (result) {
$('#modal').html(result).dialog('open');
}
});
return false;
});
$('#modal').dialog({
autoOpen: false,
modal: true
});
});
function handleModalSubmit(result) {
if (result.value) {
// JSON returned => validation succeeded =>
// close the modal and update some property on the main form
$('#modal').dialog('close');
$('#otherProperty').val(result.value);
} else {
// validation failed => refresh the modal to display the errors
$('#modal').html(result);
}
}

update Model from UserControl - mvc

I have a problem: I Have created a UserControl A, A has its own controller in order to reuse Usercontrol actions in every view added, UserControl A expects a model UserControlModel, what I want to do is to update the model of the view that contains the UserControl A.
How can I pass value from the UserControl to main view or any view containg the user control in order to persist this value?
Some Code :
UserControl Controller
public class ColorBlockUserControlController : Controller
{
/// <summary>
/// Callback method for ColorBlockUserControl's AJAX form.
/// </summary>
/// <param name="model">ColorModel</param>
/// <returns>HTML string to be dispalyed within target DIV tag.</returns>
[HttpPost]
public ActionResult DrawColor(ColorModel model)
{
if (ModelState.IsValid)
{
return Content(ColorManager.GetGradientDiv(model.RGBColor, model.Width, model.Height));
}
else
{
return Redirect("/");
}
}
[AcceptVerbs(HttpVerbs.Post)]
public JsonResult Sumar(int Height, int Width)
{
return Json(true);
}
}
UserControl HTML :
<script type="text/javascript">
$(document).ready(function () {
var Valores = {
'Height': 30,
'Width': 30
};
$("#btnSumar").click(function () {
var targetDiv = "#TargetResult";
$.post(
'/ColorBlockUserControl/Sumar',
Valores,
function (data) {
if (data === true) {
debugger;
$(targetDiv).html('Sumado');
}
else {
alert('Failed to save the user');
}
},
'json'
);
});
});
</script>
#using (Ajax.BeginForm("DrawColor", "ColorBlockUserControl", new AjaxOptions { UpdateTargetId = "color-" + Model.Id }))
{
<div>RGB (example: FFAA00)</div>
<div class="formLine">
#Html.EditorFor(x => x.RGBColor)
</div>
#Html.ValidationMessageFor(x => x.RGBColor)
<div>Width</div>
<div class="formLine">
#Html.EditorFor(x => x.Width)
</div>
<div>Height</div>
<div class="formLine">
#Html.EditorFor(x => x.Height)
</div>
<div id="btnSumar" style="cursor:pointer;">This is a Test</div>
<p><input type="submit" value="Color Me!" /></p>
<div id="color-#Model.Id"><!-- Will be populated by AJAX method --></div>
}
View with UserControl:
#model MVCColorUserControl.Models.HomeModel
#using MVCColorUserControl.Models
#{
ViewBag.Title = "Color Demo";
}
<h2>#Model.WelcomeText</h2>
<p>
A Partial Control</p>
#Html.Partial("UserControls/ColorBlockUserControl", new ColorModel())
<hr />
#*<p>
A Partial Control that is initialized on Server-Side</p>
#{
Html.RenderAction("InitializeUserControl");
}*#
#Html.ActionLink("Ir a Test View", "Test")
#Html.ActionLink("Usando otro controller", "InNewController")
To answer your question about the FormCollection:
in your Controller you can do this:
[HttpPost]
public ActionResult GetMeSomeValues(FormCollection formCollection)
{
string text = formCollection.Get("Name of the input or whatever you have in your form");
//same goes for int values which you will need to convert from a string.
//Now if you want to pass the value to a Model simply create a new Model in here
//and add it.
var model = new Model();
model.Value = text;
return View(model);
}

How to display Jquery modal dialog after server side validation error

I am very new to JQuery and MVC. In my application i am opening a JQuery modal dialog on button click. I am rendering a partial view on this dialog using controller action method which is something like:
public ActionResult Create()
{
return PartialView("Create");
}
Partial view contains some textboxes and "create" button. On create button i am trying to save data in database. But before that i do some validation like if entered name already exist then show that message to user.
I did this using following code:
return PartialView("Create", model);
this is showing the message properly but it render only partial view in browser and modal dialog gets disappeared.
Please let me know how can i show the same modal dialog with error.
You will need to use AJAX submit of the form. Here's how to proceed. As always start with a view model which will represent the information for the dialog form:
public class MyViewModel
{
public string Foo { get; set; }
[Required(ErrorMessage = "The bar is absolutely required")]
public string Bar { get; set; }
}
then a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Create()
{
return PartialView("Create");
}
[HttpPost]
public ActionResult Create(MyViewModel model)
{
if (!ModelState.IsValid)
{
return PartialView(model);
}
// TODO: the model is valid => do some processing with it
// and return a JSON result confirming the success
return Json(new { success = true });
}
}
and a main view (~/Views/Home/Index.cshtml):
<script src="#Url.Content("~/Scripts/jquery-ui-1.8.11.js")" type="text/javascript"></script>
<script type="text/javascript">
// Remark: all this javascript could be placed in a separate js file
// to avoid cluttering the views
$(function () {
$('#modalLink').click(function () {
$('#dialog').load(this.href, function () {
$(this).dialog();
bindForm(this);
});
return false;
});
});
function bindForm(dialog) {
$('form', dialog).submit(function () {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
if (result.success) {
alert('thanks for submitting');
$('#dialog').dialog('close');
} else {
$('#dialog').html(result);
bindForm();
}
}
});
return false;
});
}
</script>
#Html.ActionLink("open modal", "create", null, null, new { id = "modalLink" })
<div id="dialog"></div>
and a partial view (~/Views/Home/Create.cshtml) which will contain the form shown in the modal:
#model MyViewModel
#using (Html.BeginForm())
{
<div>
#Html.LabelFor(x => x.Foo)
#Html.EditorFor(x => x.Foo)
#Html.ValidationMessageFor(x => x.Foo)
</div>
<div>
#Html.LabelFor(x => x.Bar)
#Html.EditorFor(x => x.Bar)
#Html.ValidationMessageFor(x => x.Bar)
</div>
<input type="submit" value="OK" />
}

how to get partialview data in controller

I am using three partialview on a single view, I have a submit button on clicking of which I want to send information to database, I have to retrieve data from all the partialview.
Can You please provide me correct information to do it.
Darin I m using L2S so when I drag my stored procedure, I get code some thing like this in
[global::System.Data.Linq.Mapping.FunctionAttribute(Name="SP_Name")]
public int SP_Name(
[global::System.Data.Linq.Mapping.ParameterAttribute(Name="EmployeeID", DbType="Int")] System.Nullable<int> EmployeeID
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), EmployeeID);
encounterID = ((System.Nullable<int>)(result.GetParameterValue(293)));
return ((int)(result.ReturnValue));
}
}
Updated
<script language="javascript" type="text/javascript">
$(function () {
$('#Form1').submit(function () {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (data) {
var message = data.Result;
$('#Result').html(message);
}
});
return false;
});
});
</script>
In my Controller I am using
public ActionResult Index(FormCollection frm)
{
My Code ---------------------
return Json(new { Result = "Success" });
}
When I return this I m getting a file in post back and it ask me to save it.
I have checked using flidder, in URL it shows me that the path as / only
where as If I fill any particular partialview It shows something like /Controller Name/Partialview
Can You help me with this problem
Well, sending data to a controller action is usually done by performing an HTTP request to this controller action. There are different ways of performing an HTTP request:
Use a <form> tag pointing to this action
Use AJAX
So if you go with the first approach you could have a single <form> wrapping all the partials which would have multiple submit buttons (with different names). Then when you click on one submit buttons all the input fields will be sent to the controller action and then inside the controller action you could process the data based on which submit button was clicked.
If you use the second option, well, then simply harvest the values you need to be sent uipon button click and send them along the AJAX request.
UPDATE:
As requested in the comments section here's how the first technique could be put into action. It uses two partials instead of three but it could be easily extrapolated.
As always you start by defining a view model which will represent the data you would like to work with on this particular view:
public class MyViewModel
{
public Partial1ViewModel Model1 { get; set; }
public Partial2ViewModel Model2 { get; set; }
}
public class Partial1ViewModel
{
public string Foo { get; set; }
}
public class Partial2ViewModel
{
public string Bar { get; set; }
}
Then a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
Model1 = new Partial1ViewModel { Foo = "foo" },
Model2 = new Partial2ViewModel { Bar = "bar" },
};
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// Here you have access to model.Model1.Foo and model.Model2.Bar =>
var button = "";
if (!string.IsNullOrEmpty(Request["submit1"]))
{
// submit1 button was used
button = "submit1";
}
else if (!string.IsNullOrEmpty(Request["submit2"]))
{
// submit2 button was used
button = "submit2";
}
var result = string.Format("thanks for submitting using {0}", button);
return Content(result, "text/plain");
}
}
and then a main view (~/Views/Home/Index.cshtml):
#model MyViewModel
#using (Html.BeginForm())
{
#Html.EditorFor(x => x.Model1)
#Html.EditorFor(x => x.Model2)
}
and the two corresponding editor templates (or partials if you will):
~/Views/Home/EditorTemplates/Partial1ViewModel.cshtml:
#model Partial1ViewModel
<h2>Partial 1</h2>
<div>
#Html.LabelFor(x => x.Foo)
#Html.EditorFor(x => x.Foo)
<input type="submit" value="Submit me!" name="submit1" />
</div>
~/Views/Home/EditorTemplates/Partial2ViewModel.cshtml:
#model Partial2ViewModel
<h2>Partial 2</h2>
<div>
#Html.LabelFor(x => x.Bar)
#Html.EditorFor(x => x.Bar)
<input type="submit" value="Submit me!" name="submit2" />
</div>

Resources