JSFiddle - React, Tailwind, and code Playground

by Dan Bonelli

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-debug.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.2/jquery.js"></script>
<ul data-bind="foreach: products">
    <li class="product">
      <strong data-bind="text: name"></strong>
      <div data-bind="component: { name: 'like-widget' }"></div>
    </li>
</ul>
 
<script id="like-template" type="text/x-knockout-template">
    <div>
        <div class="like-or-dislike" data-bind="visible: ratingButtonVisible">
            <button data-bind="click: like">Like it</button>
            <button data-bind="click: dislike">Dislike it</button>
        </div>
        
        <div class="result" data-bind="visible: ratingDescriptionVisible">
            You <strong data-bind="text: userRating"></strong> it
        </div>
    </div>
</script>

JavaScript

function Product(name, rating) {
    this.name = name;
    this.userRating = ko.observable(rating || null);
}
 
function MyViewModel() {
    this.products = [
        new Product('Garlic bread'),
        new Product('Pain au chocolat'),
        new Product('Seagull spaghetti', 'like') // This one was already 'liked'
    ];
} 

ko.components.register('like-widget', {    
    viewModel: {
        createViewModel: function (params, componentInfo) {
            var context = ko.contextFor(componentInfo.element);
    
            var self = context.$data;
            
            return ko.utils.extend(context.$data, {
                ratingButtonVisible: ko.computed(function() {
                    return (self.userRating()==null);
                }),
                
                ratingDescriptionVisible: ko.computed(function() {
                    return !(self.userRating()==null);
                }),                
                
                like:   function() {                    
                    self.userRating('like');
                },
                
                dislike:  function() {                    
                    self.userRating('dislike');
                }
            });
        }            
    },
    template: { element: 'like-template' }
});
 
ko.applyBindings(new MyViewModel());