JSFiddle - React, Tailwind, and code Playground
by kyllle
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-alpha1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.2.2/backbone-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.marionette/2.4.3/backbone.marionette.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.css">
<div class="js-ctn"></div>
<!-- CompositeView Template -->
<script type="text/html" class="js-persons-tmpl">
<table>
<tbody class="js-tbody">
</tbody>
</table>
</script>
<!-- ItemView Template -->
<script type="text/html" class="js-person-tmpl">
<% _.each(bookedClasses, function(booked, i) { %>
<tr>
<% if(i == 0) { %>
<td rowspan="4"><%= name %></td>
<% } %>
<td>
<%= booked %>
<button class="action action--remove js-action--remove"><svg viewBox="0 0 24 24"><g><path d="M12,2C6.5,2,2,6.5,2,12c0,5.5,4.5,10,10,10s10-4.5,10-10C22,6.5,17.5,2,12,2z M16.9,15.5l-1.4,1.4L12,13.4l-3.5,3.5 l-1.4-1.4l3.5-3.5L7.1,8.5l1.4-1.4l3.5,3.5l3.5-3.5l1.4,1.4L13.4,12L16.9,15.5z"/></g></svg></button>
</td>
<td>
<select class="js-sessions-select" data-classid="<%= booked %>">
<option>Please select...</option>
<% _.each(availableClasses, function(available) { %>
<option value="<%= available.id %>"><%= available.name %> --- <%= availableSessions %></option>
<% }) %>
</select>
</td>
</tr>
<% }) %>
</script>
CSS
@import url(http://fonts.googleapis.com/css?family=Roboto:300, 400, 500);
body {
font-family: Roboto;
color: #191919;
}
a {
color: #191919;
}
svg {
overflow: hidden;
vertical-align: middle;
position: relative;
top: -1px;
box-sizing: content-box;
pointer-events: none;
}
/* Actions */
.action {
border: none;
outline: none;
background: none;
}
.action--remove {
padding: 0;
position: absolute;
top: 50%;
right: 0;
transform: translateY(-50%);
}
.action--remove svg {
width: 15px;
fill: black;
}
/* General Table Styles */
table {
margin: 0;
padding: 0;
width: 100%;
}
table th, table td {
padding: 10px 20px;
text-align: left;
border-bottom: 1px solid #ccc;
}
table th {
border-width: 2px;
}
table td {
color: #666;
position: relative;
vertical-align: middle;
}
table tr:last-child th, table tr:last-child td {
border-bottom: none;
}
table tr:nth-child(even) {
background: #eee;
}
select.error {
border: 1px solid red;
}
JavaScript
console.clear();
'use strict';
// Dummy data
var availableClassesData = [{
"id": 34,
"name": "Core Evo"
}, {
"id": 686,
"name": "Core Body Workout"
}, {
"id": 870,
"name": "Boxercise"
}, {
"id": 1345,
"name": "Rapid Circuits"
}];
var personsData = [{
"id": 1,
"name": "Kenneth Wise",
"bookedClasses": [
"375",
"980",
"1072",
"1320"],
"cancelledClasses": [],
"swappedClasses": {},
"availableSessions": 1
}];
// Model Class
var Person = Backbone.Model.extend({});
var FitnessClass = Backbone.Model.extend({});
// Collection Class
var Persons = Backbone.Collection.extend({
model: Person
});
var FitnessClasses = Backbone.Collection.extend({
model: FitnessClass
});
var PersonView = Marionette.ItemView.extend({
events: {
'change .js-sessions-select': 'onSessionSelect'
},
template: '.js-person-tmpl',
templateHelpers: function () {
return {
availableClasses: this.options.availableClasses.toJSON()
}
},
initialize: function () {
//console.log('PersonView::initialize', this.model.toJSON());
},
onSessionSelect: function(event) {
var $currentTarget = $(event.currentTarget),
classId = $currentTarget.val(),
availableSessions = this.model.get('availableSessions');
var selectedOption = this.$el.find('.js-sessions-select option[value="'+classId+'"]:selected'),
len = selectedOption.length;
if(len > availableSessions) {
selectedOption.parent().addClass('error');
} else {
selectedOption.parent().removeClass('error');
}
}
});
// View Class
var PersonsView = Marionette.CompositeView.extend({
template: '.js-persons-tmpl',
childView: PersonView,
childViewContainer: '.js-tbody',
childViewOptions: function () {
return {
availableClasses:...