- Introduction to MVC Architecture
- Setting Up the Project
- Creating the Model
- Creating the View
- Creating the Controller
- Connecting the MVC Components
- Adding Event Handling
- Finalizing and Testing
- Conclusion
Building your own MVC (Model-View-Controller) framework in JavaScript can be a rewarding exercise. It helps you understand the core principles of web frameworks and gives you control over your application's architecture. In this article, we'll create a basic MVC framework from scratch using JavaScript. This will involve setting up models, views, and controllers, and understanding how they interact with each other.
Introduction to MVC Architecture
The MVC pattern is a design pattern used to separate concerns in web applications. It divides the application into three interconnected components:
- Model: Manages the data and business logic.
- View: Handles the presentation of data.
- Controller: Manages user input and updates the model and view accordingly.
This separation allows for more modular and maintainable code.
Setting Up the Project
First, let's set up our project structure. Create a directory for your project and initialize it with the following structure:
mvc-framework/
|-- index.html
|-- css/
| |-- styles.css
|-- js/
| |-- model.js
| |-- view.js
| |-- controller.js
| |-- app.js
-
index.html
: The main HTML file. -
css/styles.css
: CSS for styling the application. -
js/model.js
: Contains the model logic. -
js/view.js
: Contains the view logic. -
js/controller.js
: Contains the controller logic. -
js/app.js
: Initializes the application.
Creating the Model
The model will handle our application's data. For simplicity, let's create a model that manages a list of items.
-
Define the Model: Open
js/model.js
and add the following code:class Model { constructor() { this.items = JSON.parse(localStorage.getItem('items')) || []; } addItem(item) { this.items.push(item); this._commit(this.items); } deleteItem(index) { this.items.splice(index, 1); this._commit(this.items); } _commit(items) { localStorage.setItem('items', JSON.stringify(items)); this.onChange(items); } bindOnChange(callback) { this.onChange = callback; } }
Creating the View
The view will manage the presentation of our data. We'll create methods to display the list of items and handle user input.
-
Define the View: Open
js/view.js
and add the following code:class View { constructor() { this.app = this.getElement('#root'); this.form = this.createElement('form'); this.input = this.createElement('input'); this.input.type = 'text'; this.input.placeholder = 'Add an item'; this.input.name = 'item'; this.submitButton = this.createElement('button'); this.submitButton.textContent = 'Submit'; this.form.append(this.input, this.submitButton); this.itemList = this.createElement('ul', 'item-list'); this.app.append(this.form, this.itemList); this._temporaryItemText = ''; this._initLocalListeners(); } get _itemText() { return this.input.value; } _resetInput() { this.input.value = ''; } createElement(tag, className) { const element = document.createElement(tag); if (className) element.classList.add(className); return element; } getElement(selector) { return document.querySelector(selector); } displayItems(items) { while (this.itemList.firstChild) { this.itemList.removeChild(this.itemList.firstChild); } items.forEach((item, index) => { const li = this.createElement('li'); li.id = index; const span = this.createElement('span'); span.textContent = item; const deleteButton = this.createElement('button', 'delete'); deleteButton.textContent = 'Delete'; deleteButton.addEventListener('click', () => { this.onDeleteItem(index); }); li.append(span, deleteButton); this.itemList.append(li); }); } _initLocalListeners() { this.itemList.addEventListener('input', event => { if (event.target.className === 'editable') { this._temporaryItemText = event.target.innerText; } }); } bindAddItem(handler) { this.form.addEventListener('submit', event => { event.preventDefault(); if (this._itemText) { handler(this._itemText); this._resetInput(); } }); } bindDeleteItem(handler) { this.onDeleteItem = handler; } }
Creating the Controller
The controller will manage the interaction between the model and view.
-
Define the Controller: Open
js/controller.js
and add the following code:class Controller { constructor(model, view) { this.model = model; this.view = view; this.model.bindOnChange(this.onModelChange); this.view.bindAddItem(this.handleAddItem); this.view.bindDeleteItem(this.handleDeleteItem); this.onModelChange(this.model.items); } onModelChange = items => { this.view.displayItems(items); }; handleAddItem = item => { this.model.addItem(item); }; handleDeleteItem = index => { this.model.deleteItem(index); }; }
Connecting the MVC Components
Now we need to initialize our MVC components and connect them together.
-
Initialize Components: Open
js/app.js
and add the following code:document.addEventListener('DOMContentLoaded', () => { const app = new Controller(new Model(), new View()); });
Adding Event Handling
We’ve already added event handling for adding and deleting items in the view and controller. Let's review and ensure everything is correctly wired up.
-
View Event Handlers:
-
bindAddItem
: Handles the form submission and adds a new item. -
bindDeleteItem
: Handles the deletion of an item when the delete button is clicked.
bindAddItem(handler) { this.form.addEventListener('submit', event => { event.preventDefault(); if (this._itemText) { handler(this._itemText); this._resetInput(); } }); } bindDeleteItem(handler) { this.onDeleteItem = handler; }
-
-
Controller Event Handlers:
-
handleAddItem
: Adds a new item to the model. -
handleDeleteItem
: Deletes an item from the model.
handleAddItem = item => { this.model.addItem(item); }; handleDeleteItem = index => { this.model.deleteItem(index); };
-
Finalizing and Testing
With everything in place, let's finalize and test our application.
-
HTML Structure: Open
index.html
and add the following code:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>MVC Framework</title> <link rel="stylesheet" href="css/styles.css"> </head> <body> <div id="root"></div> <script src="js/model.js"></script> <script src="js/view.js"></script> <script src="js/controller.js"></script> <script src="js/app.js"></script> </body> </html>
-
Styling: Open
css/styles.css
and add some basic styles:body { font-family: Arial, sans-serif; } .item-list { list-style-type: none; padding: 0; } .item-list li { display: flex; justify-content: space-between; padding: 5px; border-bottom: 1px solid #ccc; } .item-list li span { flex-grow: 1; } .delete { background-color: red; color: white; border: none; padding: 5px; cursor: pointer; }
-
Testing: Open your
index.html
file in a web browser and test the functionality of adding and deleting items. Make sure everything works as expected.
Conclusion
Building your own MVC framework in JavaScript is a great way to understand the fundamental principles of this popular architectural pattern. By separating concerns into models, views, and controllers, you can create a more modular and maintainable application. This tutorial provided a basic implementation, but you can expand upon it by adding features such as validation, more complex data manipulation, and routing.
This exercise not only helps you understand how MVC frameworks work but also gives you a solid foundation for using more complex frameworks and libraries in the future.
Interested in proving your knowledge of this topic? Take the JavaScript Fundamentals certification.
JavaScript Fundamentals
Showcase your knowledge of JavaScript in this exam, featuring questions on the language, syntax and features.
$99
![JavaScript Fundamentals](/img/badges/javascript-fundamentals.png)