2
votes

Sorry if this is a repeat but I was going through the documentation on Breezejs.com and I wanted to see if I could get a bit of an elaboration on 'best practice'

I am using .extend to load up some navigation properties on a parent object. When I want to add an entity to that observable array I am using a modal pop-up. I see the blank entity added on my view that calls the modal, but when I close the modal after creating the entity and saving the observable array doesn't update and just leaves the main page's new entity blank.

http://www.breezejs.com/documentation/navigation-properties says that using .push() into the Observable array will add the object to the array so just wanted to get an idea whether I am doing this correctly or there is a better method. The reason it seems funny is that I have to return the entity from my modal back to my parent view and then push it, and thought maybe there was a better method.

Edit

From my parent view model, I use Durandal.js's app.js to show a modal.

var addComment = function () {
    rfcommentcreate.responseFormId(responseForm().id());
    app.showModal(rfcommentcreate).then(function (modalResult) {
        if (!modalResult) { datacontext.cancelChanges(); return false; }
        console.log(modalResult);  // Just to make sure the result is not null and of the right type
        responseForm.responseFormResponseFormComments.push(modalResult);
        return true;
    });
};

When I save on the modal I pass the created object back.

    datacontext.saveChanges()
        .fail(initFailed)
        .fin(complete);

    function complete() {
        self.modal.close(responseFormComment());  // responseFormComment is the entity that I work on in the modal
    }

ResponseForm.ResponseFormResponseFormComments is the navigation property of ResponseForm.

The above code adds the entity to Breeze's entity manager but Knockout is not tracking it after it is created. This appears to be a true statement because in my Html on the parent view I see something like this

: @

from the HTML code

<span data-bind="text: user().fullName"></span> : <span data-bind="text: message"></span> @ <span data-bind="DateTime: commentDt"></span>

After I create the entity in the modal

According to the navigation-properties page on breezejs.com that should work if I am interpreting it properly.

A: It does not, and is probably my fault B: Is there a better method to keeping track of navigation properties without having to 'push' them into an array?

Notice that we pushed to Orders and not Orders().

3
Could you prepare a small sample, preferably in jsFiddle or Plunkr. It's difficult for us to understand the use case w/o the aid of some code.Ward
Sorry I could not find a good way to post the code I am using in jsFiddle (no Durandal referencing) but I posted some code above that MAY help to show the conundrum.PW Kad
Ward - do you think it is possible I am breaking knockout's binding when I am creating the comment in the entityManager? For example if I create the comment like this - return manager.createEntity('ResponseFormComment', { responseForm: responseForm, user: user }); like I said it's like KnockOut sees that an entity is made but it's like the binding to the ever so redundant responseFormResponseFormComments is brokenPW Kad

3 Answers

2
votes

There can be timing issues with KO. I know it's kludgy but you might try the following (btw, I changed the name of the function parameter because modalResult is not intuitive to me):

app.showModal(rfcommentcreate).then(function (comment) {
        if (!comment) { datacontext.cancelChanges(); return false; }
        console.log(comment);  // Just to make sure the result is not null and of the right type
        responseForm.responseFormResponseFormComments.push(comment);
        return Q.delay(true,5); // return true after 5 ms to get another JS event loop cycle in.
    });

My suggestion is in the last line:

return Q.delay(true,5); // return true after 5 ms to get another JS event loop cycle in.

See the Q.delay method in the Q API reference. What I'm doing is giving KO a chance to hear the event raised by Breeze's update of the array and respond accordingly.

If there is a back navigation from ResponseFormComment to ResponseForm, don't think I would push into the navigation property (is it really called responseFormResponseFormComments? "responseForm" twice?), not that there is anything wrong with that.

I'd rather write:

comment.responseForm(responseForm); // entity assignment

or

comment.responseFormId(responseForm.id); // foreign key assignment

Both have the intended side-effect of updating the responseForm's comments collection.

But back to the main issue ... try the delay and let us know if that works. Sometimes KO and Breeze get their timing mixed up.

2
votes

Not sure exactly what you are doing, but you should NOT need to requery, or save and refresh, to get your entity. I am guessing that you have some issues with your view model. Try performing your add/push logic without any UI and see if the issue goes away. My guess is that it will. If so, then you need to take a closer look at your binding logic.

1
votes

Thanks to Ward's help I was able to better pin point the issue. Having to use .push was a work around that wasn't really working anyway. My problem was that I was creating the entity and assigning the navigation property while creating it, when in fact I needed to create it and then assign the navigation property -

// *Goto the data context and create a 'comment' and assign the current user*    

rfcommentcreate.responseFormComment(datacontext.createResponseFormComment(shell.currentUser()));

// *Assign the navigation property back to the current responseForm after creation*

rfcommentcreate.responseFormComment().responseForm(responseForm());
// *Show the modal, while making edits in the modal Knockout is still bound back to the parent properly*

app.showModal(rfcommentcreate).then(function (comment) {
        if (!comment) { datacontext.cancelChanges(); return false; } // If user cancels the dialog cancel changes (actually probably not needed)
        return true;
    });

Before I was showing a modal and then creating the comment linked back to the responseForm that was passed in and I think it was breaking the parent's Knockout bindings.