Search code examples
mvvmknockout.jsknockout-2.0master-detail

KnockoutJS and Property-Dependent Create/Edit-View (Master/Detail Scenario)


I am having trouble creating a property-dependent create/edit-view in KnockoutJS.

Here's the thing: everything I create are "People" of sorts - it could be a Healthcare Professional, Plumber, Mechanic or Engineer. Depending on what kind/type of person it is, I need to enter different data.

Here an example:

Healthcare Professional: Name, Telephone, Hospital, etc.
Plumber: Name, Telephone, Crafts, etc.
Engineer: Name, Telephone, Specialities, etc.

What I can do is create properties on my ViewModels such as "showCity", "showHospital" and so on to hide individual form-fields.

However, for the sake of separation, I would like to use entirely different forms: again, I could set the respective form to only show if the condition is met.

However, I would like KnockoutJS to only render the respective form that should be used (the Person's type is always determined when it is first created - it cannot be changed).

What I don't end-up doing is have one form that is shown and ten that are there (and data-bound) but hidden.

I tried using the "if" binding like so: <div data-bind="with: $root.selectedPerson"><form data-bind="if: $data.type='mathematician'"></form></div>, but to no avail.

Would anybody know what the best-practice is in this case?


Solution

  • Your if binding is setting the $data.type value, not comparing it. Try:

    <div data-bind="with: $root.selectedPerson"><form data-bind="if: $data.type() === 'mathematician'"></form></div>
    

    Although this is fine, I always try to avoid code in my data-binding markup. I would try and create a computed that would return the resulting true/false of the comparison, but in your situation, you would need one for each person type, and that would get tricky. For that, I would turn to templates. You could do:

    <div data-bind="template: { name: $root.selectedPerson().type, data: $root.selectedPerson }"></div>
    <script type="text/html" id="mathematician">...</script>
    <script type="text/html" id="plumber">...</script>
    

    *Note: As of KO version 2.3.0, the name property of the template binding can accept observables. If you're using a previous version, be sure to call the observable in the binding: name: $root.selectedPerson().type()