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'>
        <stack-master params="data: modeArrs, options: $root.stackOptions, name: entityType"></stack-master>
    </span>
    <span data-bind="foreach: stacks">
        <stack params="data: $data, options: $root.stackOptions"></stack>
    </span>
</div>
    
</div>

<template type="text/template" id="hover-template">
    <div data-bind="visible: $root.hoverTemplate() == 'hover-template-hovering', template: 'hover-template-hovering'"></div>
    <div data-bind="visible: $root.hoverTemplate() == 'hover-exists-template', template: 'hover-template-exists'"></div>
    <div data-bind="visible: $root.hoverTemplate() == 'hover-template-hover-new', template: 'hover-template-hover-new'"></div>
</template>

<template type="text/template"...

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' }
});

ko.components.register('stack-master', {
    viewModel: function(params) {
    	var self = this;
        this.items = params && params.data || [];
        this.name = params && params.name || "?";
        this.draggingEntity = params && params.options && params.options.draggingEntity || ko.observable(undefined);
        this.dragSourceStack = params && params.options && params.options.dragSourceStack || ko.observable(undefined);
        
        this.startDrag = function(data, e, f) {   
            self.dragSourceStack(undefined);
            self.draggingEntity(ko.dataFor(this));
        }

        this.endDrag = function(data, event) {
            self.dragSourceStack(undefined);
            self.draggingEntity(undefined);
        }
    },
    template: { element: 'stack-master-template' }
});


ko.components.register('stack', {
    viewModel: function(params) {
    	var self = this;

        // params
       ...