JSFiddle - React, Tailwind, and code Playground

by Satyanshu Acharya

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js"></script>
<body>
     <h1>Hello, Knockout.js</h1>
<p data-bind = 'with: featuredProduct'>
        do you need <strong data-bind = 'text: name'></strong>?<br/>
        get one now for only <strong data-bind = 'text: price'></strong>.    
    </p>
    <span data-bind = 'html: featuredProduct().formattedName'></span>
    <p><span data-bind='text: fullName'></span>'s Shopping cart</p>
    <button data-bind="click: checkOut">Checkout</button>
    <table>
        <thead>
            <tr>
                <th>Product</th>
                <th>Price</th>
            </tr>
        </thead>
        <tbody data-bind="foreach: shoppingCart">
            <tr>
                <td data-bind = 'text: $index'></td>
                <td data-bind="text: name"></td>
                <td data-bind="text:price"></td>
                <!--below binding is breaking the script-->
                <td>
                    <ul data-bind = 'foreach: tags'>
                        <li>
                            <span data-bind = "text: $parent.name"></span>-
                            <span data-bind = 'text: $data'></span>
                        </li>
                    </ul>
                </td>
                <td data-bind = 'if: discount() > 0' style = 'color: red'> You saved <span data-bind = 'text: formattedDiscount, css:{supersaver: discount() > .15}'></span>!!!
                </td>
                <td>
                    <button data-bind="click: $root.removeProduct">Remove</button>
                </td>
            </tr>
        </tbody>
    </table>
    <button data-bind="click: addProduct">Add Item</button>
</body>

CSS

.supersaver{
    font-size: 1.2em;
    font-weight: bold;    
}

JavaScript

function Product(name, price, tags, discount) {

             this.name = ko.observable(name);
             this.price = ko.observable(price);
             tags = typeof(tags) !== 'undefined' ? tags : [];
             this.tags = ko. observableArray(tags);
             discount = typeof(discount) !== 'undefined' ? discount : 0;
             this.discount = ko.observable(discount);
             this.formattedDiscount = ko.computed(function(){
                 return (this.discount()*100) + "%";
             }, this);
             this.formattedName = ko.computed(function(){
                 return "<strong>" + this.name() + "</strong>";
             }, this);

         };

         function personViewModel() {
             var self = this;

             self.firstName = ko.observable("John");
             self.lastName = ko.observable("Smith");
             self.checkOut = function () {
                 alert("Trying to Checkout");
             };

             self.fullName = ko.computed(function () {
                 return self.firstName() + " " + self.lastName();
             })

             self.addProduct = function () {

                 self.shoppingCart.push(new Product("Yogurt", 10.99));

             };

             self.shoppingCart = ko.observableArray([

             new Product("milk", 10.99, null, .20),
             new Product("bread", 7.99,null,.10),
             new Product("Jam", 1.39),
             new Product("Buns", 1.56, ['Baked', 'Hot Dogs'])

             ]);


             //this method is bind with the button and producing error
             self.removeProduct = function (product) {
                 self.shoppingCart.remove(product)
             };
             
             var featured = new Product("Acme BBQ Sauce", 3.99);
    this.featuredProduct = ko.observable(featured);

         };

         ko.applyBindings(new personViewModel);