I have an ASP.NET MVC app that uses durandal, knockout.js, and breeze on the client. I have an issue that I'm encountering repeatedly, and yet I haven't found any mention of it anywhere. Not sure if I've gotten myself into a unique situation, or if I'm just not searching the right way.
I need to know how to delete a Breeze entity from an observableArray so that the commit succeeds (see Option A below) and the UI reflects the change (see Option B below).
I have the following models (abbreviated):
public class Donor
{
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public virtual IList<Contact> Contacts { get; set; }
}
public class Contact
{
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[ForeignKey("Donor")]
public int? DonorId { get; set; }
public virutal Donor Donor { get; set; }
}
I'm trying to delete a Contact from my Donor. I am having difficulty getting the flow right between Breeze and Knockout so that the item is both removed from the observableArray (with a notification) and also able to be deleted through Breeze.
Here is what I have tried (javascript):
Option A:
function deleteContact(contact){
viewModel.donor().contacts.remove(contact);
contact.entityAspect.setDeleted();
viewModel.uow.commit();
}
When I use this approach, I get the following error from Breeze.WebApi:
Int32Converter cannot convert from System.Int64
I have looked through the stack, and examined the Breeze source code (though I haven't yet configured a solution to step through it), and the error is coming from Breeze.WebApi.EFContextProvider::RestoreOriginal, where it is restoring original property values to the object. I don't know why it thinks my value is an Int64, but I was not able to find a good work-around, so I tried...
Option B:
function deleteContact(contact){
contact.entityAspect.setDeleted();
viewModel.uow.commit();
}
This approach allows me to successfully save the delete (because the item has not been removed from the collection manually, and therefore, doesn't have any "original values"). However, the issue here is that setDeleted effectively removes the item from the observableArray without notifying my knockout bindings that the array has changed. So the item has been removed and deleted, but my UI still shows the item. Future attempts to call donor().contacts.remove(contact) are futile, because the observableArray no longer has the item.
valueHasMutated()on your observable array after using option b? - RobHvar foo = ko.observableArray(["A"]); foo.push("B");This updates the array and DOM.foo().push("C");This only updates the array. Option A does it right, but Option B, from your experience, doesn't. Here's a jsfiddle example. You can see the values were unshifted to each array, but only one updated the DOM. If you addvm.foo.valueHasMutated();after applyBindings, then the DOM updates both, which is the simplified version of what's happening here and why that works. - nwayve