Load as View or ViewModel?

660 views Asked by At

Using Durandal 2.0.1, Knockout 3.0.0, RequireJS 2.1.10.

The following is background info, just setting the stage:

I have a fundamental question about whether to load a sub item as a view or a view model. I am trying to follow the design printed on the Durandaljs website. I have an index.cshtml page which has a div element named applicationHost which loads shell.html using data-main="App/main" as part of a script tag on index.cshtml.

I am trying to modularize my markup, so inside shell.html, I have a div which loads header.html using:

<!-- ko compose: 'viewmodels/header' -->
<!-- /ko -->

Inside header.html, I have another div which FAILS to successfully load guestSummary.html.

The ViewModel for guestSummary (guestSummary.js) retrieves data and displays a few statistics of interest to guests, which I am attempting to bind to guestSummary.html using Knockout.

Because of the data lookup and binding needed for the controls in guestSummary.html, I thought I would need to load guestSummary.html using the following code (inside header.html):

<!-- ko compose: 'viewmodels/guestSummary' -->
<!-- /ko -->

When I try that, I get the following error message (from the console tab in Google Chrome developer tools), "Uncaught Error: Failed to load composed module (viewmodels/guestSummary). Details: model is not defined".

Looking at the Durandaljs website, it says, "Each page in our navigation application is comprised of a view and a view model. Once you've set up the structure as described above, all there is to extending the application is dropping new view models in the viewmodels folder along with an appropriate view in the views folder. Then, you just register them with the router in main.js. When the corresponding route is navigated to, the router will locate your module and the composition infrastructure will see to it that it's bound and inserted into the DOM".

The above guidance seems to indicate I should use a view instead of a view model, since I'm NOT attempting to navigate to the guestSummary.html page, and it doesn't seem I would need to add the model to the router and I'm not really using the router for navigating to the guestSummary.html page.

Since guestSummary needs data and data binding, would I be better off trying to load guestSummary.html as a VIEW and data-binding to a $parent (or $parent.parent, etc) property, instead of trying to combine the guestSummary.js file with the guestSummary.html file and load the two as a VIEWMODEL?

Is there a better way to do what I'm trying to accomplish? Thanks in advance for any help you might be willing to share.

1

There are 1 answers

1
user2864740 On

You can bind views to existing view-model objects if they do not need/warrant their own view-model. This is discussed, albeit briefly, in Using Composition.

Composing Explicit Models and Views [when an object is supplied to the compose binding ..]

If a view property exists, but no model property, the view will be resolved and bound to the bindingContext, then injected into the element .. If both model and view properties exist, then they will be bound and injected into the element ..

For example, to bind a model explicitly..

compose: {
    view: 'views/guestSummary',
    model: somethingThatResolvesToARelevantModelInThisContext
}

The $root in the view will be the model value.

I recommend never using $parent properties as it just turns code into a mess. Instead use binding names where applicable (e.g. each-bindings) and withProperties - in this case I would even use withProperties on $root to provide a name with more meaning.