I did similar to authors and books with many relationships. The main idea is to create a JSON object from a view that contains all the authors inside it and is subordinate to the controller. I also used jQuery UI TagIt to allow the user to add / remove authors associated with the book. When the user clicks the Save Book button, the script builds a JSON object that mimics the Book object.
Below is the code. Make sure you add "json2.js" and "tagit.js" to the project before trying this code.
Browse Models:
public class BookViewModel { public string Title { get; set; } public int BookId { get; set; } public int IsAvail { get; set; } public string CallNumber { get; set; } //Assiged authors public List<AuthorViewModel> Authors { get; set; } //available authors public List<AuthorViewModel> AuthorOptions { get; set; } } public class AuthorViewModel { public int AuthorId { get; set; } public string FirstName { get; set; } }
Code for the book /Edit.chtml:
@using System.Web.Script.Serialization @model eLibrary.Models.BookViewModel @{ ViewBag.Title = "Edit"; } <h2>Edit</h2> <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> @*This is for JSON*@ <script src="../../Scripts/json2.js" type="text/javascript"></script> <script src="../../Scripts/tagit.js" type="text/javascript"></script> @*These are for styling Control*@ <link href="../../Content/themes/base/jquery.ui.all.css" rel="stylesheet" type="text/css" /> <script type="text/javascript"> //This function is used for sending data(JSON Data) to BookController function BookSave() { // Step 1: Read View Data and Create JSON Object var author = { "AuthorId": "", "FirstName": "" }; // Creating book Json Object var book = { "BookId": "", "Title": "", "IsAvail": "", "CallNumber":"", "authors": []}; // Set Boook Value book.BookId = $("#BookId").val(); book.Title = $("#Title").val(); book.IsAvail = $("#IsAvail").val(); book.CallNumber = $("#CallNumber").val() ; var tags = $('#authors').tagit('tags'); for (var i in tags) { author.AuthorId = tags[i].value; author.FirstName = tags[i].label; book.authors.push(author ); author = { "AuthorId": "", "FirstName": "" }; } // Step 1: Ends Here // Set 2: Ajax Post // Here i have used ajax post for saving/updating information $.ajax({ url: '/Book/Edit', data: JSON.stringify(book), type: 'POST', contentType: 'application/json;', dataType: 'json', success: function (result) { if (result.Success == "1") { window.location.href = "/Book/Edit"; } else { alert(result.ex); } } }); } </script> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Book Details</legend> @Html.HiddenFor(model => model.BookId) <div class="editor-label"> @Html.LabelFor(model => model.Title) </div> <div class="editor-field"> @Html.EditorFor(model => model.Title) @Html.ValidationMessageFor(model => model.Title) </div> <div class="editor-label"> @Html.LabelFor(model => model.IsAvail) </div> @Html.EditorFor(model => model.IsAvail) @Html.ValidationMessageFor(model => model.IsAvail) @Html.EditorFor(model => model.CallNumber); </fieldset> @Html.Partial("AuthorsByBook", Model.Authors, new ViewDataDictionary { { "mode", "EDIT" } }) <input type="button" value="Book Save" onclick="BookSave()" /> }
Code for the book /AuthorsByBook.chtml
@model IEnumerable< eLibrary.Models.AuthorViewModel> <link href="../../Content/tagit-awesome-blue.css" rel="stylesheet" type="text/css" /> <div class="box"> <ul id="authors" name="authors"> </ul> </div> <script type="text/javascript"> //Load authors in the javascript variable $(function () { var initialAuthorList=[]; @if(ViewData["mode"]=="EDIT") { foreach (var category in Model) { <text> initialAuthorList.push({label: "@category.FirstName", value: @category.AuthorId }); </text> } } $('#authors').tagit({tagSource: function (request, response) { $.ajax({ url: "/Author/SearchAuthor", type: "POST", dataType: "json", data: { searchText: request.term, maxResults: 10 }, success: function (data) { response($.map(data, function (item) { return { label: item.FirstName, value: item.AuthorId } })) } }) }, initialTags:initialAuthorList,minLength:3,allowNewTags:false,sortable:true,delay:400}); }); </script>
Code for BookController.cs
public ActionResult Edit(int id) {
Code for the SearchAuthor method in AuthorController.cs
public JsonResult SearchAuthor(string searchText, int? maxResults) { IEnumerable<Author> query = db.Authors; searchText = searchText.ToLower(); query = query.Where(c => c.FirstName.ToLower().Contains(searchText)); if ((maxResults ?? 0) == 0) { return Json(query.ToList()); } else { return Json(query.Take((int)maxResults).ToList()); } }