Knockoutjs.com - Simple list example

http://knockoutjs.com/examples/simpleList.html

by Barry Carter

HTML

<script src="http://knockoutjs.com/downloads/knockout-3.2.0.js"></script>
<script src="https://rawgit.com/rniemeyer/knockout-sortable/master/build/knockout-sortable.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<div class='liveExample'> 
    
<div>
    <div class="subheader">
        <h1>Mode</h1>
        <mode-button params="text: 'Campaign => Team', modeId: 0, mode: mode"></mode-button>
        <mode-button params="text: 'Team => User', modeId: 1, mode: mode"></mode-button>
        <mode-button params="text: 'Queue => User', modeId: 2, mode: mode"></mode-button>
    </div>
    <div>
        Filter On
        <span><input type="checkbox" data-bind="checked: options.filterOnSelected" />Selected</span>
        <span><input type="checkbox" data-bind="checked: options.filterOnDrag" />Drag</span>
        <span data-bind="visible: $root.selectedEntity, click: $root.selectedEntity(undefined)">Reset</span>
    </div>
    <!-- ko with: selectedEntity -->
    <div data-bind="text: name">
    </div>
    <!-- /ko -->
    <p>Your items:</p>
    <span class='tlentity primary'>
        <h2 data-bind="text: entityType"></h2>
        <div data-bind="foreach: $root.modeArrs">
                  <div class='entity' data-bind="
                      draggable: { data: $data, options:{ start: $root.startDrag, stop: $root.endDrag } },
                      click: $root.entity_click, css: { 'selected-entity': $data === $root.selectedEntity() }">
                      <div data-bind="text: name"></div>
                  </div>
        </div>
    </span>
    <span data-bind="foreach: topLevelItems">
      <div class='tlentity' data-bind="visible: $root.tlItemVisible($data), droppable: { data: $root.dropped('normal', $data),
          options: { greedy: true, classes: {'ui-droppable-hover': 'highlight' }, over:...

CSS

body { font-family: arial; font-size: 14px; }
.liveExample { padding: 1em; background-color: #EEEEDD; border: 1px solid #CCC; max-width: 655px; }
.liveExample input { font-family: Arial; }
.liveExample b { font-weight: bold; }
.liveExample p { margin-top: 0.9em; margin-bottom: 0.9em; }
.liveExample select[multiple] { width: 100%; height: 8em; }
.liveExample h2 { margin-top: 0.4em; }

.tlentity {
  display: inline-block;
  width: 150px;
  height: 400px;
  background-color: blue;
  vertical-align: top;
  padding: 2px;
}

.tlentity.primary {
    background-color: green;
    margin-right: 8px;
}

.tlentity h2 {
    font-size:1.5em;
    margin: 3px 3px 10px 1px;
}

.entity-wrap {
  display: block;
}
.entity {
  display: flex;
  width: 150px;
}

.team-primary {
  display: flex;
  width: 10px;
  height: 10px;
  background-color: red;
}

.selected-entity {
  background-color: blue;
}

.drop-entity {
    display: block;
    width: 150px;
    height: 200px;
    background-color: red;
}

.subheader {
    display: inline-flex;    
}

.subheader > h1 {
    font-size: 1.2em;
    font-weight: bold;
    margin: 2px 5px 0px 0px;
}

.subheader mode-button {
    width: 180px;
    margin: 3px;
    border: 1px solid #5a5959;
}

.mode-button-el {
    background-color: #d7d7d7;
    display: inline-flex;
    width: 100%;
}

.mode-button-el.active {
    background-color: green;
}

JavaScript

var users = [{id: 1, name: "Bob", teamIds: [1, 2], primaryTeamId: 1, queueIds: [1,2]},
{id: 1, name: "Jim", teamIds: [1], primaryTeamId: 1, queueIds: [1,3]}, 
{id: 1, name: "Jane", teamIds: [2,3], primaryTeamId: 2, queueIds: [1,2, 3]}];

var teams = [{id: 1, name: "Team 1", campIds: [2]},
{id: 2, name: "Team 2", campIds: [1]}, {id: 3, name: "Team 3", campIds: [2]}];

var camps = [{id: 1, name: "Camp 1"}, {id: 2, name: "Camp 2"},{id: 3, name: "Camp 3"}];

var queues = [{id: 1, name: "Queue 1"}, {id: 2, name: "Queue 2"},{id: 3, name: "Queue 3"}];

ko.components.register('mode-button', {
    viewModel: function(params) {
    	var self = this;
        this.text = params && params.text || '';
	    this.mode = params && params.mode || '';
        this.modeId = params && params.modeId || 0;
        
        this.isActive = ko.pureComputed(function() {
        	return self.mode() == self.modeId ? 'active' : '';
        });

    	this.click = function(data, event) {
    		self.mode(self.modeId)
    	}
    },
    template: { element: 'mode-button-template' }
});


var SimpleListModel = function(items) {
	var self = this;
    var ocamps = ko.mapping.fromJS(camps);
    var oteams = ko.mapping.fromJS(teams);
    var ousers = ko.mapping.fromJS(users);
    var oqueues = ko.mapping.fromJS(queues);
    
	this.topLevelItems = ko.observableArray(ocamps());
    this.mode = ko.observable(0); // start in camp->team
    this.selectedEntity = ko.observable();
    this.selectedTopLevelId = ko.observable();
        
    this.entity_click = function(data, event) {
    		self.selectedEntity(data);
    }
    
    this.modeArrs = ko.observableArray([]);
    this.modeArrPropName = "Id";
    this.entityType = ko.observable("");
    this.modeChange = ko.observable()
    
    this.mode.subscribe(function(d) {
    	var mode = self.mode();
    	if (mode === 0) {
            self.modeArrs(oteams());
            self.modeArrPropName = "campIds";
            self.topLevelItems(ocamps());
           ...