Autocomplete with a foreign key using jQuery - c#

I have an application dealing with Donations from Houses for a Church. I would like it so when a donation comes in to the Church, someone will type in a textbox the address but as there will be a lot of homes, I want an autocomplete box to make it easier.
Here are my models:
public class Donation
{
[Key]
public int DonationId { get; set; }
public string TypeOfDonation { get; set; }
public decimal Amount { get; set; }
[ForeignKey("Church")]
public int ChurchId { get; set; }
[ForeignKey("House")]
public int HouseId{ get; set; }
public virtual Church Church { get; set; }
public virtual House House { get; set; }
}
public class House
{
[Key]
public int HouseNumber { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressLine3 { get; set; }
}
I think I am doing something wrong in my controller method:
public JsonResult GetAddress(string term)
{
var items = db.Houses
.Where(x => x.AddressLine1.Contains(term))
.Select(x => new { Label = x.HouseNumber, Value = x.AddressLine1 })
.Take(10);
return Json(items, JsonRequestBehavior.AllowGet);
}
Or my jQuery:
<div class="form-group">
#Html.LabelFor(model => model.House.HouseNumber, "Address", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.House.HouseNumber, new { id = "HouseNumber" })
#Html.ValidationMessageFor(model => model.House.HouseNumber, "", new { #class = "text-danger" })
</div>
</div>
$('#Address').autocomplete({
source: function(request, response) {
$.get('#Url.Action("GetAddress", "DonationsController")',
{ term: request.term },
function(data) {
response($.map(data, function (item) {
return {
label: item.Label,
value: item.Value
}
}));
});
},
minLength: 2
})
Can anyone point me in the right direction?
EDIT:

Your screenshot shows the problem.
When creating URLs in MVC, you should not include the word "Controller", even though the controller class is called DonationsController
Change it to
$.get('#Url.Action("GetAddress", "Donations")',

I just created an autocomplete with JQuery UI this example could help.
jQuery
$("#txtCode").autocomplete({
source: function (request, response) {
$.ajax({
url: '#Url.Action("ProductAutocompleteByCode", "Products")',
dataType: 'json',
data: {
codigo: $("#txtCode").val()
},
success: function (data) {
var parsedData = $.map(data, function (n, i) {
return { label: n.Code, value: n.Id };
});
response(parsedData);
}
});
}
});
Controller
public JsonResult ProductAutocompleteByCode(string code)
{
var products = Json(db.Products.Where(p => p.code.Contains(code)).Select(p => new ProductDTO { Id = p.id, Code = p.code, Name = p.name, Price= p.price }));
return Json(products.Data, JsonRequestBehavior.AllowGet);
}

Related

Pull data that has just been stored into a database using only one button

I'm creating my very own marketing funnel for my website. How do I get the id of the record I've just saved onto my ajax call without having to use any additional buttons or user triggered methods.
I have created a modal which shows after a user registers their details onto our system as way of the system to interact with the user. Anyway, from this stage onwards, there should be multiple questions being asked to the user about their preferences and the products they want. In my head this just means that I should be updating that user's information the minute that first modal pops up.
Ajax call for saving user info:
$("#btn-save-client").click(function () {
var clientData = {
id: $('#id').val(),
firstName: $('#FirstName').val(),
lastName: $('#LastName').val(),
cellNo: $('#CellNo').val(),
emailAddress: $('#EmailAddress').val(),
country: $('#Country').val()
};
$.ajax({
type: "POST",
url: '/Home/SaveClientData',
data: JSON.stringify(clientData), //Serialises the form's elements.
contentType: "application/json",
dataType: "json",
beforeSend: function () {
$("#contactForm").append('<div class="overlay"><span class="fa fa-refresh fa-spin"></span></div>');
},
success: function (data) {
$("#contactForm .overlay").remove();
$("#contactForm")[0];
LoadFirstFunnel(data.id);
},
error: function (error) {
console.log(error);
console.log(error.responseText);
alert(error.responseText);
},
completed: function () {
$("#contactForm .overlay").remove();
}
});
});
C# method for saving in HomeController.cs:
[System.Web.Mvc.HttpPost]
public ActionResult SaveClientData([FromBody]ClientData clientDataModel)
{
if (clientDataModel == null) return new JsonResult(new {id = null, error = "Please fill in all the details required."});
var _addClientData = new HomeTransactions(new PetaConnection().db()).SaveClient(clientDataModel);
return new JsonResult(new { id = _addClientData.id, error = null });
}
From my HomeController.cs, my code goes to the following code to save data into the database and then return values:
public string SaveClient(ClientData clientDataModel)
{
try
{
ClientInfo clientModel = new ClientInfo();
ClientCompanyInfo clientCompanyModel = new ClientCompanyInfo();
if (clientModel.id == 0 && clientCompanyModel.id == 0)
{
clientCompanyModel.CompanyName = "Default Inc.";
_connect.Save(clientCompanyModel);
Random rand = new Random();
int randomNo = rand.Next(10000, 20000);
string referenceNo = "MTP-" + randomNo;
clientModel.ReferenceNo = referenceNo;
clientModel.FirstName = clientDataModel.FirstName;
clientModel.LastName = clientDataModel.LastName;
clientModel.CellNo = clientDataModel.CellNo;
clientModel.EmailAddress = clientDataModel.EmailAddress;
clientModel.Country = clientDataModel.Country;
clientModel.companyId = clientCompanyModel.id;
clientModel.Active = 1;
clientModel.DateAdded = DateTime.Now;
clientModel.DateUpdated = DateTime.Now;
_connect.Save(clientModel);
clientDataModel.id = clientModel.id;
}
return clientModel.id.ToString();
}
catch (Exception ex)
{
throw;
}
}
Ajax call for LoadFirstFunnel mentioned in the previous Ajax call.
function LoadFirstFunnel(clientId) {
$.ajax({
type: "POST",
url: '/Home/_OpenFirstPanelModal',
data: { clientId: clientId }, // serializes the form's elements.
beforeSend: function (data) {
$("#MessageBoxModal").append('<div class="overlay"><span class="fa fa-refresh fa-spin"></span></div>');
},
success: function (data) {
id = data.id;
$("#MessageBoxModal .overlay").remove();
$('#MessageBoxModal .modal-title').html('Your information was successfully added.');
$('#MessageBoxModal .btn-style-one').attr('id', 'btn-notification');
$('#MessageBoxModal .btn-style-one').attr('id', 'btn-deny-note');
$('#MessageBoxModal .btn-style-one').attr('data-id', '');
$('#MessageBoxModal #regNote').html(data);
$('#MessageBoxModal .modal-dialog').css('width', '');
$('#MessageBoxModal').modal({
backdrop: 'static',
keyboard: false,
show: true
});
},
error: function (xhr, status, error) {
$("#MessageBoxModal .overlay").remove();
alert(error);
},
completed: function (data) {
$("#MessageBoxModal .overlay").remove();
}
});
};
C# call on HomeController.cs which responds to the LoadFirstFunnel ajax call:
public ActionResult _OpenFirstPanelModal(int clientId)
{
ClientInfo _openClientInfoModel = new ClientInfo();
_openClientInfoModel = new HomeTransactions(new PetaConnection().db()).OpenClientInfo(clientId);
return PartialView("_OpenFirstPanelModal", _openClientInfoModel);
}
Modal.cshtml that pops up after registration:
#model MotseThePowerHouse_Website.Models.ClientInfo
<div class="row">
<input type="hidden" value="#Model.id" name="id" />
<div class="text-muted text-center col-sm-12" id="msgDisplay">
<h4>Some text here...</h4>
<h4>Some text here...</h4>
</div>
</div>
<div class="row">
<a id="btn-notification" data-id="#Model.id" class="theme-btn btn-style-one">Yes, notify me</a>
<a id="btn-deny-note" data-id="#Model.id" class="theme-btn btn-style-one">No, thank you</a>
</div>
I know this is all jumbled and it is not working although the logic could make sense, I want to know of other methods out there which can be used by me to deliver this funnel output.
Below is my ClientInfo Model:
using System;
namespace MotseThePowerHouse_Website.Models
{
public class ClientInfo
{
public int id { get; set; }
public string ReferenceNo { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UnitNo { get; set; }
public string UnitStreetName { get; set; }
public string ComplexNo { get; set; }
public string ComplexName { get; set; }
public string StreetName { get; set; }
public string Suburb { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Province { get; set; }
public string Country { get; set; }
public string CellNo { get; set; }
public string TelephoneNo { get; set; }
public string EmailAddress { get; set; }
public string Website { get; set; }
public string BlogNotification { get; set; }
public int companyId { get; set; }
public string PositionHeld { get; set; }
public string OfficeLocation { get; set; }
public DateTime DateAdded { get; set; }
public string UpdatedBy { get; set; }
public DateTime DateUpdated { get; set; }
public int Active { get; set; }
}
}
Create a class which will represent your request body:
public class ClientData
{
public string FirstName {get;set;}
public string LastName {get;set;}
public string CellNo {get;set;}
public string EmailAddress {get;set;}
public string Country {get;set;}
}
Modify your SaveClientData method to the following:
[HttpPost]
public ActionResult SaveClientData([FromBody]ClientData clientData)
{
if (clientDataModel == null) return Json(new {error = "Please fill in all the details required."}, JsonRequestBehavior.AllowGet);
var _addClientData = new HomeTransactions(new PetaConnection().db()).SaveClient(clientDataModel);
return Json(new {id = _addClientData}, JsonRequestBehavior.AllowGet);
}
and your JavaScript code:
var clientData = {
firstName : $('#FirstName').val(),
lastName: $('#LastName').val(),
cellNo: $('#CellNo').val(),
emailAddress: $('#EmailAddress').val(),
country: $('#Country').val()
}
$.ajax({
...
data: JSON.stringify(clientData),
contentType:"application/json",
success: function(data){
if(data.error) { return;}
$("#contactForm .overlay").remove();
$("#contactForm")[0];
LoadFirstFunnel(data.id);
}
});
and for the second part you have to modify the parameter name from id to clientId:
public ActionResult _OpenFirstPanelModal(int clientId)

MVC ASP.NET Dropdown onchange load another dropdown

I have 2 dropdownlist on a page.When i select some value from first dropdown list then in second dropdownlist all the values should load according to the value selected (Subcategories loaded according to Categories). Here is what I tried but it doesn't work:
Model
public class Product
{ ...
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
public int SubCategoryId { get; set; }
public virtual SubCategory SubCategory { get; set; }
public IEnumerable<SelectListItem> SubCategories { get; set; }
...
}
View
<label>Select Category</label>
#Html.DropDownListFor(m => m.CategoryId, new SelectList(Model.Categories, "Value", "Text"), "Select Category", new { id = "catList", #class = "form-control" })
<label>Selectat Subcategory</label>
#Html.DropDownListFor(m => m.SubCategoryId, new SelectList(Enumerable.Empty<SelectListItem>(), "Value", "Text"), "Selectat Subcategory", new { id = "subcatList", #class = "form-control" })
<script type="text/javascript">
$(document).ready(function () {
$("#catList").change(function () {
var cID = $(this).val();
$.getJSON("../Product/New/LoadSubCategories", { catId: cID },
function (data) {
var select = $("#subcatList");
select.empty();
select.append($('<option/>', {
value: 0,
text: "Selecteaza o subcategorie"
}));
$.each(data, function (index, itemData) {
select.append($('<option/>', {
value: itemData.Value,
text: itemData.Text
}));
});
});
});
});
</script>
Controller
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult LoadSubCategories(string catId)
{
var subCatList = GetAllSubCategories(Convert.ToInt32(catId));
return Json(subCatList, JsonRequestBehavior.AllowGet);
}
[NonAction]
public IEnumerable<SelectListItem> GetAllSubCategories(int selectedCatId)
{
//generate empty list
var selectList = new List<SelectListItem>();
var subcategories = from sbcat in db.SubCategories
where sbcat.CategoryId == selectedCatId
select sbcat;
foreach (var subcategory in subcategories)
{
//add elements in dropdown
selectList.Add(new SelectListItem
{
Value = subcategory.SubCategoryId.ToString(),
Text = subcategory.SubCategoryName.ToString()
});
}
return selectList;
}
you need to change your getJson to Ajax method
here is the ajax sample code
$.ajax({
type: "GET",
url: '/Product/New/LoadSubCategories',
data: {catId: cID},
success: successFunc,
error: errorFunc
});
function successFunc(data) {
var select = $("#subcatList");
select.empty();
select.append($('<option/>', {
value: 0,
text: "Selecteaza o subcategorie"
}));
$.each(data, function (index, itemData) {
select.append($('<option/>', {
value: itemData.Value,
text: itemData.Text
}));
});
}
function errorFunc() {
alert('error');
}
});
this ajax code you need to write on dropdown change and in success of ajax call, you need to write the code you want to do when dropdown's value changes and data received successfully
For change the second Drop down value according to first drop down value, you need to write an Onchange event, then only it will get change.. please check below stackoverflow question an answer it will be help full to you
Click here

How can I make a cascading dropdown list?

I have Companies and Vacancies tables.
Company has n number of Vacancies. I need to make two dropdown lists.
In one it will be Company, when I select it, there will be Vacancies related to this company.
Here is model of Companies
public Company()
{
this.Clients = new HashSet<Client>();
this.Vacancies = new HashSet<Vacancy>();
}
[Key]
public int CompanyID { get; set; }
public string CompanyName { get; set; }
public string Id { get; set; }
public virtual AspNetUser AspNetUser { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Client> Clients { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Vacancy> Vacancies { get; set; }
}
Here is model for Vacancies
public partial class Vacancy
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Vacancy()
{
this.Interviews = new HashSet<Interview>();
}
[Key]
public int VacancyId { get; set; }
public string VacancyName { get; set; }
public Nullable<int> CompanyID { get; set; }
public virtual Company Company { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Interview> Interviews { get; set; }
Here is controller where I need to do this
[HttpGet]
public ActionResult WelcomeScreen()
{
// Формируем список команд для передачи в представление
SelectList teams = new SelectList(db.Vacancy, "VacancyId", "VacancyName");
ViewBag.Teams = teams;
return View();
}
//Заносим инфу о вакансии в таблицу
[HttpPost]
public ActionResult WelcomeScreen(Interview interview)
{
db.Interview.Add(interview);
db.SaveChanges();
//Int32 id = interview.Interview_Id;
//TempData["id"] = id;
return RedirectToAction("Index", "Questions", new { id = interview.Interview_Id });
}
How I need to make Cascade Dropdown list?
UPDATE
I try solution
Here is my controller (Questions controller)
[HttpGet]
public ActionResult WelcomeScreen()
{
// Формируем список команд для передачи в представление
//SelectList teams = new SelectList(db.Vacancy, "VacancyId", "VacancyName");
//ViewBag.Teams = teams;
ViewBag.Companies = new SelectList(db.Companies, "CompanyID", "CompanyName");
return View();
}
//Заносим инфу о вакансии в таблицу
[HttpPost]
public ActionResult WelcomeScreen(Interview interview)
{
db.Interview.Add(interview);
db.SaveChanges();
//Int32 id = interview.Interview_Id;
//TempData["id"] = id;
return RedirectToAction("Index", "Questions", new { id = interview.Interview_Id });
}
public ActionResult Vacancies(int companyId)
{
var items = db.Vacancy
.Where(x => x.CompanyID == companyId)
.Select(x => new SelectListItem
{
Value = x.VacancyId.ToString(),
Text = x.VacancyName
})
.ToList();
return Json(items, JsonRequestBehavior.AllowGet);
}
Here is script
<script>
$(function () {
$("#Company").change(function (e) {
var $vacancy = $("#vacancy");
var url = $vacancy.data("url") + '?companyId=' + $(this).val();
$.getJSON(url, function (items) {
$.each(items, function (a, b) {
$vacancy.append('<option value="' + b.Value + '">' + b.Text + '</option>');
});
});
});
});
</script>
And here is View
<div class="right-grid-in-grid">
<div style="margin-left:20px;">
#Html.DropDownList("Company", ViewBag.Companies as SelectList, new { #class = "greeting"})
#Html.ValidationMessageFor(model => model.VacancyId, "", new { #class = "text-danger" })
</div>
<div style="margin-left:20px;">
<select name="id" id="vacancy" data-url="#Url.Action("Vacancies","Questions")" class="greeting"/>
</div>
</div>
But AJAX not works.
The idea of cascading dropdown is, When you load the page, you load the dropdown content for the first SELECT element. The second SELECT element will be an empty one. When user selects an option from the first dropdown, send that to the server which returns the content needed to build the second dropdown.
So in the GET action of your page, get the data needed to render the first dropdown.
public ActionResult Welcome()
{
ViewBag.Companies = new SelectList(db.Companies, "CompanyID", "CompanyName");
return View();
}
Now in the view, you can use the DropDownList helper method to render the SELECT element with the data we set to the ViewBag.Companies. We will also add our second dropdown as well.
#Html.DropDownList("Company", ViewBag.Companies as SelectList)
<select name="id" id="vacancy" data-url="#Url.Action("Vacancies","Home")">
Now we will use some ajax code(using jQuery in this example) to get the content for the second dropdown. Register an event handler for the change event of the first dropdown, get the selected value, make an ajax call to the Vacancies action method which returns the data needed to build the second dropdown in JSON format. Use this JSON data to build the second dropdown in javascript.
$(function(){
$("#Company").change(function (e) {
var $vacancy = $("#vacancy");
var url = $vacancy.data("url")+'?companyId='+$(this).val();
$.getJSON(url, function (items) {
$.each(items, function (a, b) {
$vacancy.append('<option value="' + b.Value + '">' + b.Text + '</option>');
});
});
});
});
Now the last part is, implementing the Vacancies method.
public ActionResult Vacancies(int companyId)
{
var items = db.Vacancies
.Where(x=>x.CompanyID==comapnyId)
.Select(x => new SelectListItem { Value = x.VacancyId.ToString(),
Text = x.VacancyName })
.ToList();
return Json(items, JsonRequestBehavior.AllowGet);
}
Assuming db is your DbContext class object.
Ajax is not necessary for implementing cascading dropdowns. You can post the form with the selected companyId and the action method can return the same with second dropdown filled. But people usually use ajax to give a nice user experience

three level cascading drop down list

I am a beginner in programming being stuck the last 2 days on that and i am hopping on your help :)
I am building an mvc 4 app and I have a partial view with a list of departments and when you choose the department you can see the item types for this specific department in a drop down list in Browse view.
What I am trying to make is one more dropdown list in Browse view that will show the items according to the selected department and item types.
So this is my code :
View :
#using (Html.BeginForm("Browse", "Bookings", FormMethod.Post, new { id = "TypeItemFormID", data_itemsListAction = #Url.Action("ItemsList") }))
{
<fieldset>
<legend> Type/Item</legend>
#Html.DropDownList("department", ViewBag.ItemTypesList as SelectList, "Select a Type", new {id="ItemTypeID"})
<div id="ItemsDivId">
<label for="Items">Items </label>
<select id="ItemsID" name="Items"></select>
</div>
<p>
<input type ="submit" value="Submit" id="SubmitID" />
</p>
</fieldset>
}
<script src ="#Url.Content("~/Scripts/typeItems.js")"></script>
The controller :
public class BookingsController : Controller
{
private BookingSystemEntities db = new BookingSystemEntities();
//
// GET: /Bookings/
public ActionResult Index()
{
ViewBag.Message = "Select your Department";
var departments = db.Departments.ToList();
return View(departments);
}
public ActionResult Browse(string department, string ID)
{
ViewBag.Message = "Browse for Equipment";
var departments = db.Departments.Include("Items").Single(i => i.DepartmentName == department);
ViewBag.ItemTypesList = GetItemTypeSelectList(department);
return View();
}
public ActionResult Details(int id)
{
var item = db.Items.Find(id);
return View(item);
}
//
// GET: /Home/DepartmentMenu
[ChildActionOnly]
public ActionResult DepartmentMenu()
{
var departments = db.Departments.ToList();
return PartialView(departments);
}
public SelectList GetItemTypeSelectList(string department)
{
var departments = db.Departments.Include("Items").Single(i => i.DepartmentName == department);
List<SelectListItem> listItemTypes = new List<SelectListItem>();
foreach (var item in departments.Items.Select(s => s.ItemType.ItemTypeName).Distinct())
{
listItemTypes.Add(new SelectListItem
{
Text = item,
Value = item,
}
);
}
return new SelectList(listItemTypes.ToArray(),
"Text",
"Value");
}
public ActionResult ItemsList(string ID)
{
string Text = ID;
var items = from s in db.Items
where s.ItemType.ItemTypeName == Text
select s;
if (HttpContext.Request.IsAjaxRequest())
return Json(new SelectList(
items.ToArray(),
"ItemId",
"ItemName")
, JsonRequestBehavior.AllowGet);
return RedirectToAction("Browse");
}
}
The Javascript :
$(function () {
$('#ItemsDivId').hide();
$('#SubmitID').hide();
$('#ItemTypeID').change(function () {
var URL = $('#TypeItemFormID').data('itemsListAction');
$.getJSON(URL + '/' + $('#ItemTypeID').val(), function (data) {
var items = '<option>Select a Item</option>';
$.each(data, function (i, item) {
items += "<option value='" + item.Value + "'>" + item.Text + "</option>";
// state.Value cannot contain ' character. We are OK because state.Value = cnt++;
});
$('#ItemsID').html(items);
$('#ItemsDivId').show();
});
});
$('#ItemsID').change(function () {
$('#SubmitID').show();
});
});
And at last my Model :
public class Department
{
public int DepartmentId { get; set; }
[DisplayName("Department")]
public string DepartmentName { get; set; }
public List<Item> Items { get; set; }
}
public class ItemType
{
public int ItemTypeId { get; set; }
[DisplayName("Type")]
public string ItemTypeName { get; set; }
[DisplayName("Image")]
public string ItemTypeImage { get; set; }
public List<Item> Items { get; set; }
}
public class Item
{
public int ItemId { get; set; }
[DisplayName("Name")]
public string ItemName { get; set; }
[DisplayName("Description")]
public string ItemDescription { get; set; }
[DisplayName("Ref Code")]
public string ItemReferenceCode { get; set; }
[ForeignKey("ItemType")]
public int ItemTypeId { get; set; }
public virtual ItemType ItemType { get; set; }
[ForeignKey("Department")]
public int DepartmentId { get; set; }
public Department Department { get; set; }
[DisplayName("Computer Location")]
public string ComputerLocation { get; set; }
[DisplayName("Author Name")]
public string AuthorName { get; set; }
[DisplayName("Published Year")]
public string PublishedYear { get; set; }
}
Here's how I would accomplish something like this. It isn't the only way to do it.
$('#ItemTypeID').on('change', function() {
$.ajax({
type: 'POST',
url: '#Url.Action("GetItemTypeForm")',
data: { itemTypeId: $('#ItemTypeID').val() },
success: function(results) {
var options = $('#ItemTypeFormId');
options.empty();
options.append($('<option />').val(null).text("- Select an Item Type -"));
$.each(results, function() {
options.append($('<option />').val(this.ItemTypeFormId).text(this.Value));
});
}
});
});
Then you'd have a controller that looks something like this.
[HttpPost]
public JsonResult GetItemTypeForm(string itemTypeId)
{
//pseudo code
var data = Repostitory.GetData(itemTypeId)
return Json(data);
}

Knockoutjs: Posting complex type to MVC controller query

I have been battling with this for 3 days.
Basically, I have a javascript object posting up to an MVC controller. Upon checking the property key names in the Request.Form.AllKeys namevalueCollection, I noticed that my sub-properties are being surrounded with [] and the MVC model binder doesnt bind these values.
The values coming through on the controller look like this:
[6]: "Metadata[ScreenResolution]"
[7]: "Metadata[AudioCodec]"
[8]: "Metadata[VideoCodec]"
[9]: "Metadata[Format]"
My question is why is this happening.
Edit: The "first-level properties are binding successfully, In the javascript, when the javascript object is being created, all the properties are being set correctly from KO"
MVC Model:
public class Movie
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public string Directors { get; set; }
public string Description { get; set; }
public int GenreId { get; set; }
public int YearId { get; set; }
public MovieMetadata Metadata { get; set; }
public int RatingId { get; set; }
public string MovieUrl { get; set; }
public string Stars { get; set; }
public string Duration { get; set; }
}
public class MovieMetadata
{
public int Id { get; set; }
public string ScreenResolution { get; set; }
public string VideoCodec { get; set; }
public string AudioCodec { get; set; }
public int FormatId { get; set; }
}
Knockout Js file:
var SimpleModelLoading = function (data) { //data: this is JSON result coming back form the action method
var self = this;
self.MovieModel = {};
self.MovieName = ko.observable(data.Name);
self.Description = ko.observable(data.Description);
self.Directors = ko.observable(data.Directors);
self.MovieUrl = ko.observable(data.MovieUrl);
self.Stars = ko.observable(data.Stars);
self.Duration = ko.observable(data.Duration);
self.ScreenResolution = ko.observable(data.Metadata.ScreenResolution);
self.AudioCodec = ko.observable(data.Metadata.AudioCodec);
self.VideoCodec = ko.observable(data.Metadata.VideoCodec);
self.selectedGenre = ko.observable();
self.selectedYear = ko.observable();
self.selectedRating = ko.observable();
self.selectedFormat = ko.observable();
self.MovieModel = ko.computed(function () {
var movieModel =
{
Name: self.MovieName(),
Description: self.Description(),
GenreId: self.selectedGenre() == undefined ? undefined : self.selectedGenre().Key,
YearId: self.selectedYear() == undefined ? undefined : self.selectedYear().Key,
RatingId: self.selectedRating() == undefined ? undefined : self.selectedRating().Key,
Directors: self.Directors(),
Stars: self.Stars(),
MovieUrl: self.MovieUrl(),
Duration: self.Duration(),
};
movieModel.Metadata =
{
ScreenResolution: self.ScreenResolution(),
AudioCodec: self.AudioCodec(),
VideoCodec: self.VideoCodec(),
Format: self.selectedFormat() == undefined ? undefined : self.selectedFormat().Key
};
return movieModel;
}, self);
self.Genres = data.LookupData.Genre;
self.Year = data.LookupData.Year;
self.Rating = data.LookupData.Rating;
self.Format = data.LookupData.Format;
self.saveMovie = function () {
var url = "/Movie/SaveMovie";
$.ajax(
{
url: url,
data: self.MovieModel(),
type: "POST",
success: function () {
alert('save successful');
},
error: function (xhr) {
alert(xhr.responseText);
}
});
};
};
Movie View:
<div>
<form method="POST">
<div data-role="collapsible" data-collapsed="false" id="movieInfoContainer">
<h2>Add New Video</h2>
#* <div data-role="collapsible" data-collapsed="false">
<h3>Movie Details</h3>
<div id="movieInfo">
#Html.Partial("MovieDetails")
</div>
</div>*#
<div data-role="collapsible" data-collapsed="true" id="movieMetadataContainer">
<h3>Technical Specifications</h3>
<div id="movieMetadata">
#Html.Partial("MovieMetadataDetails")
</div>
</div>
</div>
<p>
<button data-bind="click: saveMovie">Save</button>
</p>
</form>
</div>
Movie Metadata View:
<p>
Audio Encoding:<input data-bind="value: AudioCodec" />
</p>
<p>
Video Encoding:<input data-bind="value: VideoCodec" />
</p>
<p>
Screen Resolution:<input data-bind="value: ScreenResolution" />
</p>
<div class="clearSpaceLine"><span>Format:</span></div>
<select data-bind="options: Format, value: selectedFormat, optionsText: 'Value'"></select>
<br />
You are posting the observable object directly, but observables nested inside are functions, not data.
Try replacing this
data: self.MovieModel(),
with this
data: ko.toJSON(self.MovieModel()),
More information on this here

Categories

Resources