Child JSON object undefined when its not - asp.net-mvc

I have an array of JSON objects in the page source that all work except a child object (category).
Here is the code in cshtml:
<script type="text/javascript">
var initialData = #Html.Raw(Json.Encode(ViewBag.OfferItems));
</script>
Here is the resulting page source:
<script type="text/javascript">
var initialData = [{"Id":1,"Name":"Item1","ProductVariantLinks":[{"category":{"Id":2,"Name":"Basic Pizza","Products":null},"product":{"Id":1,"Name":"Margherita","Description":null,"ProductVariants":null},"productVariant":{"Id":1,"Name":"10 inch"}},{"category":{"Id":2,"Name":"Basic Pizza","Products":null},"product":{"Id":2,"Name":"Zeno","Description":null,"ProductVariants":null},"productVariant":{"Id":4,"Name":"8 inch"}}]},{"Id":2,"Name":"Item2","ProductVariantLinks":[]}];
</script>
As far as I can tell category is there and contains properties, but it appears as undefined in IE's debugger.
Is there something I'm missing?
P.S. the JSON is valid.
Update
I'm using knockoutjs and category is in inialdata until it does ko.applybindings. I'm not sure why it would do this, code below:
/// <reference path="jquery-1.5.1.js" />
/// <reference path="knockout-2.0.0.js" />
var ProductVariantLink = function() {
var self = this;
self.category = ko.observable();
self.product = ko.observable();
self.productVariant = ko.observable();
// Whenever the category changes, reset the product selection
self.category.subscribe(function() {
self.product(undefined);
self.productVariant(undefined);
});
};
var OfferItem = function() {
var self = this;
self.Name = new String();
self.ProductVariants = new Array();
};
var SpecialOfferItemModel = function (specialOfferItems) {
var self = this;
self.specialOfferItems = ko.observableArray(ko.utils.arrayMap(specialOfferItems, function (specialOfferItem) {
return { Id: specialOfferItem.Id, Name: specialOfferItem.Name, ProductVariants: ko.observableArray(specialOfferItem.ProductVariantLinks) };
}));
self.addSpecialOfferItem = function () {
self.specialOfferItems.push({
Id: "",
Name: "",
ProductVariants: ko.observableArray()
});
};
self.removeSpecialOfferItem = function (specialOfferItem) {
self.specialOfferItems.remove(specialOfferItem);
};
self.addProductVariant = function (specialOfferItem) {
specialOfferItem.ProductVariants.push(new ProductVariantLink());
};
self.removeProductVariant = function (ProductVariant) {
$.each(self.specialOfferItems(), function () { this.ProductVariants.remove(ProductVariant) })
};
self.save = function () {
var OfferItems = new Array();
$.each(self.specialOfferItems(),
function () {
var item = this;
var offer = new OfferItem();
offer.Name = item.Name;
$.each(item.ProductVariants(),
function () {
offer.ProductVariants.push(this.ProductVariant);
});
OfferItems.push(offer);
});
self.lastSavedJson(JSON.stringify(ko.toJS(self.specialOfferItems()), null, 2));
return false;
};
self.lastSavedJson = ko.observable("");
};
var model = new SpecialOfferItemModel(initialData);
ko.applyBindings(model);
$(function () {
$('#myForm').submit(function () {
model.save();
});
});
<table class="specialOfferItemsEditor">
<tr>
<th>
</th>
<th>
Name
</th>
<th>
ProductVariants
</th>
</tr>
<tbody data-bind="foreach: specialOfferItems">
<tr>
<td>
<div>
Delete</div>
</td>
<td>
<input data-bind="value: Name" />
</td>
<td>
<table>
<tr>
<th>
Category
</th>
<th>
Product
</th>
<th>
ProductVariant
</th>
</tr>
<tbody data-bind="foreach: ProductVariants">
<tr>
<td>
<select data-bind='options: ProductCategories, optionsText: "Name", optionsCaption: "Select...", value: category, uniqueName: true'>
</select>
</td>
<td data-bind="with: category">
<select data-bind='options: Products, optionsText: "Name", optionsCaption: "Select...", value: $parent.product, uniqueName: true' >
</select>
</td>
<td data-bind="with: product">
<select data-bind='options: ProductVariants, optionsText: "Name", optionsCaption: "Select...", value: $parent.ProductVariant, uniqueName: true'
>
</select>
</td>
<td>
<a href='#' data-bind='click: $root.removeProductVariant'>Delete</a>
</td>
</tr>
</tbody>
</table>
<a href='#' data-bind='click: $root.addProductVariant'>Add Product Variant</a>
</td>
</tr>
</tbody>
</table>

The JSON isn't coming in as you're expecting. I assigned the JSON string you provided above and my IE debugger was able to find 'category' without any issues.
Screenshot: https://i.stack.imgur.com/cI60U.jpg
Try to console.log (or alert) JSON.stringify(initialData);

Related

Partial View Not Rendering inside div

So I was trying to follow this guide and the followup article.
But Before I started with the searching, sorting and filtering, I wanted to see if even the pages were working as intended.
Unfortunately they are not and I cant for the life of me figure it out why, I even went so far as to download his working example just to see if it was something with my browser. (To download his working example its at the top of the second article, I cant post more then 2 links)
Since his worked I compared his views, controllers and scripts side by side to mine and from what I can tell they mirror each other.
So I ended up copying my code somewhere else and pasted his into my project, changed the ActionLinks to reflect the naming conventions I used and left out the stuff I havent implemented yet (noted above). And it still do sent work.
When I run them side by side I get no errors in the console, they are loading the same scripts with the exception that I added jquery.unobstrusive-ajax.js as an attempt to correct it from searching for solutions, but it didnt help.
I have no idea what I'm doing wrong here :/
My Manage View - Correlates to his Home Index View
The only thing I really changed here is the action link
#{
ViewBag.Title = "Home Page";
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/bootstrap")
<script src="~/Scripts/ModalDialog.js"></script>
<style>
.testClass {
font-size: xx-large;
text-transform: capitalize;
}
</style>
<title>
Complete example of MVC pagination, filtering and sortig inside patial view with edit in modal dialog
</title>
</head>
<body style="padding-top:0">
<table style="width:100%;" border="1" cellspacing="0" cellpadding="0">
<tr>
<td style="" colspan="2">
<div id="logo" style="height:70px; background-color:rgba(86, 111, 111, 1);font: 1.5em Georgia, Times New Roman, Times, serif;">
Complete example of MVC pagination, filtering and sortig inside patial view with edit in modal dialog
</div>
<div id="navigation" style="background-color:#a4c2c2">
HOME
</div>
</td>
</tr>
<tr style="height:600px">
<td style="width:200px;background-color: #a4c2c2; vertical-align:top; padding-top:10px; padding-left:10px">
<div>
<ul>
<li>
#Html.ActionLink("Manage Assets", "MasterDetail", "Assets", new { }, new { id = "btnCustomers", #class = "btn btn-default btn-xs" })
</li>
</ul>
</div>
</td>
<td>
<div id="contentFrame" style="width:100%; height:600px; padding-top:10px; padding-left:10px" />
</td>
</tr>
</table>
</body>
</html>
<script type="text/javascript">
$(function () {
$.ajaxSetup({cache : false})
$('#btnCustomers').click(function () {
$('#contentFrame').mask("waiting ...");
$('#contentFrame').load(this.href, function (response, status, xhr) {
$('#contentFrame').unmask("waiting ...");
});
return false;
});
});
</script>
My MasterDetail View - Correlates to his Customers Index view
My table is setup different because i havent done everything he has yet
#using PagedList.Mvc
#model PagedList.IPagedList<Furst_Alpha_2._0.Models.Quantities>
#{
Layout = null;
}
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/bootstrap")
<script src="~/Scripts/ModalDialog.js"></script>
<h2>Inventory Management</h2>
<p>
#Html.ActionLink("Create New", "_Create", new { id = -1 }, new { btnName = "btnCreate", #class = "btn btn-default btn-xs" })
</p>
<table class="table">
<tr>
<th>
Category
</th>
<th>
Make
</th>
<th>
Model
</th>
<th>
Type
</th>
<th>
Length
</th>
<th>
Width
</th>
<th>
Height
</th>
<th>
Weight
</th>
<th>
Description
</th>
<th>
Rental Price
</th>
<th>
Number Of Techs
</th>
<th>
Total
</th>
<th>
In User
</th>
<th>
Availability
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Assets.Category.CategoryName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.Make.MakeName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.Model.ModelName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.Type.TypeName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.Length)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.Width)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.Height)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.Weight)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.Description)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.RentalPrice)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.NumTechsReq)
</td>
<td>
#Html.DisplayFor(modelItem => item.total)
</td>
<td>
#Html.DisplayFor(modelItem => item.InUse)
</td>
<td>
#Html.DisplayFor(modelItem => item.Availability)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.QuantityId }, new { btnName = "btnEdit", #class = "btn btn-default btn-xs" })
#Html.ActionLink("Delete", "Delete", new { id = item.QuantityId }, new { btnName = "btnDelete", #class = "btn btn-default btn-xs" })
</td>
</tr>
}
</table>
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
<div id="myPager">
#Html.PagedListPager(Model, page => Url.Action("MasterDetail", new { page, OrderID = ViewBag.OrderID }))
</div>
<script type="text/javascript">
$(function () {
$.ajaxSetup({ cache: false });
setDialogLink($('a[btnName=btnCreate]'), 'Add New Asset', 500, 600, "contentFrame", "/Assets/MasterDetail");
setDialogLink($('a[btnName=btnEdit]'), 'Edit Customer', 500, 600, "contentFrame", "/Customers/Index");
setDialogLink($('a[btnName=btnDetails]'), 'Customer Details', 500, 600, "contentFrame", "/Customers/Index");
$('a[btnName=btnDelete]').click(function (e) {
e.preventDefault();
var confirmResult = confirm("Are you sure?");
if (confirmResult)
{
$('#contentFrame').mask("waiting ...");
$.ajax(
{
url: this.href,
type: 'POST',
data: JSON.stringify({}),
dataType: 'json',
traditional: true,
contentType: "application/json; charset=utf-8",
success:function(data)
{
if (data.success) {
$('#contentFrame').load("/Customers/Index");
}
else {
alert(data.errormessage);
}
$('#contentFrame').unmask("waiting ...");
},
error: function (data) {
alert("An error has occured!!!");
$('#contentFrame').unmask("waiting ...");
}
});
}
})
$("a[btnName=FilterCustomer]").click(function (e) {
e.preventDefault();
var search = $('input[name=search]').val();
this.href = this.href.replace('xyz', search);
$('#contentFrame').mask("waiting ...");
$.ajax({
url: this.href,
type: 'POST',
cache: false,
success: function (result) {
$('#contentFrame').unmask("waiting ...");
$('#contentFrame').html(result);
}
});
});
$(".SortButton").click(function (e) {
e.preventDefault();
$('#contentFrame').mask("waiting ...");
$.ajax({
url: this.href,
type: 'POST',
cache: false,
success: function (result) {
$('#contentFrame').unmask("waiting ...");
$('#contentFrame').html(result);
}
})
});
$('#myPager').on('click', 'a', function (e) {
e.preventDefault();
$('#contentFrame').mask("waiting ...");
$.ajax({
url: this.href,
type: 'GET',
cache: false,
success: function (result) {
$('#contentFrame').unmask("waiting ...");
$('#contentFrame').html(result);
}
});
});
});
</script>
My AssetsController Manage and MasterDetail methods which correlate to his HomeController Index and CustomerController Index methods respectively.
// GET: Assets
public ActionResult Manage()
{
return View();
}
// GET: MasterDetail
public ActionResult MasterDetail(int? page)
{
ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(User.Identity.GetUserId());
//ApplicationUser user = db.Users.First(u => u.Id == userr.Id);
var assets = db.Quantities.Where(a => a.VendorId == user.VendorId).OrderByDescending(a => a.AssetId);
int pageNumber = page ?? 1;
int pageSize = 3;
return PartialView(assets.ToPagedList(pageNumber, pageSize));
}
I am not too sure about what your problem is, but I THINK there I saw a problem in your code.
in MasterDetail.cshtml try replacing
#Html.PagedListPager(Model, page => Url.Action("_MasterDetail", new { page, OrderID = ViewBag.OrderID }))
with
#Html.PagedListPager(Model, page => Url.Action("MasterDetail", new { page, OrderID = ViewBag.OrderID }))
Url.Action expects an Action name, not a razor view name.
So last night while laying in bed stumped as to whats causing the problem I thought well maybe I should just look up alternatives. I saw some Ajax variations (that youll see commented out) and I ended up on this SO thread which ultimately lead me to a solution.
Below is the end result of my tinkering, I left commented code in from my attempts so you'll see other thigns I've tried. Other than this all I changed in the view was add a reference for a modal wait screen and then changed Html.ActionLink to a button. <input id="btnCustomers" type="button" value="Manage Assets" />
<script type="text/javascript">
$(function () {
$.ajaxSetup({cache : false})
$('#btnCustomers').click(function () {
//$('#contentFrame').mask("waiting ...");
waitingDialog.show("Please wait while we prepare your inventory ...");
$('#contentFrame').load('#Url.Action("MasterDetail","Assets")', function () {
setTimeout(function () {
waitingDialog.hide();
}, 1000);
});
//$.ajax({
// type: 'GET',
// url: '#Url.Content("~/Assets/MasterDetail")',
// data: -1,
// success: function (data) {
// $('#contentFrame').innerHtml = waitingDialog.hide();
//$('#contentFrame').load('#Url.Action("MasterDetail","Assets")');
// }
//})
//$('#contentFrame').load(this.href, function (response, status, xhr) {
// $('#contentFrame').unmask("waiting ...");
//});
return false;
});
});
</script>

Knockout Nested List Post Null

I'm trying integrate ko on one of my razor views. I've researched quite a bit yesterday but haven't been able to find a similar solution for my problem.
I have a record model:
public class Record
{
public Int Request Id {get;set;}
public string RecordName {get;set;}
public Person Person {get;set;}
public IList<Person> People { get; set; }
}
And a Person Model:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IList<Alias> Aliases { get; set; }
}
My View:
#model Record
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm("PostRequest", "Request", FormMethod.Post))
{
#Html.LabelFor(m => m.Person.FirstName)
#Html.TextBoxFor(m => m.Person.FirstName)
<h5>People</h5>
<table>
<tbody data-bind="foreach: People">
<tr>
<td>#Html.LabelFor(m => m.Person.FirstName)</td>
<td><input type="text" data-bind="value: FirstName, attr: {name: 'People[' + $index() + '].FirstName'}" /></td>
<td>#Html.LabelFor(m => m.Person.LastName)</td>
<td><input type="text" data-bind="value: LastName, attr: {name: 'People[' + $index() + '].LastName'}" /></td>
</tr>
<tr>
<td><button id="removePerson" data-bind="click: $root.removePerson">Remove Person</button></td>
</tr>
<tr>
<td>
<button id="addAlias" data-bind="click: addAlias">Add Alias</button>
</td>
</tr>
<!-- ko foreach: Aliases -->
<tr>
<td>#Html.LabelFor(m => m.Alias.FirstNameAlias)</td>
<td><input type="text" data-bind="value: FirstNameAlias, attr: {name: 'Aliases[' + $index() + '].FirstNameAlias'}" /></td>
<td>#Html.LabelFor(m => m.Alias.LastNameAlias)</td>
<td><input type="text" data-bind="value: LastNameAlias, attr: {name: 'Aliases[' + $index() + '].LastNameAlias'}" /></td>
<td><button id="removeAlias" data-bind="click: $root.removeAlias">Remove Alias</button></td>
</tr>
<!-- /ko -->
</tbody>
</table>
<button id="addPerson" data-bind="click: addPerson">Add Person</button>
<button>Submit</button>
<input id="clickMe" type="button" value="clickme" onclick="submit();" />
}
And Script:
#section scripts
{
<script type="text/javascript">
$(function () {
var personItem = function () {
var self = this;
self.LastName = ko.observable();
self.FirstName = ko.observable();
self.Aliases = ko.observableArray();
};
var model = ko.mapping.fromJS(#Html.Raw(Model.ToJson()));
alert('The length of the array is ' + model.People().length);
alert('The first element is ' + model.People()[0].Aliases().length);
alert(ko.toJSON(model));
model.addPerson = function () {
model.People.push(new personItem());
};
model.removePerson = function (person) {
model.People.remove(person);
};
ko.applyBindings(model);
})
function submit() {
$.ajax({
url: '/Request/PostRequest',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: ko.toJSON(model),
success: function (status) {
alert(status);
}
});
};
</script>
}
The Controller action that GETs this view pre initializes some data for the record model, so the binding appears to be working properly, however when I post data, the data for Alias List comes back Null.
Controller:
public ActionResult CreateRequest(Record viewModel)
{
var list = new Record
{
People = new List<Person> {
new Person {FirstName = "My First Person", Aliases = new List<Alias> { new Alias{FirstNameAlias = "firstnamealias",LastNameAlias = "lastnamealias1"}},},
new Person {FirstName = "My Second Person", Aliases = new List<Alias> { new Alias{FirstNameAlias = "firstnamealias2", LastNameAlias ="lastnamealias2"}},}
},
Person = new Person()
{
FirstName = "me"
}
};
return View(list);
}
[HttpPost]
public JsonResult PostRequest(Record viewModel)
{
return Json(String.Format("'Success':'false','Error':'"));
}
I feel that I am missing something with ko.mapping. But so close, as the data populates from the GET controller action, but fails to POST.
SOLUTION
I updated my KO script, and the way I was rendering the ko data in the view. This has solved my problem.
Updated Script
<script>
var initialData = #Html.Raw(Serialize(Model.People));
var BackgroundModel = function(people) {
var self = this;
self.people = ko.mapping.fromJS(people);
self.addPerson = function() {
self.people.push({
FirstName: "",
LastName: "",
Aliases: ko.observableArray()
});
};
self.removePerson = function(person) {
self.people.remove(person);
};
self.addAlias = function(person) {
person.Aliases.push({
//todo
FirstNameAlias: "",
LastNameAlias: ""
});
};
self.removeAlias = function(Alias) {
$.each(self.people(), function() { this.Aliases.remove(Alias) })
};
self.save = function() {
self.lastSavedJson(JSON.stringify(ko.toJS(self.people), null, 2));
var subModel = JSON.stringify(ko.toJS(self));
$.ajax({
url: '/Request/PostRequest',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: subModel,
success: function (status) {
alert(status);
}
});
};
self.lastSavedJson = ko.observable("")
};
ko.applyBindings(new BackgroundModel(initialData));
</script>
Updated View
<div data-bind="foreach: people">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title"> <a data-bind="attr:{href:'#collapseOne'+$index()}, text:FirstName() +' '+ LastName()" #*href="#collapse_One"*# class="accordion-toggle" data-toggle="collapse" data-parent="#accordion"></a> </h4>
</div>
<div data-bind="attr:{id:'collapseOne'+$index()}" class="panel-collapse collapse in" #*data-bind="attr:{id:_collapseId, class:_collapsedIn}"*#>
<div class="panel-body">
<table>
<tbody>
<tr>
<td>#Html.DisplayNameFor(x => x.Person.FirstName)</td>
<td>#Html.DisplayNameFor(x => x.Person.LastName)</td>
</tr>
<tr>
<td><input data-bind="value: FirstName, name: FirstName" /></td>
<td><input data-bind="value: LastName, name: LastName" /></td>
</tr>
<tr>
<td><a href='#' data-bind='click: $root.removePerson'>Remove Person</a></td>
</tr>
</tbody>
</table>
<!-- ko foreach: Aliases -->
<table>
<tbody>
<tr>
<td>#Html.DisplayNameFor(x => x.Alias.FirstNameAlias)</td>
<td>#Html.DisplayNameFor(x => x.Alias.LastNameAlias)</td>
</tr>
<tr>
<td><input data-bind="value: FirstNameAlias, name: FirstNameAlias" /></td>
<td><input data-bind="value: LastNameAlias, name: LastNameAlias" /></td>
</tr>
<tr>
<td><a href='#' data-bind='click: $root.removeAlias'>Remove Alias</a></td>
</tr>
</tbody>
</table>
<!-- /ko -->
<a href='#' data-bind='click: $root.addAlias'>Add Alias</a>
</div>
</div>
</div>
</div>
The variable model in your submit funtion is going to be undefined it's not the model you're expecting it to be.
Move the submit method to in to your model...
$(function () {
var personItem = function () {
var self = this;
self.LastName = ko.observable();
self.FirstName = ko.observable();
self.Aliases = ko.observableArray();
};
var model = ko.mapping.fromJS(#Html.Raw(Model.ToJson()));
alert('The length of the array is ' + model.People().length);
alert('The first element is ' + model.People()[0].Aliases().length);
alert(ko.toJSON(model));
model.addPerson = function () {
model.People().push(new personItem());
};
model.removePerson = function (person) {
model.People().remove(person);
};
model.submit = function() {
$.ajax({
url: '/Request/PostRequest',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: ko.toJSON(model),
success: function (status) {
alert(status);
}
});
};
ko.applyBindings(model);
});
and update the binding on your button to
<input id="clickMe" type="button" value="clickme" data-bind="click: submit" />
Also
Controller.Json expects an object to serialize rather than a string
[HttpPost]
public JsonResult PostRequest(Record viewModel)
{
return Json(String.Format("'Success':'false','Error':'"));
}
Should be:
[HttpPost]
public JsonResult PostRequest(Record viewModel)
{
return Json(new { success = false, error: String.Empty });
}
Update
Also noticed another issue with updating the model.People array
model.addPerson = function () {
model.People.push(new personItem());
};
model.removePerson = function (person) {
model.People.remove(person);
};
In these functions model.People should be model.People(), i.e.
model.addPerson = function () {
model.People().push(new personItem());
};
model.removePerson = function (person) {
model.People().remove(person);
};
Notice the () after model.People - included in the code block above.

Can not save data 2nd time knockout mvc

I am new in knockout and asp.net mvc both.
I am trying to Insert update delete data in database with knockout. My knockout model is
function City(data) {
this.CityId = ko.observable(data.CityId);
this.CityName = ko.observable(data.CityName);
}
function CityViewModel() {
var self = this;
self.Citys = ko.observableArray([]);
self.CityId = ko.observable();
self.CityName = ko.observable();
self.selectedCity = ko.observable();
// self.City = ko.observable();
selectCity = function (item) {
self.selectedCity(item);
}
//load
loadCitys = function () {
$.getJSON("/Admin/GetCitys", {}, function (result) {
var mappedCitys = ko.utils.arrayMap(result.Data, function (item) {
return new City(item);
});
self.Citys([]);
self.Citys.push.apply(self.Citys, mappedCitys);
});
}
//edit
EditCity = function (item) {
//what need to do here
// is it possible to fill the hidden fild and the text box ??
}
//save
SaveCity = function (item) {
City = new City(item);
$.ajax({
type: "POST",
url: "/Admin/SaveCity",
data: ko.toJSON({ City: City }),
contentType: "application/json",
success: function (result) {
if (result.Edit) {
City.CityId = result.Success;
City.CityName = item.CityName;
self.Citys.push(City);
toastr.success('City Information Save Successfully', 'Success');
}
else if (result.Edit == false) {
toastr.success('City Information Update Successfully', 'Success');
}
else {
toastr.error('There is an error please try again later', 'Errror');
}
}
});
}
//delete
DeleteCity = function (City) {
$.ajax("/Admin/DeleteCity", {
data: ko.toJSON({ CityId: City.CityId }),
type: "POST", contentType: "application/json",
success: function (result) {
if (result.Success) {
self.Citys.remove(City);
toastr.success('City Remove Successfully', 'Success');
}
else {
alert("Error..");
}
}
});
}
}
(function () {
ko.applyBindings(new CityViewModel, document.getElementById("Citys"));
loadCitys();
});
And my Html codes are
<table class="table table-striped">
<thead>
<tr>
<th>City Id</th>
<th>City Name</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: $root.Citys">
<tr data-bind="click: selectCity">
<td><span data-bind="text:CityId"></span></td>
<td><span data-bind="text:CityName"></span></td>
<td><button data-bind="click: EditCity" class="btn btn-primary">Edit</button></td>
<td><button data-bind="click: DeleteCity" class="btn btn-danger">Delete</button></td>
</tr>
</tbody>
</table>
<fieldset>
<legend>Add new / Edit City</legend>
<label>City name</label>
<input type="hidden" data-bind="value: CityId" />
<input type="text" data-bind="value: CityName" placeholder="Type city nameā€¦">
<button type="submit" data-bind="click: SaveCity" class="btn">Submit</button>
</fieldset>
With this codes I can get data form database display them successfully in my view file,
I delete the data from database, and I also can Insert data to database but here is a problem I can save data only 1st time when I change the textbox value (without page refresh) and try to save city information then it say (in Firebug on my javascript code):
TypeError: City is not a constructor
City = new City(item);
My question is what have I done wrong in this codes, and I am trying to fill the textbox and the hidden field when edit button click, how can I do this?
Thanks in advance.
There are a number of faults with your javascript, including:
The methods on your viewmodel, such as SaveCity, DeleteCity, EditCity are all being defined without the 'this/self' prefixes, therefore they are being added to the global namespace.
In your SaveCity method, your are assigning a new instance of the City class to a variable called 'City', therefore destroying the City class. It will work the first time, but any other attempts to create an instance of a City will yield an exception.
Anyway, this should be a working version of your script and HTML without the ajax stuff. You will need to adapt that yourself. I have also created a working JsFiddle here..
function City(data) {
this.CityId = ko.observable(data.CityId);
this.CityName = ko.observable(data.CityName);
}
function CityViewModel() {
var self = this;
self.Citys = ko.observableArray([]);
self.SelectedCity = ko.observable();
self.EditingCity = ko.observable(new City({CityId: null, CityName: ''}));
self.EditCity = function(city){
self.EditingCity(new City(ko.toJSON(city)));
};
//load
self.loadCitys = function () {
self.Citys().push(new City({CityId: '1245', CityName: 'Los Angeles'}));
self.Citys().push(new City({CityId: '45678', CityName: 'San Diego'}));
};
//save
self.SaveCity = function () {
var city = self.EditingCity();
if(city.CityId()){
var cityIndex;
for(var i = 0; i < self.Citys().length; i++) {
if(self.Citys()[i].CityId() === city.CityId()) {
cityIndex = i;
break;
}
}
self.Citys[cityIndex] = city;
}
else{
city.CityId(Math.floor((Math.random()*1000000)+1));
self.Citys.push(city);
}
self.EditingCity(new City({CityId: null, CityName: ''}));
}
//delete
self.DeleteCity = function (city) {
self.Citys.remove(city);
};
}
var viewModel = new CityViewModel();
viewModel.loadCitys();
ko.applyBindings(viewModel, document.getElementById("Citys"));
HTML
<table class="table table-striped">
<thead>
<tr>
<th>City Id</th>
<th>City Name</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: Citys">
<tr data-bind="click: $root.SelectedCity">
<td><span data-bind="text:CityId"></span></td>
<td><span data-bind="text:CityName"></span></td>
<td><button data-bind="click: $root.EditCity" class="btn btn-primary">Edit</button></td>
<td><button data-bind="click: $root.DeleteCity" class="btn btn-danger">Delete</button></td>
</tr>
</tbody>
</table>
<fieldset data-bind='with:EditingCity'>
<legend>Add new / Edit City</legend>
<label>City name</label>
<input type="hidden" data-bind="value: CityId" />
<input type="text" data-bind="value: CityName" placeholder="Type city name" />
<button type="submit" data-bind="click: $root.SaveCity" class="btn">Submit</button>
</fieldset>

MVC: HTML table rows in a PartialView are not rendered in HTML after an Ajax call

My form looks like;
#model IEnumerable<SCD.ViewModels.UserLineViewModel>
#{
ViewBag.Title = "List";
}
<h2>List</h2>
<form method="GET" action="#Url.Action("AddNewUser", "DataService")" data-scd-ajax="true" data-scd-target="#userList">
#if (TempData["SuccessMessage"] != null)
{
<p class="successHighlight">#TempData["SuccessMessage"].ToString()</p>
}
#if (TempData["ErrorMessage"] != null)
{
<p class="errorHighlight">#TempData["ErrorMessage"].ToString()</p>
}
<p>
<input type="search" name="searchTerm" id="searchTerm" class="newUser"
data-scd-autocomplete="#Url.Action("AutocompleteUser", "DataService")" style = "width:300px;"/>
<input type="hidden" id="searchId" name="searchId"/>
</p>
<table>
<tr>
<th>Forename</th>
<th>Surname</th>
<th>Created</th>
<th>Administrator?</th>
<th></th>
</tr>
<tbody id="userList">
#Html.Partial("_UserLine")
</tbody>
</table>
</form>
My partial view looks like
#model IEnumerable<UserLineViewModel>
#Html.EditorForModel()
And the editor template so far looks like
#model UserLineViewModel
<tr>
<td>
#Html.DisplayFor(x => x.Employee.Forename)
</td>
<td>
#Html.DisplayFor(x => x.Employee.Surname)
</td>
<td>
#Html.DisplayFor(x => x.UserScd.Created)
</td>
<td>
#Html.EditorFor(x => x.UserScd.AdminFlag)
</td>
<td>
#Html.ActionLink("Remove", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
When the user selects a person from autocomplete, this method on the DataService controller gets called;
public ActionResult AddNewUser(int searchId)
{
var opStatus = this.UserScdRepository.Add(searchId);
if (!opStatus.Status)
{
return this.PartialView("_UserLine", new List<UserLineViewModel>());
}
this.TempData["SuccessMessage"] =
string.Format("You successfully entered the new user {0}",
vw_EmployeesAndJobTitles.GetName(searchId)).MessageTime();
var employeesInScd = this.EmployeeRepository.GetEmployeesInScd();
UserLineViewModel.UserScdRepository = this.UserScdRepository;
var userList = employeesInScd.Select(employee => new UserLineViewModel(employee)).ToList();
return this.PartialView("_UserLine", userList);
}
And the Jquery/Ajax that joins this up looks like;
var ajaxFormSubmit = function () {
var $form = $(this);
var options = {
url: $form.attr("action"),
type: $form.attr("method"),
data: $form.serialize()
};
$.ajax(options).done(function (data) {
var $target = $($form.attr("data-scd-target"));
var $newHtml = $(data);
$target.replaceWith($newHtml);
$newHtml.effect("highlight");
});
return false;
};
var showOtherTrade = function (data) {
$('#searchOtherTrade').val('');
$('#otherTradeList').html(data);
};
var updateAutocompleteForm = function (event, ui) {
var $input = $(this);
if ($input.hasClass("newUser")) {
$('#searchId').val(ui.item.id);
var $form = $input.parents("form:first");
$form.submit();
}
$input.attr('readonly', 'readonly');
$input.css('font-size', '11px');
$input.selectRange(0, 50);
}
};
var createAutocomplete = function () {
var $input = $(this);
var options = {
source: $input.attr("data-scd-autocomplete"),
select: updateAutocompleteForm
};
$input.autocomplete(options);
};
Now the problem I am getting is that when I return the PartialView in the controller, the data is not rendered in the HTML of the Partial View. So how do I fix this?

Pass filename as parameter to Controller through jQuery

I am trying to upload an image using jQuery-ui dialog and pass the image file to the controller which will actually do the uploading work. However, I can't seem to get it right. The code is given below
View:
<table>
<tr>
<th>
Image
</th>
<th>
Name
</th>
</tr>
#foreach (var item in Model.CourseApplicationForms)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.thumbnail)
</td>
<td>
#Html.DisplayFor(modelItem => item.sname)
</td>
<td>
Upload File
</td>
</tr>
}
</table>
<div id="dialog" title="Upload files">
#using(Html.BeginForm("ImageUpload","Student", FormMethod.Post, new {id="photouploadform", enctype = "multipart/form-data" }))
{
<p><input type="file" id="fileUpload" name="fileUpload" size="23"/> </p><br />
<p><input type="submit" value="Upload file" /></p>
<input type="hidden" id="EnrollId" />
}
</div>
<script type="text/javascript">
$(function () {
$('.photoupload').click(function (event) {
$('#EnrollId').val(event.target.id);
$('#dialog').dialog('open');
});
$('#photouploadform').submit(function () {
$.getJSON("/Student/ImageUpload/", {
Id: $('#EnrollId').val(), file: $('#fileUpload')
}, function (data) {
$('#dialog').append('<p>' + data + '</p>');
});
return false;
});
$("#dialog").dialog({
autoOpen: false,
show: "blind",
width: 400,
hide: "fade",
modal: true,
resizable: false
});
});
</script>
Controller
[AcceptVerbs(HttpVerbs.Get)]
JsonResult ImageUpload(int Id, HttpPostedFileBase file = null)
{
string filePath = string.Empty;
if (file.ContentLength > 0)
{
Directory.CreateDirectory(HttpContext.Server.MapPath("~/Content/Photo/medium"));
filePath = Path.Combine(HttpContext.Server.MapPath("~/Content/Photo/medium"), Path.GetFileName(file.FileName));
file.SaveAs(filePath);
}
return Json(filePath, JsonRequestBehavior.AllowGet);
}
I want to pass the fileupload image but don't have a clue how to do it. Kindly help
Thanks in advance

Resources