WildflowerJS Demos
Tip Splitter: data-model, data-action, data-bind, data-render, computed

Tip Splitter

One HTML file. One script tag. Live reactivity.

 people
Add at least one person to split the bill.
Each person pays
Tip (%)
Total with tip

Built with wildflower.nano.min.js

HTML

<div data-component="tip-splitter">
    <input type="number" data-model="bill" placeholder="0.00">

    <button data-action="setTip" data-tip="15" data-bind-class="tipClass15">15%</button>
    <!-- ...one preset per rate... -->

    <button data-action="fewer">&minus;</button>
    <span data-bind="people"></span>
    <button data-action="more">+</button>

    <div data-render="tooFew">Add at least one person to split the bill.</div>

    <div class="per" data-bind="perPerson"></div>
    <span data-bind="tipTotal"></span>
    <span data-bind="grandTotal"></span>
</div>

JavaScript

const money = n => '$' + (Number.isFinite(n) ? n : 0).toFixed(2);

wildflower.component('tip-splitter', {
    state: {
        bill: '',
        tip: 15,
        people: 2
    },
    computed: {
        billNum() { return parseFloat(this.bill) || 0; },
        tooFew() { return this.people < 1; },
        tipTotalNum() { return this.billNum * this.tip / 100; },
        grandTotalNum() { return this.billNum + this.tipTotalNum; },
        perPersonNum() { return this.people > 0 ? this.grandTotalNum / this.people : 0; },
        tipTotal() { return money(this.tipTotalNum); },
        grandTotal() { return money(this.grandTotalNum); },
        perPerson() { return money(this.perPersonNum); },
        // Reactive highlight for the active preset button
        tipClass10() { return this.tip === 10 ? 'on' : ''; },
        tipClass15() { return this.tip === 15 ? 'on' : ''; },
        tipClass18() { return this.tip === 18 ? 'on' : ''; },
        tipClass20() { return this.tip === 20 ? 'on' : ''; }
    },
    setTip(event, el) {
        this.tip = parseInt(el.dataset.tip, 10);
    },
    more() { this.people++; },
    fewer() { if (this.people > 0) this.people--; }
});