0
votes

There are a few questions around on this but none of them (that I've found) have been fully answered/resolved yet.

So in classic asp.net I'd have a model/class that represented the database table I'm trying to create - say a new customer. In my .net view/page I'd have a button to "add new" and this would clear out all the customer fields (name, address, phone number, email, website, etc.) and allow user entry. When the user fills in the fields and clicks on the "Add >" button, I'd validate the entries and then call an "add customer" routine, passing in the new customer record/entity I wanted creating. To make it easier I'd have the "add customer" method take a customer object as a parameter and would use the customer class I already have in my entity/linq model to achieve this.

All dead simple, vanilla, "create new" functionality.

So in breeze/knockout I'm struggling to see the way to do this without an alarming amount of redefinition/repetition. If I have a "newcustomer.html" view and a matching "newcustomer.js" viewmodel then how can I expose a blank or empty customer entity to "value:" bind to the form fields? I can happily read the database and display the returned customer entity in the form fields via a "data-bind: text..." type approach but at the point of creating a new customer I want a blank customer entity, not one returned from a database read.

So I know that one suggestion Ward makes is to have an item viewmodel which I validate and then pass on to the background "create entity" breeze method if it passes validaton but this is where my perception is that I'd have to redefine/repeat all the existing model fields in the viewmodel to achieve it. Surely I'd need a whole list of observables:

var customerName = ko.observable('');
var customerAddress1 = ko.observable('');
var customerAddress2 = ko.observable('');
var customerTown = ko.observable('');
etc...

And as I already effectively have this same model/class defined in my project, why would this be an efficient or acceptable way to approach this? Is there no way to have the "newcustomer" view bind to an instance of the existing breeze entity model? This would be awful to maintain in the event that the database changed as I'd need to manually edit all my item viewmodels to match!

I may, of course, be hugely missing the point here...

EDIT: On reading a bit further, it looks like maybe creating a detached entity and binding that to the knockout form could be a way forward. It appears that my desired method is similar to the one mentioned in this question: creating/updating breeze entities with one-to-one relationship but, frustratingly, the questioner's question about whether the detached entity > bind > edit fields > add detached entity to manager > savechanges is a recommended workflow is unanswered.

As Ward himself was participating in the question and didn't freak out at the suggestion, maybe it's ok? Again, frustratingly, I note that Ward is perplexed at why the OP creates the detached entity when this seems an entirely correct way of going about doing this. In my mind, creating the entity in an attached state would result in having to delete it if the user decided not to commit to the save. Or am I getting mixed up and "attached" does not actually create the entity at that point and that doesn't happen until "save changes" happens on the manager?

1

1 Answers

0
votes

I have never used Breeze so I am not sure if this is applicable to your problem, but if I have a viewModel that is used by the view but will get data asynchronously I usually solve it like this:

var CustomerModel = function (data) {
    this.name = ko.observable('');
    this.address1 = ko.observable('');
    this.address2 = ko.observable('');
    this.town = ko.observable('');

    this.init(data);
};

CustomerModel.prototype = {
    init: function (data) {
        if (!data) return;
        this.name(data.name);
        this.address1(data.address1);
        this.address2(data.address2);
        this.town(data.town);       
    }
}

var ViewModel = function () {
    var self = this;
    this.customerModel = new CustomerModel();
    this.getData = function() {
        dataservice.getData()
            .done(function(result) {
                self.customerModel.init(result);
            });
    };
};

var vmInstance = new ViewModel();

ko.applyBindings(vmInstance);

vmInstance.getData();

I've made a fiddle example here: http://jsfiddle.net/danne567/9E9Yk/6/