Skip to content

Instantly share code, notes, and snippets.

@sinhavartika
Last active July 13, 2017 14:00
Show Gist options
  • Save sinhavartika/43d9dd2295783ddf01f0a311d93b1931 to your computer and use it in GitHub Desktop.
Save sinhavartika/43d9dd2295783ddf01f0a311d93b1931 to your computer and use it in GitHub Desktop.
MVC in vanilla javascript
<html>
<head>
<style>
/* global css */
.mt-sm {
margin-top: 5px;
}
.text-justify {
text-align: justify;
}
.text-center {
text-align: center;
}
.show {
display: block;
}
.clearfix:after {
content: " "; /* Older browser do not support empty content */
visibility: hidden;
display: block;
height: 0;
clear: both;
}
/* custom css */
body {
background-color: #333;
}
.container {
width : 600px;
margin: 10px auto;
padding: 10px;
background-color: #fff;
}
.ui {
margin: 10px 0;
border: 1px solid #333;
padding: 10px;
}
.ui > ul, .ui > div {
float: left;
width: 45%;
padding: 5px;
}
.number-list {
list-style-type: none;
margin: 0;
border-right: 1px solid #333;
}
.number-list > li {
height: 30px;
margin : 3px 0;
padding: 5px 5px 5px 15px;
background-color: #f1f1f1;
cursor: pointer;
word-wrap: break-word;
}
.number-list > li:hover {
background-color: #e1e1e1;
}
.number {
margin: 8px 10px 0 5px;
background-color: #f1f1f1;
}
.number > button{
float: right;
}
/* tab component */
.tabs > .tab-pane {
display: none;
}
.tabs > .tab-pane.show {
display: block;
}
.tabs > .tab-pane h4 {
margin: 5px 0;
}
</style>
</head>
<body>
<div class="container">
<h3 class="text-center">Exploring <strong>Model-View-Controller</strong> in Javascript</h3>
<p class="text-justify">
Readme
<button id="add-number-to-list">Add</button>
</p>
<div class="ui clearfix">
<ul id="number-list" class="number-list"></ul>
<div class="number">
<button data-target="number_view" data-feature="tab">Edit</button>
<div data-tab="number_view" class="tabs">
<div class="tab-pane show">
<h4>View</h4>
<div id="selected-number-view"></div>
</div>
<div class="tab-pane">
<h4>Editor<h4>
<input type="text" id="selected-number-edit"/>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var vquery = {};
(function(vquery){
vquery.on = function(staticParent, eventName, dynamicChildSelector, fn){
document.querySelector(staticParent).addEventListener(eventName, function (event) {
if (event.target.classList.contains(dynamicChildSelector)) {
fn(event);
}
})
};
})(vquery);
</script>
<!-- script defining the controller -->
<script>
(function(){
// function toogles the tab on button click
function toggleTab(event){
// get the target tab component
var toggleTabTarget = event.target.dataset.target;
var targetElm = document.querySelectorAll('[data-tab="' + toggleTabTarget + '"]')[0];
// toggle the show of all the divs with .tab-pane class
var elms = targetElm.querySelectorAll(".tab-pane");
elms.forEach(function(elm){
elm.classList.toggle("show");
});
}
/***************************** private functions ***************************/
// funciton that should be called when class divs with certain toggles attribs should be toggled
function toggleClass(target, classNames){
var elms = document.querySelectorAll('[data-toggle="' + target + '"]');
elms.forEach(function(elm){
elm.classList.toggle(classNames);
});
}
/***************************** event functions ***************************/
var tabBtns = document.querySelectorAll("[data-feature='tab']");
tabBtns.forEach(function(elm){
elm.addEventListener("click", toggleTab, false);
});
})();
</script>
<script>
var numberController = function(model, view){
/***************** private variables ********************/
var model = model;
var view = view;
/***************** initializing controller **************/
activate();
/***************** public functions *********************/
// function to render the numbers in the list
var renderNumberList = function(){
model.numberList.forEach(function(number){
var li = document.createElement("li");
li.className = "number";
var text = document.createTextNode(number.value);
li.dataset.id = number.id;
li.appendChild(text);
view.ul.appendChild(li);
});
};
// function to select a number from the list
var selectNumber = function(event){
// get the number model from list
var id = event.target.dataset.id;
var number = model.numberList.find(function(number){
return number.id === id;
});
// set the number in model
model.number = number;
// set the number in view
view.selected_number_edit.value = number.value;
view.selected_number_view.innerHTML = number.value;
};
// function to edit a number from the list
var editNumber = function(event){
// change in model
var listNumberModel = model.numberList.find(function(number){
return number.id === model.number.id;
});
listNumberModel.value = view.selected_number_edit.value;
model.number.value = view.selected_number_edit.value;
// change in view
var listNumberView;
view.ul.childNodes.forEach(function(numberView){
if(numberView.dataset.id === model.number.id){
listNumberView = numberView;
}
});
listNumberView.innerHTML = model.number.value;
view.selected_number_view.innerHTML = model.number.value;
}
var addNumberToTheList = function(){
var number = {
"id" : "" + model.numberList.length + 1,
"value" : model.numberList.length + 1
}
model.numberList.push(number);
var li = document.createElement("li");
li.className = "number";
var text = document.createTextNode(number.value);
li.dataset.id = number.id;
li.appendChild(text);
view.ul.appendChild(li);
}
var toggleEditing = function(event){
model.editing = !model.editing;
var editBtn = event.target;
if(model.editing){
editBtn.innerHTML = "Preview";
}else{
editBtn.innerHTML = "Edit";
}
}
/***************** private functions *********************/
function activate(){
var number = model.numberList[0];
// set the number in model
model.number = number;
// set the number in view
view.selected_number_edit.value = number.value;
view.selected_number_view.innerHTML = number.value;
}
return {
"renderNumberList" : renderNumberList,
"selectNumber" : selectNumber,
"editNumber" : editNumber,
"toggleEditing" : toggleEditing,
"addNumberToTheList" : addNumberToTheList
}
}
</script>
<!-- init -->
<script>
/**
Model
*/
var numbersModel = {
numberList : [
{id:"1", value: 1},{id:"2", value: 2},{id:"3", value: 3}
],
number : {},
editing : false
}
/**
View
*/
var numbersView = {
ul : document.getElementById("number-list"),
selected_number_view : document.getElementById("selected-number-view"),
selected_number_edit : document.getElementById("selected-number-edit")
}
/**
Numbers Controller
*/
var numbersController = numberController(numbersModel, numbersView);
numbersController.renderNumberList();
/**
binding events
// */
numbersView.selected_number_edit.addEventListener("keyup", numbersController.editNumber, false);
var tabBtns = document.querySelectorAll("[data-feature='tab']")[0];
tabBtns.addEventListener("click", numbersController.toggleEditing, false);
document.getElementById("add-number-to-list").addEventListener("click", numbersController.addNumberToTheList, false);
vquery.on("ul.number-list", "click", "number", numbersController.selectNumber);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment