Ractive Wrappers for jQueryUI

I’m planning an ambitious new Digital Humanities platform in my role at the UNC Digital Innovation Lab, and part of the planning stage is deciding what programming libraries, modules and frameworks are worth adopting in 2015. This forthcoming platform, a successor for DH Press, will serve data from a web server to a web browser client, and this blog post relates to the JavaScript framework I’ve currently decided looks like the best choice for this system: Ractive. About a year ago I wrote about my frustrations with Angular and my preference for Knockout. My dislike for Angular remains unabated: it is a bloated, hegemonic, and non-transparent system that requires painfully convoluted code and results in unreadable software. Although I still think that Knockout is a good option, Ractive seems even better to me. Let me explain some of my criteria for the choice of framework:

  1. It must integrate into an Open Source project that will be made freely available to the DH community (educational institutions, libraries, museums, etc.)
  2. It must either provide its own GUI widget solutions or work well with jQueryUI
  3. It must create clean and sustainable code
  4. It must not be too bloated
  5. It should allow text to be separated from code so that language translation is not overly cumbersome
  6. It has to be integrated into a WordPress plugin and thus cannot assume the support of a complex infrastructure, such as node.js

I’ve also looked at React, Vue, and several other interesting options — the number of options is actually overwhelming. As a recent commentator noted, web developers can easily suffer from innovation fatigue. However, it is often the case that new frameworks, especially those not built by large teams, have insufficient documentation and examples to help would-be adopters with all of the information necessary to use the framework in the real world scenarios we actually need to implement. I’ve tried to anticipate some of the complex usages that I’ve need in my own application and tried to use Ractive in such a scenario, using it to wrap jQueryUI widgets. Fortunately, I got help from generous contributors on GitHub to get me over some hurdles and I want to share those tricks and tips here for the sake of others, and perhaps draw further helpful comments for improvements. So, here’s a scenario: I have some editing screen and when the user presses some button, a modal dialog box opens that allows some more detailed data to be configured. This modal dialog box is a jQueryUI widget that itself contains other jQueryUI widgets wrapped in Ractive code. We need to start out with a div in the main HTML body where the Ractive elements will be inserted:

<body>
 <p>Ractive wrapper for jQueryUI demo</p>
 <div id="ractive-output">
 </div>
</body>

We need a script section elsewhere in the HTML file that contains the Ractive code that gets decoded and inserted into this section. It can be as simple as:

<script id="ractive-base" type='text/ractive'>
	<div id="insert-point"></div>
	<button on-click="open-dialog">Open Dialog</button>
</script>

Now we need to create an application-level Ractive object that will set things in motion. It is very, very simple (this is just a demo skeleton).

		var rApp = new Ractive({
			el: '#ractive-output',
			template: '#ractive-base',
			components: {
			},
			data: {
			}
		});

Now that this is done, we can “listen” for the button press and create a Ractive object to handle a modal dialog and all of the objects on it. We’ll insert a button on the dialog box that does something (hence the function doSomething). The listener code needs to create a dialog that is specific to our needs, and looks like the code below.

NOTE: Since posting my initial solution, I discovered that the code for the Cancel button did not work. I’ve probably provided a solution that is somewhat less than optimal, IMO. The external caller needs to listen for the cancel button and teardown the dialog, just like the save listener. I haven’t found a means enabling the Dialog component to do this work itself.

		rApp.on('open-dialog', function() {
			var dialogTest = new Ractive({
				el: '#insert-point',
				template: '#sample-dialog',
				components: {
					dialog: RJDialogComponent,
				},
				data: {
					dialogData: myData
				}
				doSomething: function() {
// do something with the dialog data here
				}
			}); // new Ractive()

			dialogTest.on('dialog.save', function(evt) {
// save the data from the dialog
				dialogTest.teardown();
			});
			dialogTest.on('dialog.cancel', dialogTest.teardown);
		}); // open-dialog

Note that I create a “listener” on the save event, which will be fired by the dialog code when the Save button is pressed. This enables the code that uses the modal dialog to save the data without having to pollute the dialog box itself with that logic. I need to provide the Ractive template/jQuery wrapper for the dialog itself. Here’s the script template (very simple!) and the JavaScript code wrapper that creates the jQueryUI widget after Ractive has inserted the DOM elements.

<!-- Ractive Template for Dialog Component -->
<script id="dialog-r-template" type='text/ractive'>
 <div class="jq-dialog-template" title="{{title}}">
 <h3 id="dialog-subtitle">{{subtitle}}</h3>
 {{yield}}
 </div> <!-- dialog -->
</script>

var RJDialogComponent = Ractive.extend({
	template: '#dialog-r-template',
	data: {
			// set defaults
		title: '',
		subtitle: '',
		width: 350,
		height: 300
	},

		// Intercept render to insert and active jQueryUI plugin
	onrender: function() {
		var self = this;
		var thisComponent = this.find('*');
		self.modal = jQuery(thisComponent).dialog({
			width: self.get('width'),
			height: self.get('height'),
			modal : true,
			autoOpen: true,
			buttons: [
			{
				text: 'Cancel',
				click: function() {
					self.fire('cancel');
				}
			},
			{
				text: 'Save',
				click: function() {
					self.fire('save');
				}
			}]
		});
	}, // onrender

		// Intercept teardown to destroy jQueryUI component
	onteardown: function () {
		this.modal.dialog('destroy');
	} // onteardown
});

This simple little piece of code enables us to define a new HTML directive for creating a dialog box and provide optional properties (with default values) for its title, subtitle, width and height. Look at how readable and clear the resulting HTML is!

<!-- Legend Configuration Dialog -->
<script id="sample-dialog" type="text/ractive">
 <dialog title="Test Title" subtitle="Test Subtitle" width="400" height="350">

   Get some input: <input type="text" id="some-input" size="12"/>
   Get more input: <input type="text" id="more-input" size="4"/>
   <button on-click="doSomething()">Do Something</button>

   <myJQueryUIComponent ...></myJQueryUIComponent>
 </dialog>
</script>

I hope that this helps those who are considering Ractive as a framework. So far, it looks like a very strong option to me, although I would like to see more examples of it in complex scenarios (rather than just small, stand-alone components), such as that I’ve shown here.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s