JSFiddle - React, Tailwind, and code Playground

by Doug Hill

HTML

<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.1.0.js"></script>
<script src="http://ivaynberg.github.io/select2/select2-3.4.1/select2.js"></script>
<link rel="stylesheet" href="http://ivaynberg.github.io/select2/select2-3.4.1/select2.css">
<label for="txtManagers">Managers:</label>
<br />
<input id="txtManagers" data-bind="
    value: myTags, 
    select2Value: selectedTags,
    select2: { 
        tags: ko.toJS(Tags), 
        minimumInputLength: 1, 
        tokenSeparators: [',', ' '] 
    }
" style="width: 300px;" />
<br />
<hr />
<div>Local Selected: <span data-bind="text: managerNames"></span>

</div>
<hr />
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>

CSS

#txtManagers {
    width: 300px;
}

JavaScript

ko.bindingHandlers.select2 = {
    init: function (element, valueAccessor) {
        var options = ko.utils.unwrapObservable(valueAccessor());

        $(element).select2(options);
        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            $(this).select2('destroy');
        });
    },
    update: function (element, valueAccessor) {
        $(element).trigger('change');
    }
};
ko.bindingHandlers.select2Value = {
    update: (function () {
        var unwrap = ko.utils.unwrapObservable,
            contains = function (array, otherItem) {
                return !!ko.utils.arrayFirst(array, function (item) {
                    var id1 = unwrap(item.id), id2 = unwrap(otherItem.id);
                    return id1 && id2 && id1 === id2;
                });
            },
            isObservableArray = function (obj) {
                // close enough
                return ko.isWriteableObservable(obj) && obj.push && obj.remove;
            };

        return function (element, valueAccessor) {
            var targetObservable = valueAccessor();

            if (!isObservableArray(targetObservable)) {
                return console.warn("select2Value binding is supposed to be an ko.observableArray!");
            }

            $(element).change(function (event) {
                if (event.added && !contains(targetObservable, event.added)) {
                    targetObservable.push(event.added);
                } else if (event.removed && contains(targetObservable, event.removed)) {
                    targetObservable.remove(event.removed);
                }
            });
        };
    })()
};

function ViewModel(tags) {
    var self = this;

    self.Tags = ko.observableArray(tags);
    self.myTags = ko.observable();
    self.selectedTags = ko.observableArray();
    self.managerNames = ko.computed(function () {
        return ko.utils.arrayMap(self.selectedTags(), function (tag) {
            return tag.text;
        });
   ...