Solution -
Uninstall .Net 4.5
Wait for the uninstallation to finish.
Finally to install Release candidates of .NET framework 4.5 and Visual studio 2012 again, Go to - http://www.microsoft.com/visualstudio/11/en-us
“I blogged on this topic in September 2010 and received a few mail about showing how to add new entities (as opposed to update) and also an implementation of this in MVC 3.0 using Razor. While the concepts and explanation in the previous blogs still hold correct, here’s an implementation using MVC 3.0 and Razor with some improvements. My apologies for not posting this blog as sooner; also really appreciate your comments & mails.”The requirement I was given was, to show the form to Add/Edit Products and the details view, in a jQuery UI dialog. Also these dialogs were to be shown at many places all across the application. I certainly did not want to render views by default, everywhere the dialog was to be shown. So I created extenders which would have scripts to load the view when needed.
public class Product {
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Description { get; set; }
}
And a product’s service for CRUD operationspublic class ProductService {
private readonly string ProductsInSession = "ProductsInSession";
/// <summary>
/// Some Dummy products
/// </summary>
private List<Product> _initialData {
get {
return new List<Product> {
new Product() {
Id = 1,
Name = "My New Product",
Description = "This is a cool way to extend the jQuery UI dialog!" },
new Product() {
Id = 2,
Name = "My New B",
Description = "Details for Product Beee!" },
new Product() {
Id = 3,
Name = "My New C",
Description = "Details for Product Ceee!" },
new Product() {
Id = 4,
Name = "My New D",
Description = "Details for Product Deee!" },
new Product() {
Id = 5,
Name = "My New E",
Description = "Details for Product Eeee!" }
};
}
}
/// <summary>
/// Get and Set List of products from and to the session
/// </summary>
private List<Product> _Products {
get {
List<Product> data = null;
if (HttpContext.Current.Session[ProductsInSession] == null) {
data = _initialData;
HttpContext.Current.Session[ProductsInSession] = data;
}
else {
data = HttpContext.Current.Session[ProductsInSession] as List<Product>;
}
return data;
}
set {
HttpContext.Current.Session[ProductsInSession] = value;
}
}
public List<Product> GetProducts() {
return _Products;
}
public Product GetProduct(int id) {
return _Products.Single(p => p.Id == id);
}
public void AddUpdateProduct(Product product) {
// Could definitely do better that this but the demo is about the dialog
var products = _Products;
if (product.Id == 0) {
product.Id = _Products.Max(p => p.Id) + 1;
products.Add(product);
}
else {
products.Single(p => p.Id == product.Id).Name = product.Name;
products.Single(p => p.Id == product.Id).Description = product.Description;
}
//Save back to session
_Products = products;
}
}
public ActionResult Details(int id) {
return View(_productService.GetProduct(id));
}
The View - @model DialogExtender_MVC3.Models.Product
<fieldset>
<legend>Product</legend>
<div class="display-label">Name</div>
<div class="display-field">
@Html.DisplayFor(model => model.Name)
</div>
<div class="display-label">Description</div>
<div class="display-field">
@Html.DisplayFor(model => model.Description)
</div>
</fieldset>
The and Extender with the script to load the data (I’m calling it ProductDetailsDialog and putting it in the shared folder)<div id="ProductDetailsDialogDiv" title="Product details" style="display: none;">
</div>
<script type="text/javascript">
function openProductDetailsDialog(id) {
$.ajax({
type: "GET",
url: encodeURI('@Url.Action("Details", "Product")' + "?id=" + id),
cache: false,
dataType: 'html',
error: function (XMLHttpRequest, textStatus, errorThrown) {
$("#ProductDetailsDialogDiv").html(errorThrown);
},
success: function (data, textStatus, XMLHttpRequest) {
$("#ProductDetailsDialogDiv").html(data);
},
complete: function (XMLHttpRequest, textStatus) {
$('#ProductDetailsDialogDiv').dialog({
modal: true,
width: "300px",
close: function (event, ui) { $("#ProductDetailsDialogDiv").html(""); },
buttons: {
"Ok": function () { $(this).dialog("close"); }
}
});
}
});
}
</script>
The openProductDetailsDialog received the product Id and calls the Details action and load whet ever it gets in the DIV ProductDetailsDialogDiv. and finally show the DIV in a dialog. The DIV is cleared when the dialog is closed. It’s always a good practice to use $.ajax (as opposed to $.get() or $.load()) as .ajax gives us handlers for error enabling better control for debugging and maintenance.<!--The link that will show the dialog-->
<a href="javascript:openProductDetailsDialog(1);">Product detail</a>
<!--The Dialog extenders will sit here quietly unless asked to do something-->
@Html.Partial("ProductDetailsDialog")
"E-d-i-t---S-u-c-c-e-s-s-f-u-l"and placed it in the shared folder.
public class ProductViewModel {
public Product Product { get; set; }
}
Here’s the AddEditAction from ProductController - public ActionResult AddEdit(int? id) {
if (id.HasValue && id.Value != 0) {
//Edit an existing Product
return View(new ProductViewModel { Product = _productService.GetProduct(id.Value) });
}
else {
//Add a new Product
return View(new ProductViewModel { Product = new Product { Id = 0 } });
}
}
[HttpPost]
public ActionResult AddEdit(ProductViewModel vm) {
if (ModelState.IsValid) {
_productService.AddUpdateProduct(vm.Product);
return PartialView("AddEditSuccess");
}
return View(vm);
}
Note that we identify whether it is a add or edit based on the availability of the primary key. A similar logic sits in the Product service too which is why the same action and service method is used to achieve both adding and editing products.@model DialogExtender_MVC3.Models.ProductViewModel
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Ajax.BeginForm(new AjaxOptions { OnComplete = "addEditProductComplete" })) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Product</legend>
@Html.HiddenFor(model => model.Product.Id)
<div class="editor-label">
@Html.LabelFor(model => model.Product.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Product.Name)
@Html.ValidationMessageFor(model => model.Product.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Product.Description)
</div>
<div class="editor-field">
@Html.TextAreaFor(model => model.Product.Description)
@Html.ValidationMessageFor(model => model.Product.Description)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
For the Ajax options and client validations to work we need the scripts – jquery.unobtrusive-ajax, jquery.validate, jquery.validate.unobtrusive. The Ajax options in the form will call the JavaScript method – addEditProductComplete after the response from the form post is received. This method checks if the form was successfully posted or not. If not it keep the dialog in place and updated the contents of the dialog.<div id="ProductEditDialogDiv" title="Product" style="display: none;">
</div>
<script type="text/javascript">
function openProductEditDialog(id) {
$("#ProductDetailsDialogDiv").html("");
$.ajax({
type: "GET",
url: encodeURI('@Url.Action("AddEdit", "Product")' + "?id=" + id),
cache: false,
dataType: 'html',
error: function (XMLHttpRequest, textStatus, errorThrown) {
$("#ProductEditDialogDiv").html(XMLHttpRequest.responseText);
},
success: function (data, textStatus, XMLHttpRequest) {
$("#ProductEditDialogDiv").html(data);
},
complete: function (XMLHttpRequest, textStatus) {
$('#ProductEditDialogDiv').dialog({
width: '500px',
modal: true
});
}
});
}
function addEditProductComplete(xmlHttpRequest, textStatus) {
var data = xmlHttpRequest.responseText;
if (data.indexOf("E-d-i-t---S-u-c-c-e-s-s-f-u-l", 0) >= 0) {
$("#ProductDetailsDialogDiv").html("");
$('#ProductEditDialogDiv').dialog('close');
// call reload / refresh or any other post edit action.
}
else {
$('#ProductEditDialogDiv').html(data);
$("#EditProductButtons").hide();
}
}
</script>
And just like the non-form dialogs, here’s the two lines of markup that will show your dialog anywhere you want - <a href="javascript:openProductEditDialog(1);">Edit Product</a>
@Html.Partial("ProductAddEditDialog")
To provide the link to add, all we need is to pass a 0 or null or blank to the openProductEditDialog method - <a href="javascript:openProductEditDialog('');">Add Product</a>
@Html.Partial("ProductAddEditDialog")
A Demo Solution for the post can be downloaded here.
It was a privilege to present the second final session for ASP.NET MVC 3.0 @ SDC meetup, covering the design considerations around MVC.
Many thanks to the event hosts and as always, the audience interaction in the end was the best part.
Following are the slides and solution from the presentation -
Download slides here – | – Download the demo solution here.
Here are some if the links that can up in the presentation during discussion -
Also, I strongly recommend taking a look at the awesome open source project called “ASP.NET MVC Project Awesome” - http://awesome.codeplex.com/ for great jQuery Ajax helpers (controls).
Feel free to mail/post me any question that you might have.