1
\$\begingroup\$

Please provide some feedback.

Example

Repository

JavaScript

'use strict';

(function ($, ko) {

var init = function () {
    registerCustomBindings();
    var initialData = getData();


    var dayInformation = initialData.DayInfo;
    var studentsInfo = initialData.StudentInfo;

    var minDate = new Date(initialData.StartDate);
    var maxDate = new Date(initialData.EndDate);

    var shopCartInfo = initialData.ShopCartInfo;

    ko.applyBindings(new studentListViewModel(studentsInfo), document.getElementById("students-area"));
    ko.applyBindings(new calendarViewModel(minDate, maxDate), document.getElementById("calendar-area"));
    ko.applyBindings(new tableListViewModel(dayInformation), document.getElementById("tables-area"));
    ko.applyBindings(new shopCartViewModel(shopCartInfo), document.getElementById("shop-cart-area"));
}

function registerCustomBindings() {
    ko.bindingHandlers.appendTextAfter = {
        update: function (element, valueAccessor) {
            var value = ko.utils.unwrapObservable(valueAccessor());
            var text = " " + value + " " + "Shop Cart Items";
            //replace the last child            
            element.replaceChild(document.createTextNode(text), element.lastChild);
        }
    };

    ko.bindingHandlers.kendoCalendar.options = {
        navigate: function () {
            $(".ob-done-date", "#calendar").parent().addClass("ob-done-date-style k-state-hover");
            $(".ob-not-done-date", "#calendar").parent().addClass("ob-not-done-date-style k-state-hover");
        }
    };
}

function getSelectInitialValue() {
    return Number($("#select-students").val() || 0);
}

function getDates() {
    var dates = [];
    dates[+new Date("2015-7-11")] = "ob-done-date";
    dates[+new Date("2015-7-12")] = "ob-done-date";
    return dates;
}

function tableListViewModel(daysInfo) {
    var self = this;
    self.tables = ko.observableArray(ko.utils.arrayMap(daysInfo, function (dayInfo) {
        return new tableViewModel(dayInfo.Name,
            dayInfo.EventId,
            dayInfo.AfterSchoolId,
            dayInfo.Added,
            dayInfo.AddOns);
    }));
}

function shopCartItem(studentId, eventId) {
    var self = this;
    self.studentId = studentId;
    self.eventId = eventId;
}

function shopCartViewModel(shopCartInfo) {
    var self = this;

    self.totalShopCartItems = ko.observable(shopCartInfo.TotalShopCartItems).subscribeTo('total-shop-cart-items');

    self.shopCartItems = ko.observableArray(ko.utils.arrayMap(shopCartInfo.ShopCartItems, function (info) {
        return new shopCartItem(info.StudenId, info.EventId);
    })).publishOn('shop-cart-items');
}

function tableViewModel(name, eventId, afterSchoolId, added, addOns) {
    var self = this;
    self.name = name;
    self.eventId = eventId;
    self.afterSchoolId = afterSchoolId;
    self.added = ko.observable(added);

    self.selectedStudentId = ko.observable().subscribeTo("student-table-channel", function (newValue) {
        return newValue;
    });

    self.shopCartItems = ko.observableArray().subscribeTo('shop-cart-items', function (newValue) {
        return newValue;
    });

    self.totalShopCartItems = ko.observable().publishOn('total-shop-cart-items');

    self.shopCartItems.subscribe(function () {
        var totalItems = self.shopCartItems().length;
        self.totalShopCartItems(totalItems);
    });

    self.addToShopCart = function () {
        if (self.added()) {
            return self.removeFromShopCart();
        }
        self.added(true);
        var studentId = self.selectedStudentId() || getSelectInitialValue();
        var item = new shopCartItem(studentId, self.eventId);
        self.shopCartItems.push(item);
    }

    self.removeFromShopCart = function () {
        self.added(false);
        self.shopCartItems.remove(function (item) {
            return shopCartComparer(item);
        });
    }

    self.addOns = ko.observableArray(ko.utils.arrayMap(addOns, function (addOn) {
        return new addOnViewModel(addOn.Name,
            addOn.EventId,
            afterSchoolId,
            addOn.Fee,
            addOn.Added);
    }));

    self.isInShopCart = ko.computed(function () {
        var valorStudent = self.selectedStudentId();
        var itemInShopCart = ko.utils.arrayFirst(self.shopCartItems(), function (item) {
            return shopCartComparer(item);
        });
        var result = (itemInShopCart) ? true : false;
        self.added(result);
    });

    function shopCartComparer(item) {
        var studentId = self.selectedStudentId() || getSelectInitialValue();
        return item.eventId == self.eventId && item.studentId == studentId;
    }
}

function addOnViewModel(name, eventId, afterSchoolId, fee, added) {
    var self = this;
    self.name = name;
    self.eventId = eventId;
    self.fee = fee;
    self.afterSchoolId = afterSchoolId;
    self.added = ko.observable(added);

    self.shopCartItems = ko.observableArray().subscribeTo('shop-cart-items', function (newValue) {
        return newValue;
    });

    self.totalShopCartItems = ko.observable().extend({
        notify: "always"
    }).publishOn('total-shop-cart-items');

    self.shopCartItems.subscribe(function () {
        var totalItems = self.shopCartItems().length;
        self.totalShopCartItems(totalItems);
    });

    self.addToShopCart = function () {
        if (self.added()) {
            return;
        }
        self.added(true);
        var studentId = self.selectedStudentId() || getSelectInitialValue();
        var item = new shopCartItem(studentId, self.eventId);
        self.shopCartItems.push(item);
    }

    self.removeFromShopCart = function () {
        self.added(false);
        self.shopCartItems.remove(function (item) {
            return shopCartComparer(item);
        });
    }

    function shopCartComparer(item) {
        var studentId = self.selectedStudentId() || getSelectInitialValue();
        return item.eventId == self.eventId && item.studentId == studentId;
    }

    self.isAdded = ko.pureComputed(function () {
        return self.added() ? 'In Cart' : 'Add';
    });

    self.selectedStudentId = ko.observable().subscribeTo("student-table-channel", function (newValue) {
        return newValue;
    });

    self.isInShopCart = ko.computed(function () {
        var valorStudent = self.selectedStudentId();
        var itemInShopCart = ko.utils.arrayFirst(self.shopCartItems(), function (item) {
            return shopCartComparer(item);
        });
        var result = (itemInShopCart) ? true : false;
        self.added(result);
    });
}

function calendarViewModel(minDate, maxDate) {
    var self = this;

    self.startDate = ko.observable(new Date());

    self.maxDate = maxDate;
    self.minDate = minDate;
    self.selectedDates = ko.observableArray(); 

    self.selectedDatesFiltered = ko.pureComputed(function () {
        return ko.utils.arrayFilter(self.selectedDates(), function (date) {
            var studentId = self.selectedStudentId() || getSelectInitialValue();
            return date.studentId == studentId;
        });
    });

    self.dates = ko.computed(function () {
        console.log("entrando a dates");
        var datesCurrentStudentAdded = ko.utils.arrayFilter(self.selectedDates(), function (date) {
            var studentId = self.selectedStudentId() || getSelectInitialValue();
            return date.studentId == studentId;
        });
        var dates = [];
        var provisionalDates = ko.utils.arrayMap(datesCurrentStudentAdded, function (item) {
            return item.shortDate;
        });
        for (var i = 0; i < provisionalDates.length; i++) {
            dates[+new Date(provisionalDates[i])] = "ob-done-date";
        }            
        return dates;
    });

    self.change = function () {
        var value = this.value();
        var fullDate = getFullDate(value);
        var shortDate = getShortDate(value);
        var dayName = getDayName(value);
        var studentId = self.selectedStudentId() || getSelectInitialValue();

        var elementToPush = {
            studentId: studentId,
            fullDate: fullDate,
            dayName: dayName,
            shortDate: shortDate

        };
        self.selectedDates.push(elementToPush);
    }

    self.calendar = ko.observable();

    self.selectedStudentId = ko.observable().subscribeTo('student-calendar-channel', function (newvalue) {
        return newvalue;
    });

    self.template = ko.computed(function () {
        console.log("entrando a template");
        var dates = self.dates();
        var result = '# console.log(typeof data.dates[+data.date] === "string") #' +
            '# if(typeof data.dates[+data.date] === "string"){ #' +
            '# console.log(data.dates[+data.date]) #' +
            '<div class="#= data.dates[+data.date] #">' +
            '#= data.value #' +
            '</div>' +
            '# }else{ #' +
            '# console.log(data.value) #' +
            '#= data.value #' +
            '# } #';
        return result;
    });
}
function getShortDate(value) {
    var year = value.getFullYear().toString();
    var monthNumber = (value.getMonth() + 1).toString();
    var dayNumber = value.getDate().toString();
    return year + "-" + monthNumber + "-" + dayNumber;
}

function getFullDate(value) {
    var year = value.getFullYear().toString();
    var monthName = getMonthName(value);
    var dayName = getDayName(value);
    var dayNumber = value.getDate().toString();

    return dayName + ", " + monthName + " " + dayNumber + "th" + " " + year;
}

function getMonthName(value) {
    var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
    var monthNumber = (value.getMonth()).toString();
    return months[monthNumber];
}

function getDayName(value) {
    var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
    var dayNameNumber = value.getDay();
    return days[dayNameNumber];
}

function studentViewModel(name, studentId) {
    var self = this;
    self.name = name;
    self.studentId = studentId;
}

function studentListViewModel(studentsInfo) {
    var self = this;
    self.selectedStudentId = ko.observable().publishOn("student-calendar-channel").publishOn("student-table-channel");
    self.students = ko.observableArray(ko.utils.arrayMap(studentsInfo, function (student) {
        return new studentViewModel(student.Name, student.StudentId);
    }));
    self.totalshopCartItems = ko.observable();
}

function getData() {
    return {
        EndDate: "7/30/2015",
        StartDate: "5/1/2015",
        ShopCartInfo: {
            TotalShopCartItems: 2,
            ShopCartItems: [{
                    StudenId: 1,
                    EventId: 1,
                    Dates: []
        },
                {
                    StudenId: 1,
                    EventId: 2,
                    Dates: []
        }
        ]
        },
        StudentInfo: [
            {
                Name: 'Pedro Alcala',
                StudentId: 1
                },
            {
                Name: 'Jose Lopez',
                StudentId: 2
                }],
        DayInfo: [
            {
                Name: 'Monday',
                EventId: 1,
                AfterSchoolId: 2,
                Added: false,
                AddOns: [
                    {
                        Name: 'AddOn 10',
                        EventId: 10,
                        Fee: 5,
                        Added: false
                    },
                    {
                        Name: 'AddOn 11',
                        EventId: 11,
                        Fee: 10,
                        Added: false
                    }
                ]
            },
            {
                Name: 'Tuesday',
                EventId: 2,
                AfterSchoolId: 2,
                Added: false,
                AddOns: [
                    {
                        Name: 'AddOn 12',
                        EventId: 12,
                        Fee: 15,
                        Added: false
                    },
                    {
                        Name: 'AddOn 13',
                        EventId: 13,
                        Fee: 20,
                        Added: false
                    }
                ]
            },
            {
                Name: 'Wednesday',
                EventId: 3,
                AfterSchoolId: 2,
                Added: false,
                AddOns: [
                    {
                        Name: 'AddOn 14',
                        EventId: 14,
                        Fee: 25,
                        Added: true
                    },
                    {
                        Name: 'AddOn 15',
                        EventId: 15,
                        Fee: 30,
                        Added: true
                    }
                ]
            },
            {
                Name: 'Thursday',
                EventId: 4,
                AfterSchoolId: 2,
                Added: false,
                AddOns: [
                    {
                        Name: 'AddOn 16',
                        EventId: 16,
                        Fee: 35,
                        Added: false
                    },
                    {
                        Name: 'AddOn 17',
                        EventId: 17,
                        Fee: 40,
                        Added: false
                    }
                ]
            },
            {
                Name: 'Friday',
                EventId: 5,
                AfterSchoolId: 2,
                Added: false,
                AddOns: [
                    {
                        Name: 'AddOn 18',
                        EventId: 18,
                        Fee: 45,
                        Added: false
                    },
                    {
                        Name: 'AddOn 19',
                        EventId: 19,
                        Fee: 50,
                        Added: true
                    }
                ]
            }
        ]
    };
}

init();

}(jQuery, ko));

HTML

<!DOCTYPE html>
<html class="no-js">

<head>
<meta charset="utf-8">
<title>AfterSchool Demo</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<link rel="shortcut icon" href="/favicon.ico">
<!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
<!-- build:css(.) styles/vendor.css -->
<!-- bower:css -->
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
<!-- endbower -->
<!-- endbuild -->
<!-- build:css(.tmp) styles/main.css -->
<link rel="stylesheet" href="styles/main.css">
<link rel="stylesheet" href="styles/kendo.common.min.css">
<link rel="stylesheet" href="styles/kendo.default.min.css">
<link rel="stylesheet" href="styles/kendo.bootstrap.min.css">
<link rel="stylesheet" href="styles/custom.css">
<!-- endbuild -->
</head>

<body>
<!--[if lt IE 10]>
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
<![endif]-->

<div class="container">
    <div class="row" id="shop-cart-area">           
         <h3>                                                                
            <span class="label label-primary pull-right" data-bind="appendTextAfter: totalShopCartItems">
                <span class="glyphicon glyphicon-shopping-cart">                    
                </span>   
             </span>    
        </h3>          
    </div>
    <hr>
    <div class="row" id="students-area">
        <select class="form-control" id="select-students" data-bind="options: students,
                                                                        optionsText: 'name',
                                                                        optionsValue: 'studentId', value: selectedStudentId">
        </select>
    </div>        
    <div class="row">
        <div clas="row" id="calendar-area">
            <div class="col-md-10">
                <h4>First, select the dates you would like to come to the program:</h4>
                <h1 style="visibility:hidden;"></h1>
            </div>
            <div class="col-md-5">
                <div id="calendar" data-bind="kendoCalendar: { value: startDate, max: maxDate, min: minDate, change: change, dates: dates, month : { content: template() }, widget: calendar }">
                </div>
            </div>
            <div class="col-md-5 pull-right" style="overflow:auto;max-height:260px;">
                <p>Selected dates:</p>
                <ol data-bind="template: { name: 'selected-dates-template', foreach: selectedDatesFiltered }">
                </ol>
            </div>
        </div>
    </div>
    <hr>
    <div class="row" id="tables-area">
        <div data-bind="template: { name: 'table-template', foreach: tables }">
        </div>
    </div>
</div>

<script type="text/html" id="selected-dates-template">

    <li data-bind="text: $data.fullDate">
    </li>

</script>

<script type="text/html" id="table-template">

    <table class="table table-bordered">
        <tr>
            <td data-bind="text: name, click: addToShopCart, css: { selected : added() }" rowspan="2" class="col-md-2 hasRowSpan">
            </td>
            <td style="padding:0px">
                <div style="overflow:auto;">
                    <table class="table table-bordered table-hover">
                        <tbody data-bind="foreach: addOns">
                            <tr>
                                <td class="col-md-6" data-bind="text: name"></td>
                                <td class="col-md-3" data-bind="text: fee"></td>
                                <td class="col-md-3">
                                    <a href="#" data-bind="click: addToShopCart, text: isAdded"></a>
                                    <a class="btn-remove" href="#" data-bind="click: removeFromShopCart, visible: added()">Remove</a>
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </td>
        </tr>
    </table>

</script>


<!-- build:js(.) scripts/vendor.js -->
<!-- bower:js -->
<script src="bower_components/jquery/dist/jquery.js"></script>
<script src="bower_components/knockout/dist/knockout.js"></script>
<script src="bower_components/underscore/underscore.js"></script>
<script src="bower_components/knockout-postbox/build/knockout-postbox.min.js"></script>
<!-- endbower -->
<!-- endbuild -->

<!-- build:js(.) scripts/plugins.js -->
<script src="bower_components/bootstrap/js/affix.js"></script>
<script src="bower_components/bootstrap/js/alert.js"></script>
<script src="bower_components/bootstrap/js/dropdown.js"></script>
<script src="bower_components/bootstrap/js/tooltip.js"></script>
<script src="bower_components/bootstrap/js/modal.js"></script>
<script src="bower_components/bootstrap/js/transition.js"></script>
<script src="bower_components/bootstrap/js/button.js"></script>
<script src="bower_components/bootstrap/js/popover.js"></script>
<script src="bower_components/bootstrap/js/carousel.js"></script>
<script src="bower_components/bootstrap/js/scrollspy.js"></script>
<script src="bower_components/bootstrap/js/collapse.js"></script>
<script src="bower_components/bootstrap/js/tab.js"></script>
<!-- endbuild -->


<script src="scripts/kendo.all.min.js"></script>
<script src="scripts/knockout-kendo.min.js"></script>

<!-- build:js({app,.tmp}) scripts/main.js -->
<script src="scripts/main.js"></script>
<!-- endbuild -->
</body>

</html>

CSS

.btn-default {
    margin-top: 20px;
}

a.after-school-table-remove {
    color: #BF0221;
}  

.btn-remove {
    color: red;
    padding-left: 10px;
}

tbody td.selected {
    background-color: #E84354;
    font-weight: bold;
    color: black;
    box-shadow: 1px 1px 1px;
    opacity: 0.9;
}

tbody tr td.hasRowSpan {
    text-align: center;
    vertical-align: middle;
}

tbody td.hasRowSpan:hover {
    cursor: pointer;
    font-weight: bolder;
    border-style: groove;
    opacity: 0.8;
}

tbody td.hasRowSpan:hover:not(.selected) {
    background-color: transparent;
}

/* Styles to addons */

td > div {
    overflow: auto;
    max-height: 123px;
}

td div .table {
    margin-bottom: 0px;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.