MVC
& patterns
How it begins
Old days
<input type="text" name="date" onchange="validateDate(this);" />
if you have 20+ forms you need to add 20+ onchange functions
JavaScript behavior created and referenced in the HTML can be harder to use and maintain
if you have several handlers
<input type="text" name="date"
onchange="validateDate(this); dance(something); playMusic();" />
<a href="#faq1"
onclick="$('#faq1').css('display') == 'none' ? $('#faq1').show() : $('#faq1').hide();">
FAQ Question 1</a>
<div id="faq1" class="faqAnswer">FAQ Answer 1</div>
<a href="#faq2"
onclick="$('#faq2').css('display') == 'none' ? $('#faq2').show() : $('#faq2').hide();">
FAQ Question 2</a>
<div id="faq2">FAQ Answer 2</div>
<a href="#faq3"
onclick="$('#faq3').css('display') == 'none' ? $('#faq3').show() : $('#faq3').hide();">
FAQ Question 3</a>
<div id="faq3">FAQ Answer 3</div>
Obtrusive (or in-line) JavaScript:
Unobtrusive JavaScript
- Separation of functionality (the "behavior layer", JS) from a Web page's structure/content (HTML) and presentation(CSS)
-
try to avoid the problems of traditional JavaScript programming
- Progressive enhancement
<a class=”hide”>Click to hide me</a>
$('.hide').click(function() { $(this).hide(); }
jQuery way:
Profit !
Right? Not exactly
So...
Clean, semantic HTML!
Total separation!
you can’t change a line of markup without checking every single line of JavaScript to assure you’re not breaking a selector
Strictly separating HTML and JS actually led to applications that were harder to maintain and debug
MVC
is a software architectural pattern
Trygve Reenskaug introduced MVC into Smalltalk-76 while visiting the Xerox Palo Alto Research Center (PARC) in the 1970s
A bit of history
Apple's WebObjects ("borrowed" from Smalltalk) in Objective-C
WebObjects was ported to Java
Ruby on Rails, Django, ASP.NET MVC
(Client) AngularJS, EmberJS, JavaScriptMVC, Backbone
Principes
MVC offers architectural benefits over standard JavaScript — it helps you write better organized, and therefore more maintainable code.
Parts:
-
Model is where the application’s data objects are stored. The model doesn’t know anything about views and controllers.
-
View is what's presented to the users and how users interact with the app. The view is made with HTML, CSS, JavaScript and often template
-
Controller is the decision maker and the glue between the model and view.
The controller updates the view when the model changes. It also adds event listeners to the view and updates the model when the user manipulates the view.
var M = {},
V = {},
C = {};
M.data = "hello world";
V.render = function (M) {
alert(M.data);
}
C.handleOnload = function () {
V.render(M);
}
window.onload = C.handleOnLoad;
Tiny MCV application
-
View knows nothing about the Model apart from it implements some interface
-
Model knows nothing of the View and the Controller
- Controller knows about both the Model and the View and tells the View to go do something with the data from the Model.
old MVC != new MVC
- Model–View–Presenter
- Model–View–ViewModel
- Model–View–Adapter
- ...
traditional MVC pattern vs the modern interpretation in various programming languages:
some MVC–based frameworks will have the view observe the changes in the models while others will let the controller handle the view update
- Reusable and extendable code
- Separation of view logic from business logic
- Allow simultaneous work between developers who are responsible for different components (such as UI layer and core logic)
- Easier to maintain
MVC pattern brings modularity to application developers and it enables:
The Observer Pattern
This pattern implements a single object that maintains a reference to a collection of objects (known as "observers") and broadcasts notifications when a change to state occurs.
How it works?
Observers register with the Subject and wait for notification
Subject notify Observers about a change in state.
Observers take action
from http://www.slideshare.net/saifuddinmerchant/observer-pattern-15133603
var Subject = function() {
this.observers = [];
return {
subscribeObserver: function(observer) {
this.observers.push(observer);
},
unsubscribeObserver: function(observer) {
var index = this.observers.indexOf(observer);
if(index > -1) {
this.observers.splice(index, 1);
}
},
notifyObserver: function(observer) {
var index = this.observers.indexOf(observer);
if(index > -1) {
this.observers[index].notify(index);
}
},
notifyAllObservers: function() {
for(var i = 0; i < this.observers.length; i++){
this.observers[i].notify(i);
};
}
};
};
var Observer = function() {
return {
notify: function(index) {
console.log("Observer " + index + " is notified!");
}
}
}
var subject = new Subject();
var observer1 = new Observer();
var observer2 = new Observer();
var observer3 = new Observer();
var observer4 = new Observer();
subject.subscribeObserver(observer1);
subject.subscribeObserver(observer2);
subject.subscribeObserver(observer3);
subject.subscribeObserver(observer4);
subject.notifyObserver(observer2); // Observer 2 is notified!
subject.notifyAllObservers();
Publish–subscribe Pattern
is a variation of Observer pattern.
However PubSub uses a topic/event channel that sits between the objects wishing to receive notifications (subscribers) and the object firing the event (the publisher)
Differences
• there is no direct communication between objects
• objects exchange Events rather than share states of object
PubSub basic example
// create a function to subscribe to topics
var mySubscriber = function( msg, data ){
console.log( msg, data );
};
// add the function to the list of subscribers for a particular topic
// we're keeping the returned token, in order to be able to unsubscribe
// from the topic later on
var token = PubSub.subscribe( 'MY TOPIC', mySubscriber );
// publish a topic asyncronously
PubSub.publish( 'MY TOPIC', 'hello world!' );
// publish a topic syncronously, which is faster in some environments,
// but will get confusing when one topic triggers new topics in the
// same execution chain
// USE WITH CAUTION, HERE BE DRAGONS!!!
PubSub.publishSync( 'MY TOPIC', 'hello world!' );
Cancel specific subscription
// create a function to receive the topic
var mySubscriber = function( msg, data ){
console.log( msg, data );
};
// add the function to the list of subscribers to a particular topic
// we're keeping the returned token, in order to be able to unsubscribe
// from the topic later on
var token = PubSub.subscribe( 'MY TOPIC', mySubscriber );
// unsubscribe this subscriber from this topic
PubSub.unsubscribe( token );
Cancel all subscriptions for a function
// create a function to receive the topic
var mySubscriber = function( msg, data ){
console.log( msg, data );
};
// unsubscribe mySubscriber from ALL topics
PubSub.unsubscribe( mySubscriber );
Cancel all subscriptions
PubSub.clearAllSubscriptions();
// all subscriptions are removed
Resources
-
Addy Osmani's: Learning JavaScript Design Patterns
- https://github.com/tastejs/todomvc
- http://shichuan.github.io/javascript-patterns
- https://github.com/mroderick
- http://jstherightway.org
MVC. Patterns
By Nicholas Sorokin
MVC. Patterns
- 632