JSFiddle - React, Tailwind, and code Playground

by ivanov_vitaly

HTML

<div id="holder">
    
    <ul id="filtersholder" data-bind='foreach: filters'>
        <li>
            <div class="filter-template">
                <input type="button" class="delete-filter" value="-"
                    data-bind="click: function() { $root.removeFilter($data); }" />
    
                <select data-bind="options: $root.columns,                                
                                   optionsValue: Column,
                                   optionsText: 'Display',
                                   value: ColumnObj">
                </select>
    
                <select class="opperator"
                    data-bind="options: AvailableConditions, 
                               value: Condition">
                </select>
                
                <input type="text" data-bind="value: Value" />            
    
                <select style="width: 54px;" 
                    data-bind="options: $root.nextFileterBinaryConditions,
                               value: NextFileterBinaryCondition">
                </select>
    
                <input type="button" class="add-filter" value="+"
                        data-bind="click: function() { $root.addFilter($data); }" />
            </div>
        </li>
    </ul>
    
    <p>
        <input type="button" id="submitFilters"  value="Submit" data-bind="click: postFilters" />
    </p>

</div>

CSS

#filtersholder, #submitFilters {
    margin: 10px;
}
.delete-filter, .add-filter {
    width: 24px;
    height: 24px;
}

.opperator {
    width: 80px;
}

JavaScript

function ViewModel(columnsSource) {
    this.nextFileterBinaryConditions = ['AND', 'OR'];
    this.columns = ko.observableArray(columnsSource);
    this.filters = ko.observableArray([new Filter()]);

    this.addFilter = function(filterObj) {
        var invalidFilter = ko.utils.arrayFirst(this.filters(), function (filter) {
            return filter.IsValid() === false;
        });
    
        if (invalidFilter == null) {
            var currentIndex = ko.utils.arrayIndexOf(this.filters(), filterObj);
            this.filters.splice(currentIndex + 1, 0, new Filter());
        }
    };

    this.removeFilter = function(filterObj) {
        this.filters.remove(filterObj);

        if (this.filters().length == 0) {
            this.addFilter();
        }
    };

    this.postFilters = function() {
        var items = ko.toJS(this.filters());
        var mappedItems = ko.utils.arrayMap(items, function(filter) {
            delete filter.ColumnObj;
            delete filter.AvailableConditions;

            return filter;
        });

        alert(ko.toJSON(mappedItems));
    };
};