0

I am trying to work out how I bind multiple models from a master model to different parts of my HTML mark up. The HTML part is:-

   <ul data-bind="foreach: { data: members}">
        <li>
            <span data-bind="text: MemberId"></span>
            <span data-bind="text: Name"></span>
            <span data-bind="text: SwagCompany"></span>
            <span data-bind="text: SwagThing"></span>
        </li>
    </ul>

<span data-bind="text: winner.Name"></span>

But can't work out how to bind the winner.Name, my model looks like this:-

var masterViewModel = {
   vmA : { ...},
   vmB : { ... }
}

ko.applyBindings({
      winner: ko.observable(masterViewModel.vmB),
      members: ko.observableArray(mappedData),
      ...
    }

Obviously I am misunderstanding how to applyBindings correctly. I have the following code as a plunker showing an example of what I am trying to do:-

<script>
$(function () {

    var masterViewModel = {
        vmA: function memberViewModel(data) {
            this.Id = data.MemberId;
            this.MemberId = ko.observable(data.MemberId);
            this.Name = ko.observable(data.Name);
            this.SwagCompany = ko.observable("");
            this.SwagThing = ko.observable("");
            this.Photo = ko.observable(data.Photo);
        },
        vmB: {
            Name: "Initial winner..."
        }
    };

    $.getJSON("/home/memberlist")
        .then(function (rawData) {
            return ko.utils.arrayMap(rawData, function (instanceData) {
                return new masterViewModel.vmA(instanceData);
            });
        })
        .done(function (mappedData) {
            doit(mappedData);
        });

    function doit(mappedData) {
        ko.applyBindings({
            winner: ko.observable(masterViewModel.vmB),
            members: ko.observableArray(mappedData),
            getNextWinner: function () {
                var members = this.members();
                var winner = this.winner();
                //console.log(ddd.Name());
                $.getJSON("/home/nextwinner")
                    .then(function (rawData) {
                        var nextWinner = ko.utils.arrayFirst(members, function (member) {
                            return member.Id === rawData.Winner.MemberId;
                        });
                        nextWinner.SwagThing(rawData.WonSwag.Thing);
                        nextWinner.SwagCompany(rawData.WonSwag.Company);
                        winner.Name(rawData.Winner.Name);
                    });
            }
        });
    }
});
</script>
1
  • I agree with @xdumaine's answer. If you're applying the MVVM pattern correctly you should only need to create and bind a view model once. Rather than trying to change the content of the page by re-binding to a new view model instance, you should be able to simply modify the view model instance that was bound when the page was loaded. Commented Jan 18, 2014 at 4:30

1 Answer 1

4

Your code is very messy, as you're creating a viewModel object within your applybindings call, and creating viewModel objects directly. Use the constructor syntax, and create new instances of your viewmodels. All you need to do for applyBindings is give it a single instance of your master view model.

Use this JSFiddle as an example, and try to keep your code structured and organized, or it will get extremely messy very quickly.

// this is like a constructor for your members
var memberViewModel = function memberViewModel(data) {
   var self = this;
   self.Id = data.MemberId;
   self.MemberId = ko.observable(data.MemberId);
   self.Name = ko.observable(data.Name);
};

// This is like a constructor for your master view model
var masterViewModel = function() {
   var self = this;
   self.Members = ko.observableArray();

   // put two members into Members
   self.Members.push(new memberViewModel({MemberId: 1, Name: 'Member1'}));
   self.Members.push(new memberViewModel({MemberId: 2, Name: 'Member2'}));

   // set the winner to the first one for default, if you want
   self.Winner = ko.observable(self.Members()[0]);

   //do your ajax in this function
   self.GetNextWinner = function() {
     self.Winner(self.Members()[1]);
   }
};

//Apply bindings gets one instance of your view model
ko.applyBindings(new masterViewModel());
Sign up to request clarification or add additional context in comments.

4 Comments

Great, one quick question if Winner was split into several properties would you introduce a second view model or would you do something like self.Winner ... Self.WinnerSwag ... self.WinnerSwagThing and then in the GetNextWinner function set each one manually?
@Rippo If I understand correctly, it really shouldn't matter, you could just keep those on the master view model, or split them into a separate object. I'm inclined to say keep them in the master view model, unless they are all a part of a single object entity. It looks like those properties are really for UI display/action, in which case they should go in the master view model.
Thanks, I suppose I am saying Winner has around 6 properties and from a C# perspective I would create a child class called winner and have Winner.Name and Winner.Photo and Winner.DOB etc etc. So you are saying I can create a separate child object called Winner ?
@Rippo Yeah, definitely, it makes sense for that. Properties of the Winner should be on their own Winner object, but properties for the winner shouldn't - something like a property that holds a string for the instructions, or a button click handler.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.