http://stackoverflow.com/questions/43123785/knockout-observable-array-not-being-observed

by jlspake

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
Is Loaded: <span data-bind="text: isLoaded"></span><br/>
Has Roles: <span data-bind="text: SelectedUserHasRoles()"></span><br/>
selectedUser: <span data-bind="text: ko.toJSON($root.selectedUser())"></span><br/>
<!-- ko if: isLoaded -->
  <h3 data-bind="text: $root.selectedUser().username"></h3>
  <!-- ko if: SelectedUserHasRoles() -->
  <div class="roles-wrapper" data-bind="foreach: $root.selectedUser().roles()">
    <div class="role-token" data-bind="text: name()"></div>
  </div>
  <!-- /ko -->
<!-- /ko -->

JavaScript

function UsersViewModel() {
  var self = this;
  // data with some removed for brevity
  self.isLoaded = ko.observable(false);
  self.users = ko.observableArray([]);
  self.roles = ko.observableArray([{name: 'Admin'}, {name: 'Minion'}]);
  self.userAvailableRoles = ko.observableArray([]);
  self.selectedUser = ko.observable();
  self.SelectedUserHasRoles = ko.computed(function () {
    if (self.isLoaded()) {
      return self.selectedUser().roles().length > 0;
    }
    return false;
  });

  self.UserHasAllAvailableRoles = ko.computed(function () {
    if (self.isLoaded()) {
      return self.userAvailableRoles().length === 0;
    }
    return false;
  });

  // isLoaded gets set to true when AJAX call to server
  // is a success and data is returned

  // operations with some removed for brevity
  self.setCurrentUser = function (user) {
    const newRolesArray = self.roles().filter(function (role) {
      //return !contains(user.roles(), role);
      return user.roles().indexOf(role) >= 0;
    });
    self.userAvailableRoles(newRolesArray);
    self.selectedUser(user);
    self.isLoaded(true);//Debugging bypass
  }
  
	self.newUsernameText = ko.observable('New User');
  self.addUser = function () {
    self.users.push(new User({ Username: this.newUsernameText(), Roles: [{name: 'Minion'}] }));
    self.newUsernameText('');
    //self.NewUserFormIsVisible(false);
    //self.AddRolesFormIsVisible(true);
    self.setCurrentUser(self.users()[self.users().length - 1]);
  };
}

function User(data){
		var self = this;
    this.username = ko.observable(data.Username);
    this.roles = ko.mapping.fromJS(data.Roles);
    
    setTimeout(function(){
    	self.roles.push({name: ko.observable('Admin')});
    }, 1000);
}

var viewModel = new UsersViewModel();
ko.applyBindings(viewModel);
setTimeout(function(){
	viewModel.addUser();
}, 500)