I am getting a 500 error when I try and delete an item in my list using ajax.
From using the console on Chrome combined with Fiddler, a null reference on the Id is the issue. Debugging through Chrome's console shows that the announcement object does have an Id.
I was under the impression 500 errors came from the server, but I have a break point on the function path it's calling and not getting hit.
Is there anything that is staring me in the face as to why this would be setting the announcement.Id to null?
controller:
public JsonResult DeleteAnnouncement(int Id)
{
if(repository.DeleteAnnouncement(Id))
{
return Json(repository.GetAllAnnouncements(), JsonRequestBehavior.AllowGet);
}
return Json(null);
}
repository:
public bool DeleteAnnouncement(int Id)
{
var model = (from a in db.DbAnnouncement
where a.Id == Id
select a).SingleOrDefault();
if (model.Id != 0)
{
db.DbAnnouncement.Remove(model);
db.SaveChanges();
return true;
}
else
{
return false;
}
}
js script:
<script type="text/javascript">
function AnnouncementViewModel() {
//Make the self as 'this' reference
var self = this;
//Declare observable which will be bind with UI
self.Id = ko.observable("");
self.Title = ko.observable("");
self.Details = ko.observable("");
self.DTCreated = ko.observable("");
self.LastUpdated = ko.observable("");
self.CreatedUser = ko.observable("");
self.UpdatedUser = ko.observable("");
self.VersionNum = ko.observable("");
self.StartDT = ko.observable("");
self.ExpiryDT = ko.observable("");
self.Enabled = ko.observable("");
self.GroupID = ko.observable("");
self.URLLink = ko.observable("");
var Announcement = {
Id: self.Id,
Title: self.Title,
Details: self.Details,
DTCreated: self.DTCreated,
LastUpdated: self.LastUpdated,
CreatedUser: self.CreatedUser,
UpdatedUser: self.UpdatedUser,
VersionNum: self.VersionNum,
StartDT: self.StartDT,
ExpiryDT: self.ExpiryDT,
Enabled: self.Enabled,
GroupID: self.GroupID,
URLLink: self.URLLink
};
self.Announcement = ko.observable();
self.Announcements = ko.observableArray(); // list of announcements
// Delete announcement
self.delete = function (Announcement) {
if (confirm('Are you sure to Delete "' + Announcement.Title + '"?')) {
$.ajax({
url: '#Url.Action("DeleteAnnouncement","Announcement")',
cache: false,
type: 'POST',
contentType: 'application/json; charset=utf-8',
//data: ko.toJSON(Announcement.Id),
data: {Id: Announcement.Id},
success: function (data) {
self.Announcements.remove(Announcement);
alert("Record Deleted Successfully");
}
}).fail(
function (xhr, textStatus, err) {
alert(err);
});
}
}
}
$(document).ready(function () {
var viewModel = new AnnouncementViewModel();
ko.applyBindings(viewModel);
});
You are using ajax contentType as Json but not really sending a json object to server. Use
data: JSON.stringify({ Id: Announcement.Id() }),
and decorate your mvc action with [HttpPost]
[HttpPost]
public JsonResult DeleteAnnouncement(int Id)
{}
Related
I have a viewModel with a function
function resetForm(){
loanSystem("lis");
status("");
processor("");
fileType("funded");
orderDate("");
loanNumber("");
team("");
borrower("");
tracking("");
};
And a button on page with
<button type="reset" data-bind="click: resetForm">Reset</button>
But I am getting error:
Unable to process binding "click: function(){ return resetForm}. resetForm is not defined.
But I know my resetForm() works because it is called in my init function and if I change values in my resetForm() it show on initial page load. Any ideas?
var homeViewModel = (function () {
var loanSystem = ko.observable("lis");
var status = ko.observable("");
var processor = ko.observable("");
var fileType = ko.observable("funded");
var orderDate = ko.observable("");
var loanNumber = ko.observable("");
var team = ko.observable("");
var borrower = ko.observable("");
var tracking = ko.observable("");
var isLoanSystem = ko.computed(function () {
return (loanSystem() == "lps");
});
var isCalendar = ko.computed(function () {
return (isLoanSystem() && fileType() == "cancelled");
});
function resetForm(){
loanSystem("lis");
status("");
processor("");
fileType("funded");
orderDate("");
loanNumber("");
team("");
borrower("");
tracking("");
};
function submitFileInformation() {
if (!ValidInputs()) {
return;
}
var fileData = {
loanSystem: loanSystem(),
status: status(),
processor: processor(),
fileType: fileType(),
orderDate: orderDate(),
loanNumber: loanNumber(),
team: team(),
borrower: borrower(),
tracking: tracking()
};
$.ajax({
type: "POST",
url: "/ComplianceProcessing/Ajax.ashx",
data: JSON.stringify(fileData),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) {
if (data === false) {
alert("There was an error writing the file to the database.");
return;
}
alert('Data has been successfully saved.');
resetForm();
},
failure: function() {
alert('Failure');
}
});
}
return {
init: function() {
resetForm();
},
loanSystem: loanSystem,
isLoanSystem: isLoanSystem,
status: status,
processor: processor,
fileType: fileType,
isCalendar: isCalendar,
orderDate:orderDate,
loanNumber: loanNumber,
team: team,
borrower: borrower,
tracking: tracking
};
})();
Your resetForm is not exprosed from your viewmodel which makes it esentally private so Knockout cannot find it.
The solution is very easy, just include the resetForm in your returned object (which is your "public API"):
return {
init: function() {
resetForm();
},
loanSystem: loanSystem,
isLoanSystem: isLoanSystem,
status: status,
processor: processor,
fileType: fileType,
isCalendar: isCalendar,
orderDate:orderDate,
loanNumber: loanNumber,
team: team,
borrower: borrower,
tracking: tracking,
resetForm: resetForm //add this line
};
I'm getting null for the controller parameter. I am posting data as I can see it in Chrome Developer tools. I have a Person model in MVC that matches the Person model below. This is my ViewModel :
function Person(data) {
this.FirstName = ko.observable(data.FirstName);
this.LastName = ko.observable(data.LastName);
this.Id = ko.observable(data.Id);
this.fullName = ko.computed(function () {
return this.FirstName() + " " + this.LastName();
}, this);
}
function PersonViewModel() {
var self = this;
self.people = ko.observableArray([]);
$.getJSON("/api/person/getpeople", function (allData) {
var mappedTasks = $.map(allData, function (item) { return new Person(item) });
self.people(mappedTasks);
});
self.save = function(){
$.ajax("/api/person/updateperson", {
data: ko.toJSON({ people: self.people }),
type: "post", contentType: "application/json",
success: function (result) { alert(result) }
});
}
}
ko.applyBindings(new PersonViewModel);
API controller:
[HttpPost]
public bool UpdatePerson(List<Person> person)
{
return mgr.UpdatePerson(person);
}
You need to make sure that the service parameter's names match up with what you're passing.
self.save = function(){
$.ajax("/api/person/updateperson", {
data: ko.toJSON({ person: self.people }),
type: "post", contentType: "application/json",
success: function (result) { alert(result) }
});
}
I am trying to bind an array of values from a check box list to a model that has a property type of byte. So I am returned {"1", "2" , "3"} from check box selections I am needing this in byte format before it reaches my model so it can be passed properly to my model.
Property byte { get; set; }
My Knockout Viewmodel where self.DaysList = ko.observableArray(); is my check box list property.
function ScheduledCommand() {
//data
var self = this;
// An observable is a “JavaScript object that can notify subscribers about changes.”
// When the contents of an observable change, the view is automatically updated to match.
self.ScheduledCommandId = ko.observable();
self.NextOccurence = ko.observable();
self.CommandType = ko.observable();
self.CommandAssembly = ko.observable();
self.IntervalAmount = ko.observable();
self.IntervalType = ko.observable();
self.Catchup = ko.observable();
self.Retry = ko.observable();
self.SendToQueue = ko.observable();
self.Enabled = ko.observable();
self.SelectedCommand = ko.observable();
self.DaysList = ko.observableArray();
var Command = {
ScheduledCommandId: self.ScheduledCommandId,
NextOccurence: self.NextOccurence,
CommandType: self.CommandType,
CommandAssembly: self.CommandAssembly,
IntervalAmount: self.IntervalAmount,
IntervalType: self.IntervalType,
Catchup: self.Catchup,
Retry: self.Retry,
SendToQueue: self.SendToQueue,
Enabled: self.Enabled,
SelectedCommand: ko.observable(),
DaysList: ko.observableArray(),
};
self.Command = ko.observable();
self.Commands = ko.observableArray();
self.get = function () {
$.ajax({
url: '/api/Values',
cache: false,
type: 'GET',
contentType: 'application/json; charset=utf-8',
data: {},
success: function (data) {
self.Commands(data); //Put the response in ObservableArray
$("#btnGetCommands").hide();
$("#commandlist").show();
$("#btnHideCommands").show();
}
});
}
self.hidecommands = function ()
{
$("#btnGetCommands").show();
$("#btnHideCommands").hide();
$("#commandlist").hide();
}
//ko.bindingHandlers.bootstrapPopover = {
// init: function (element, valueAccessor, allBindingsAccessor, Command) {
// var options = valueAccessor();
// var defaultOptions = {};
// options = $.extend(true, {}, defaultOptions, options);
// $(element).popover(options);
// }
//};
self.create = function (formElement) {
if (Command.NextOccurence() != "" && Command.CommandType() != "" && Command.CommandAssembly() != "") {
$.ajax({
url: '/api/Values',
cache: false,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: ko.toJSON(Command),
success: function (data) {
// alert('added');
self.Commands.push(data);
self.DaysList("");
self.NextOccurence("");
self.CommandType("");
self.CommandAssembly("");
self.IntervalAmount("");
self.IntervalType("");
self.Catchup("");
self.Retry("");
self.SendToQueue("");
self.Enabled("");
alert("Command " + self.CommandType() + " successfully created.")
}
}).fail(
function (xhr, textStatus, err) {
alert(err);
});
}
else {
alert('Please Enter All the Values !!');
}
},
self.selectCommand = function (command) {
self.SelectedCommand(command.ScheduledCommandId)
alert(command.ScheduledCommandId);
},
document.getElementById("btnGetCommands").onclick
}
$(document).ready(function () {
// When the DOM is fulled loaded, call the ko.applyBindings function and pass
// in a new instance of the commandViewModel:
$("#btnHideCommands").hide();
$("#commandlist").hide();
ko.applyBindings(new ScheduledCommand());
// The ko.applyBindings method activates Knockout and wires up the view-model to the view.
});
My API Controller Method this has no value for DaysList
public HttpResponseMessage Post(ScheduledCommand model)
{
repo.Add(model);
var response = Request.CreateResponse<ScheduledCommand>(HttpStatusCode.Created, model);
string uri = Url.Link("DefaultApi", new { id = model.ScheduledCommandId });
response.Headers.Location = new Uri(uri);
return response;
}
Finally my check box list.
#foreach (var item in ViewData["checklist"] as IEnumerable<SelectListItem>)
{
<div class="checkbox">
<label>
<input type="checkbox" data-bind="attr: { value: #item.Value}, checked: $root.DaysOfWeek">
#item.Text
</label>
</div>
}
The Knockout side of it is good it returns what I want but I can not convert it to a byte.
Thank you for your time!
What I wanted to do was try to convert a knockout observable array to a byte before it was passed to server in order to satisfy the parameter type(small int). Instead, what I did was create a "placeholder"(string array) property and convert it to a byte to satisfy my data property.
I was just hoping to remove the additional step using javascript.
I'm new to web application development and i need to bind values which i retrieved from json object. i tried several ways but couldn't able to bind values to my combo box.
<script type="text/javascript">
var ViewModel = {
CheckIn : ko.observable(),
CheckOut: ko.observable(),
Lunch: ko.observable(),
Rest: ko.observable(),
WorkOnProject: ko.observable(),
Projects: ko.observableArray()
};
this.GetProjects = function () {
$.ajax({
type: "POST",
url: 'TimeRecord.aspx/ReturnComplexType',
data: {},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (arg) {
for (var i = 0; i < arg.d.length ; i++) {
var value = arg.d[i].ProjectCode;
var option = new Option(arg.d[i].ProjectCode, arg.d[i].ProjectCode);
Select1.add(option, null);
}
},
error: function (arg) {
}
});
};
ko.applyBindings(ViewModel);
</script>
My HTML Code:
<tr>
<td class="auto-style1">Project Code </td>
<td ><select id="Select1" data-bind='options: Projects' style="width: 312px"></select>
<button data-bind='click: GetProjects'>Cancel</button>
</td>
</tr>
My Sever Side Coding :
[WebMethod]
public static object ReturnComplexType()
{
List<Project> projects = new List<Project>();
Project p = new Project();
p.ProjectID = 1;
p.ProjectCode = "ABC";
p.ProjectName = "Test";
projects.Add(p);
Project p2 = new Project();
p2.ProjectID = 2;
p2.ProjectCode = "DEF";
p2.ProjectName = "xsd";
projects.Add(p2);
return projects;
}
Your structure is way off, you're mixing object instances with function on the window object..
This is one way of solving it
ViewModel = function() {
this.CheckIn = ko.observable();
this.CheckOut = ko.observable();
this.Lunch = ko.observable();
this.Rest = ko.observable();
this.WorkOnProject = ko.observable();
this.Projects = ko.observableArray()
};
ViewModel.prototype = {
GetProjects: function () {
$.ajax({
type: "POST",
url: 'TimeRecord.aspx/ReturnComplexType',
data: {},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
this.Projects(data);
}.bind(this),
error: function (arg) {
}
});
};
};
ko.applyBindings(new ViewModel());
What I did was to move the GetProjects function to the model object
Your select box is bound to the Projects observable but you don't set an explicit text/value
<select id="Select1" data-bind='options: Projects, optionsText: 'ProjectName', optionsValue:'ProjectID', value: SelectedProjectId"' style="width: 312px"></select>
The SelectedProjectId would be another observable in your model if you need to save the value somewhere.
The other thing you'll want to change is filling the actual observable array instead of select box directly.
<script type="text/javascript">
function ViewModel() {
var self = this;
self.CheckIn = ko.observable();
self.CheckOut = ko.observable();
self.Lunch = ko.observable();
self.Rest = ko.observable();
self.WorkOnProject = ko.observable();
self.Projects = ko.observableArray();
};
var VM = new ViewModel();
ko.applyBindings(ViewModel);
$.ajax({
type: "POST",
url: 'TimeRecord.aspx/ReturnComplexType',
data: {},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (arg) {
for (var i = 0; i < arg.d.length ; i++) {
VM.Projects.push(d[i]);
}
},
error: function (arg) {
}
});
</script>
After you get things binding right you'll probably want to swap out the VM.Projects.push() for a speedier way.
Calling .push() when you're filling up arrays on initial load triggers a ton of notifications that can really make the page crawl.
I have a grid and a select control on the page. Choosing any select value triggers grid update. That updating is done using computed. Can I manually trigger grid to update, say, in situation when a new value is added to a grid?
function vm(){
var self = this;
self.items = ko.observableArray([]);
self.chosen_category = ko.observable("");
self.pager = {
page_namber : ko.observable(1),
page_size : ko.observable(10)
};
self.sort = {
field : ko.observable('name'),
dist : ko.observable('asc')
};
// etc.
self.fetch = ko.computed(function(){
$.ajax({
url: '/api/items/',
type: 'GET',
data: ko.toJSON(self),
contentType: 'application/json',
success: self.items
});
}, self);
self.add_item = function() {
//here I want to update the grid
self.fetch(); // not work
};
}
Sure I can move it to a separate function but I am looking for a cleaner solution.
Thanks!
working version :
function vm() {
var self = this;
self.items = ko.observableArray([]);
self.chosen_category = ko.observable("test");
self.pager = {
page: ko.observable(1),
size: ko.observable(10)
};
self.sort = {
field: ko.observable('name'),
dist: ko.observable('asc')
};
self.fetch = function () {
var data = {
category: self.chosen_category(),
pager: ko.toJS(self.pager),
sort: ko.toJS(self.sort)
};
$.ajax({
url: '/api/items/',
type: 'POST',
data: ko.toJSON(data),
contentType: 'application/json',
success: self.items
});
};
self._auto_update = ko.computed(self.fetch).extend({ throttle: 1 }); ;
self.add_item = function () {
self.fetch();
};
}
It is better to do this with subscription instead of computed. In that case you can define fetch function to use for both subscription and manual call:
function vm(){
var self = this;
self.items = ko.observableArray([]);
self.chosen_category = ko.observable("");
self.fetch = function(){
$.get('/api/items/' + self.chosen_category(), self.items);
};
self.chosen_category.subscribe(self.fetch);
self.add_item = function() {
//here I want to update the grid
self.fetch();
};
}
Also you can do the same with computed:
function vm(){
var self = this;
self.items = ko.observableArray([]);
self.chosen_category = ko.observable("");
self.fetch = function(){
$.get('/api/items/' + self.chosen_category(), self.items);
};
self.doStaff = ko.computed(self.fetch);
self.add_item = function() {
//here I want to update the grid
self.fetch();
};
}