Skip to content
This repository has been archived by the owner on Jun 14, 2018. It is now read-only.
/ jquery-mvc Public archive

A lightweight MVC framework for the jQuery JavaScript Library.

Notifications You must be signed in to change notification settings

rjgotten/jquery-mvc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 

Repository files navigation

Introduction

This plugin extends jQuery with a small boilerplate framework for development according to the classic Model-View-Controller architectural pattern. The focus of this plugin is on keeping things light and flexible, and not forcing the programmer into the architecture of a full framework. There are no restriction by having to 'buy into' any architecture or library other than jQuery core itself and the plugin's MVC boilerplate, which - because of re-use of established practices - will feel largely reminiscent of jQuery UI widgets.

License

This plugin is dual licensed under GPL and MIT licenses.

Overview

The MVC pattern's implementation mimics the approach taken by PureMVC: the jQuery.mvc namespace offers the model, view and controller as a set of singletons serving as repositories. Smaller user-built modules can be registered to handle the responsibilities associated with the model, view and controller components of the pattern.

Communication between these modules takes place through a simple publish / subscribe notification system. This system has intentionally been kept separate from jQuery's own event handling system, which keeps it as light as possible and allows for simple, fast code tailored specifically to the system's requirements.

Model & data proxies

The model component of the MVC pattern should focus on storage and mutation of the application's data model. The model delegates its actions to a series of user-built data proxies. Data proxies registered with the model provide structured access to and management of (parts of) your application's data model. Depending on the implementation of a particular data proxy, it could manage a plain JavaScript object, some form of local storage or remote data manipulated through asynchronous requests. The underlying implementation is left to the programmer.

An example: a simple incrementing counter

The following example defines a data proxy which keeps a simple incrementing counter.

jQuery.mvc.proxy( "examples.CounterProxy", {
	_register: function() {
		this.data = 0;
	},
	
	increment: function() {
		this.data++;
		this._notify( "counterchange", { counter: this.data });
	}
});

When an instance of the counter has been created, it can be incremented using the public increment method. This will increment the internal counter and generate a notification with the new value. Subscribed observers may listen for changes this way.

var counterProxy = jQuery.mvc.model.register( "counterProxy", jQuery.mvc.examples.CounterProxy );
counterProxy.increment();

View & view mediators

The view component of the MVC pattern should focus on two things. First, it should focus on presenting data to the user. Second, it should focus on monitoring the user's interaction with interactive user interface components. The view delegates its actions to a series of view mediators, custom-built by the programmer. View mediators registered with the model may listen for notifications carrying fresh data or may send notifications carrying user input. To display changed data Mediators might directly manipulate the DOM, but they can also rely on other jQuery plugins or on jQuery UI widgets. The underlying implementation is left to the programmer.

An example: a simple incrementing counter (continued)

The following example defines a view mediator that can display updates to the counter data proxy from the earlier example. Furthermore, the mediator responds to button clicks by incrementing the proxy's counter. It also shows that the plugin allows a view mediator to directly interact with a proxy. (This may be useful for simple scenarios, where little application/business logic is involved.)

jQuery.mvc.mediator( "examples.CounterMediator", {
	options: {
		direct: true
	},
	
	notificationInterests: {
		"counterchange" : "_counterChange"
	},
	
	_register: function() {
		this._counter = $( "<span/>" ).appendTo( this.element );
		this._button = $( "<input type='button'/>" ).appendTo( this.element );				
					
		this._button.bind( "click", jQuery.proxy( this, "_buttonClick" ));
	},
	
	_remove: function() {
		this._button.remove();
		this._counter.remove();			
	}
	
	_buttonClick: function( event ) {
		event.preventDefault();
		
		// Either directly interact with the counter proxy or send a notification
		// for another part of the application to process.
		if ( this.options.direct ) {
			jQuery.mvc.model.getProxy( "counterProxy" ).increment();
		} else {
			this.notify( "requestIncrement" );
		}		
	},
	
	_counterChange: function( note ) {				
		this._counter.text( note.body.counter );
	}
});

jQuery.mvc.model.register( "counterProxy", jQuery.mvc.examples.CounterProxy );
jQuery.mvc.view.register( "counterMediator", jQuery.mvc.examples.CounterMediator, { }, $( "body" ));

Controller & commands

The controller component of the MVC pattern should focus on application/business logic that must be run when particular events, i.e., notifications take place. The controller delegates its actions to a series of commands, custom built by the programmer. A command us registered with the controller for a particular type of notification: each notification may only have a single command registered. Each time a notification is received, a fresh instance of the registered command in question will be created and its contained application/business logic will be executed. The underlying implementation of a command is left to the programmer.

An example: a simple incrementing counter (continued)

The following example builds upon the example started with the counter data proxy and continued with the paired view mediator. The example defines a command that is used to communicate with the counter data proxy. This avoids a tight coupling between view mediator and data proxy and prevents pollution of the view with application logic decisions. (In this case the command itself is trivial and merely to illustrate the point.)

jQuery.mvc.command( "examples.IncrementCommand", {
	execute: function( note ) {
		if ( note.name === "requestIncrement" ) {
			jQuery.mvc.model.getProxy( "counterProxy" ).increment();
		}
	}
})

jQuery.mvc.model.register( "counterProxy", jQuery.mvc.examples.CounterProxy );
jQuery.mvc.view.register( "counterMediator", jQuery.mvc.examples.CounterMediator, { direct: false }, $( "body" ));
jQuery.mvc.controller.register( "requestIncrement", jQuery.mvc.examples.IncrementCommand );

A note on unit testing

Should you desire to run unit tests on individual data proxies, view mediators or commands, then it might be necessary to manually prepare and inject a particular notification or manually register an (outside) observer function for a particular notification. The notifier singleton around which the MVC plugin's notification system is centered, has publicly accessible methods for registering observers and sending notifications.

// Attaching an outside observer to test a notification
var observer = jQuery.mvc.observer( this, function(note) {
	assert( note.body.foo === "bar" );
});
jQuery.mvc.notifier.register( "test", observer );

// Preparing and injecting a notification to start a test.
var notification = jQuery.mvc.notification( "test", { foo: "bar" });
jQuery.mvc.notifier.notify( notification );

About

A lightweight MVC framework for the jQuery JavaScript Library.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published