vasigorc
vasigorc

Reputation: 962

Knockout.js: combining "visible" and multiple view models

I have spent some time trying to unscramble this issue. I have a page that I would like to be used by a beauty salon owner to manage two things:

  1. Appointments
  2. Days with special schedule

To select a 'view' I am using a toggle that is based on Knockout's visible binding:

enter image description here

So when a radio button is clicked a div is being rendered and another hidden:

<div id="selectingScopes" class="col-xs-6 col-md-4">
            <fieldset>
                <legend>View:</legend>
                <div id="radioControls" class="switch-toggle well">
                    <input jsf:id="appointmentsRadio" name="appointmentsRadio" type="radio"
                           data-bind="checked: selectedScope" value="#{bigcopy.appointmentsLabel}"/>
                    <label for="appointmentsRadio" onclick="">#{bigcopy.appointmentsLabel}</label>

                    <input jsf:id="specialdaysRadio" name="specialdaysRadio" type="radio"
                           data-bind="checked: selectedScope" value="#{bigcopy.specialDaysLabel}"/>
                    <label for="specialdaysRadio" onclick="">#{bigcopy.specialDaysLabel}</label>

                    <a class="btn btn-primary"></a>
                </div>
            </fieldset>
       </div>
<div id="appointmentsModel" class="row" data-bind="fadeVisible: selectedScope()==='#{bigcopy.appointmentsLabel}'">
        <ui:include src="includes/appointmentsManagement.xhtml"/>
    </div>
    <div class="row" data-bind="fadeVisible: selectedScope()==='#{bigcopy.specialDaysLabel}'">
        <ui:include src="includes/specdaysManagement.html"/>
    </div>

In the same time I want to bind the "appointmentsModel" div above to a different view model that will be responsible only for managing the table of appointments that have to be uploaded from the server. This is the js file sifted of irrelevant clutter:

var restServiceRoot = "localhost:8080/RimmaNew/rest";

var scopeSelector = {
selectedScope: ko.observable()
};

ko.applyBindings(scopeSelector);
//appointments part
//Initial load
function appointmentsModel() {
var self = this;
self.serviceURL = restServiceRoot + "/appointments";
self.Appointments = ko.observableArray([]);
$.ajax({
    url: self.serviceURL,
    type: 'get',
    data: null,
    dataType: 'json',        
    success: function (appointments) {
        var parsed = JSON.parse(appointments);
        var appointmentsArray = parsed.current;
        var mappedAppointments = $.map(appointmentsArray, function(item){
            return new Appointment(item);
        });
        self.Appointments(mappedAppointments);
    },
    error: function (xhr, ajaxOptions, thrownError) {
        var err = xhr.responseText;
        alert(err);
    }
});
}

var appointmentsModelImpl = new appointmentsModel();
ko.applyBindings(appointmentsModelImpl, document.getElementById('appointmentsModel'));

My code is inspired of two books: Knockout.js (O'Reilly - Jamie Munro) and Java EE and HTML 5 Enterprise Application Development (Oracle Press) that barely touch upon the topic of having cross-bindings in KO. I equally didn't find official KO documentation to be helpful in this endeavor.

There is a stackoverflow ticket that dealt with a similar issue, but in one it was the author who answered himself - his explanation made perfect sense to himself, but the mentions of 'stopBinding' and 'controlsDescendantBindings' seemed taken out of context to the two bindings that he uses below...I can't see how to apply this to my problem...

So you would make me a huuge favor if you could either

  1. direct me to a resource where I could educate myself on how to use cross-bindings in KO
  2. Or guide me in how can I mend my code to be able to control the visibility of these two divs and apply a viewmodel to each of them

Doing both would be fantastic.

1 The full code for the original page (xhtml) is here

2The js file

3The js 'classes' file

4The enclosed page with the 'appointments' table

Upvotes: 0

Views: 303

Answers (1)

runfaj
runfaj

Reputation: 392

Your best bet will probably be to think of your models a little bit differently. Instead of doing a separate model binding, it may make more sense to do a default appointmentsModel, then update the observables inside that.

What I would do is have a single parent binding to the body, or a containing div in the body, then submodels for the various children.

Sample JS:

var MyParentModel = function(){
    var self = this;

    self.selectingScopes = {
        scope: ko.observable("");
    };

    self.appointmentModel = {
        param1: ko.observable(),
        param2: ko.observable()
    }
};
ko.applyBindings(new MyParentModel());

Sample HTML:

<div id="appointmentsModel" data-bind="with: appointmentModel"></div>

Upvotes: 2

Related Questions