Monday, December 1, 2014

We won Hackagong 2014!

I spent last weekend down at Hackagong 2014. It's an annual hackathon where entrants are challenged to make something awesome in 30 hours. The idea is to form small teams mixing designers, programmers, engineers, entrepreneurs, game creators or anybody with an idea or problem to solve, and build a technology driven product or service prototype. There were over $100,000 of prizes on offer.

I didn't know what to expect going in, other than it was a great opportunity to get out my comfort zone and play with new technology. Competition was pretty fierce, with nearly 40 teams submitting some amazing projects using everything from Augmented Reality goggles to drones to 3D printers. But by the end, I was thrilled to be a member of the winning team!

Team mates Brooke, Caleb, Michael and I developed a 3D-printed, Internet-of-Things Egg Hatchery over the course of 30 hours. The judges described it as "an awesome effort":

Winner: Major Prize Winner
Winner: Most Innovative 3D Print

Here's a video of our winning entry (the rules dicatated the video had to be silent):

This was my first hackathon, and it was a fantastic experience. Many thanks to the organizers and everyone who participated!

Sunday, November 2, 2014

Domain Driven Forms: Metawidget 4.0

Version 4.0 of Metawidget, the library for domain driven forms is now available!

This release was focused on:
  • Web Components support
  • clearWidgets support (JavaScript version)
  • JsonSchemaTypeMappingProcessorConfig
  • Improved Node.js support
  • Boolean radio buttons (JavaScript version)
  • Minor refactoring
  • Bug fixes, documentation and unit tests
As always, the best place to start is the Reference Documentation:

http://metawidget.org/doc/reference/en/pdf/metawidget.pdf

Your continued feedback is invaluable to us. Please download it and let us know what you think.

Breaking Changes

We've taken advantage of the major version number bump to make some minor breaking changes for the sake of clarity and consistency. Specifically:
  • For metawidget.js, addInspectionResultProcessors has been renamed to appendInspectionResultProcessors
  • Similarly for metawidget.js, addWidgetProcessors has been renamed to appendWidgetProcessors
  • XmlUtils.elementToJsonSchema has been renamed to XmlUtils.inspectionResultToJsonSchema
  • For SwtMetawidget, setInspectionPath has been renamed to setPath

Saturday, November 1, 2014

Metawidget meets Web Components

The next release of Metawidget (v4.0) introduces Web Components!

Web Components are an exciting new HTML standard that promise to bring much of the UI goodness of frameworks like AngularJS to HTML without any additional libraries. As usual with emerging technologies, not all browsers fully support Web Components, but there are fantastic 'stop gap' libraries such as Polymer that can get you most of the way there today.

With Web Components, you can use Metawidget in fewer lines of code than ever before! Here's a complete example:

<!DOCTYPE HTML>
<html>
   <head>
      <script src="metawidget-core.min.js"></script>
      <style>
         #metawidget {
            border: 1px solid #cccccc;
            width: 250px;
            border-radius: 10px;
            padding: 10px;
            margin: 50px auto;
            display: block;
         }
      </style>
      <script>
         var person = {
            firstname: 'Homer',
            surname: 'Simpson',
            age: 36,
            save: function() {
               document.getElementById( 'metawidget' ).save();
               console.log( person );
            }
         }
      </script>
   </head>
   <body>
      <x-metawidget id="metawidget" path="person"></x-metawidget>
   </body>
</html>

Note the new x-metawidget tag. This is registered automatically just by including metawidget-core.min.js. It's available to your code just like any other HTML tag. It has custom methods such as save to make it easy to bind data back from the Metawidget, and automatically watches attributes such as path to rebuild the Metawidget.

Try it today in Chrome:

We've also ported the existing Address Book sample application to Web Components to provide a more meaty example:

Download it and give it a try! And welcome to the future :)

Thursday, June 26, 2014

Metawidget meets Bower

I was recently asked whether I could add Bower support to Metawidget.

I'm delighted to say this has now been set up. The repository is here and you can install it just like any Bower repo...

bower install metawidget

...or add it into your project's bower.json file...

{
   "name": "my-app",
   "dependencies": {
      ...
      "metawidget": "~3.9.0"
   },
   "private": true
}

Other Metawidget modules, such as metawidget-angular.min.js and metawidget-bootstrap.min.js, are also included in this repository.

Feedback welcome!

Monday, May 26, 2014

"Hey Bro, I heard you liked Dynamic UIs, so I put a Dynamic UI inside your Dynamic UI"

I was recently asked:

What is the best approach to implement conditional widgets in Javascript, i.e., to selectively show/hide widgets based on other widget selection(s)?

As discussed, Metawidget tries hard not to 'dictate' anything about your architecture. Therefore the 'best' approach depends on your needs. However here are two broad solutions:

1. Have Metawidget Do All The Work

This approach is the most flexible. Basically:

  • First, define an Inspector or InspectionResultProcessor that knows how to return different results based on different conditions. For example, Angular Metawidget has an InspectionResultProcessor that can process Angular expressions
  • Next, define a WidgetProcessor that knows how to kick off a complete Metawidget re-inspection based on some change

Combining these two gives you some awesome capabilites. Here's a complete example:

<html ng-app="myApp">
   <head>
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js" type="text/javascript"></script>
      <script src="http://metawidget.org/js/3.8/metawidget-core.min.js" type="text/javascript"></script>
      <script src="http://metawidget.org/js/3.8/metawidget-angular.min.js" type="text/javascript"></script>
      <script type="text/javascript">
         angular.module( 'myApp', [ 'metawidget' ] ).controller( 'myController', function( $scope ) {

         $scope.metawidgetConfig = {
            inspector: new metawidget.inspector.JsonSchemaInspector( {
               properties: {
                  type: {
                     enum: [ 'Car', 'Truck', 'Aeroplane' ]
                  },
                  model: {
                     enum: [ 'Saloon', '4WD', 'Sports' ],
                     hidden: '{{vehicle.type != "Car"}}'
                  },
                  description: {
                     type: 'string',
                     large: true,
                     hidden: '{{vehicle.type != "Truck"}}'
                  },
                  details: {
                     hidden: '{{vehicle.type != "Aeroplane"}}',
                     properties: {
                        wingspan: {
                           type: 'number'
                        },
                        speed: {
                           type: 'number'
                        }
                     }
                  }
               }
            } )
         }
         $scope.vehicle = {};
      } );
   </script>
      <style>
         #metawidget {
            border: 1px solid #cccccc;
            width: 300px;
            border-radius: 10px;
            padding: 10px;
            margin: 50px auto;
            display: block;
         }
      </style>
   </head>
   <body ng-controller="myController">
      <metawidget id="metawidget" ng-model="vehicle" config="metawidgetConfig" />
   </body>
</html>

This UI will show/hide multiple widgets depending on the select box, and it's all defined declaratively!

2. Leverage Standard DOM Manipulation

This approach is less flexible, but also has less 'magic' in how it works. Basically:

  • First, add metadata to denote when widgets are conditional
  • Next, define a WidgetProcessor to attach standard DOM manipulation to those widgets. Metawidget helps by generating reliable IDs for everything

Here's a complete example using pure JavaScript:

<!DOCTYPE HTML>
<html>
   <head>
      <script src="http://metawidget.org/js/3.8/metawidget-core.min.js"></script>
      <style>
         #metawidget {
            border: 1px solid #cccccc;
            width: 250px;
            border-radius: 10px;
            padding: 10px;
            margin: 50px auto;
         }
         #table-model-row {
            visibility: hidden;
         }
      </style>
   </head>
   <body>
      <div id="metawidget"></div>
      <script type="text/javascript">
         var mw = new metawidget.Metawidget( document.getElementById( 'metawidget' ), {
         inspector: new metawidget.inspector.JsonSchemaInspector( {
               properties: {
                  make: {
                     enum: [ 'BMW', 'Ford', 'Toytota' ],
                     onSelect: 'model'
                  },
                  model: {
                     enum: [ 'Saloon', '4WD', 'Sports' ]
                  }
               }
            } ),
            addWidgetProcessors: [
               function( widget, elementName, attributes, mw ) {

                  if ( attributes.onSelect !== undefined ) {
                     widget.setAttribute( 'onchange', 'document.getElementById("table-' + attributes.onSelect + '-row").style.visibility="visible"' );
                  }


                  return widget;
               }
            ]
         } );
         mw.toInspect = {};
         mw.buildWidgets();
      </script>
   </body>
</html>

Feedback welcome!

Thursday, May 22, 2014

AngularJS: Changing the date format of dynamically generated components

I was recently asked:

"...is a better approach to set a different date formatting, besides from hacking it in metawidget-angular.js"

The answer is yes! Metawidget is designed around a five stage pluggable pipeline, which offers well-researched extension points to accomodate most UI requirements.

The easiest approach to this particular problem is to add a little WidgetProcessor to tweak Metawidget's standard date formatting (if you want to introduce a whole new control instead, better to go with a WidgetBuilder, as shown here). Here's a complete example:

<html ng-app="myApp">
   <head>
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js" type="text/javascript"></script>
      <script src="http://metawidget.org/js/3.8/metawidget-core.min.js" type="text/javascript"></script>
      <script src="http://metawidget.org/js/3.8/metawidget-angular.min.js" type="text/javascript"></script>
      <script type="text/javascript">
         angular.module( 'myApp', [ 'metawidget' ] ).controller( 'myController', function( $scope ) {
   
         $scope.metawidgetConfig = {
            addWidgetProcessors: [ function( widget, elementName, attributes, mw ) {
   
               if ( attributes.type === 'date' ) {
                  widget.setAttribute( 'ng-bind', widget.getAttribute( 'ng-bind' ) + ":'d MMMM yyyy'" );
               }
               
               return widget;
            } ]

         };
         $scope.person = {
            firstname: 'Homer',
            surname: 'Simpson',
            date: new Date( 1953, 5, 12 )
         };
      } );
   </script>
      <style>
         #metawidget {
            border: 1px solid #cccccc;
            width: 250px;
            border-radius: 10px;
            padding: 10px;
            margin: 50px auto;
            display: block;
         }
      </style>
   </head>
   <body ng-controller="myController">
      <metawidget id="metawidget" ng-model="person" read-only="true" config="metawidgetConfig" />
   </body>
</html>

Feedback welcome!

Thursday, May 15, 2014

AngularJS: Create editable tables with dynamic columns (Part 3)

Further to my previous post, and as mentioned in Part 1, there are lots of different UI approaches to creating editable tables.

For example: a table where you click an edit button next to each row to open a pop-up window; a table where you click the row itself to open a pop-up window; a table where you click each row and edit it 'in place'; a table where all rows are editable at once; a table where each row has both an edit button and a delete button; etc. etc. I'm sure you can think of plenty more. All of them are valid choices depending on your UI design.

It's because of this that Metawidget doesn't try to 'own' your UI. Metawidget only strives to be a piece of your overall solution: a useful widget you can sprinkle liberally all over your UI, wherever you need UI generation, but nowhere that you don't.

The downside of this flexibility is that you have to do a bit more work to wire everything together. In this post I'm going to implement one of the above approaches: a table where all rows are editable at once. It's very similar to my previous post. This time, instead of the editable table instantiating a plain piece of HTML, it instantiates a Metawidget for every row and every column:

var columnMetawidget = $( '<metawidget ng-model="row.' + columns[loop] + '" config="metawidgetConfig">' );
tr1.append( $( '<td>' ).append( columnMetawidget ) );

This works because Metawidget is very lightweight. All parts of the metawidgetConfig are immutable, so the same objects are reused for every Metawidget in the table. The result looks like this:

You can download a complete example here. Feedback welcome!

UPDATE: the built-in metawidget.widgetbuilder.HtmlWidgetBuilder now supports alwaysUseNestedMetawidgetInTables which may be useful in these cases

Wednesday, May 14, 2014

AngularJS: Create editable tables with dynamic columns (Part 2)

Following on from my previous post, I was asked:

"[In your post the] table columns are rendered using html input control with type="text"... [Can the user] add/edit new object in accordance with json schema (checkbox for boolean, dropdown for enum,...)?"

This is where Metawidget really shines. Metawidget is designed to be lightweight and embedded multiple times on a page - wherever you need small pieces of UI generation. So we can easily use a Metawidget at the foot of each column:

The implementation is almost the same as before, except instead of instantiating an <input type="text">, the editable table instantiates another <metawidget> tag:

var nestedMetawidget = $( '<metawidget ng-model="newRow.' + columns[loop] + '" config="metawidgetConfig">' );
tr2.append( $( '<td>' ).append( nestedMetawidget ) );

The hardest part is passing the row schema metadata through to the editable table:

$scope[rowSchemaKey] = inspectionResult;
var widget = $( '<table>' ).attr( 'edit-table', '' ).attr( 'schema', rowSchemaKey );

You can download a complete example here. You can also take this approach further. Feedback welcome!

Tuesday, May 13, 2014

AngularJS: Create editable tables with dynamic columns

I was recently asked:

"[how do I] implement functionality for new/delete for arrays in AngularJS... [when] object structure is unknown until runtime execution."

There are lots of ways to do this using Metawidget, which is why Metawidget doesn't dictate one out-of-the-box. By default, AngularJS Metawidget will only render arrays as read-only:

Adding editing capabilities depends on your particular UI needs. Here's one approach. Essentially we:

  • Create an Angular directive to render a simple <table> with editable rows. This directive is not specific to Metawidget
  • Create a Metawidget WidgetBuilder that can instantiate and configure the editable table. This includes reading metadata at runtime to determine the table's columns

So you'll end up with something like this:

The important Metawidget bit looks like this:

$scope.metawidgetConfig = {

   ...custom WidgetBuilder...
   
   widgetBuilder: new metawidget.widgetbuilder.CompositeWidgetBuilder( [ function( elementName, attributes, mw ) {

      if ( attributes.type === 'array' ) {

         ...inspects array metadata...
         
         var inspectionResult = mw.inspect( mw.toInspect, typeAndNames.type, typeAndNames.names );
         
         ...creates editable table

         var widget = $( '<table>' ).attr( 'edit-table', '' )
               .attr( 'columns', columns ).attr( 'ng-model', mw.path + '.' + attributes.name );
         return widget[0];
      }

You can download a complete project here. Feedback welcome!

Thursday, March 6, 2014

Metawidget In The Cloud

The awesome folks over at CloudBees have kindly donated a FOSS account for our nightly builds! See our Customer Story here.

This means you can now download snapshot bundles of Metawidget.

These are complete ZIPs containing all binaries, minified JavaScript libraries, API documentation, Reference Guide PDFs and pre-built examples. Of course, Maven snapshot JARs will still be available.

Tuesday, February 25, 2014

JavaScript Form Generator: Metawidget 3.8

Version 3.8 of Metawidget, the JavaScript form generator is now available!

This release was focused on:
  • Re-licensed under LGPL/EPL and a commercial license
  • Bootstrap 3 support
  • AngularJS date support, ngShow/ngHide support, memory leak fix
  • Spring 3.2.6 support
  • HTML 5 color picker support
  • Bug fixes, documentation and unit tests
As always, the best place to start is the Reference Documentation:

http://metawidget.org/doc/reference/en/pdf/metawidget.pdf

Your continued feedback is invaluable to us. Please download it and let us know what you think.

Wednesday, February 12, 2014

JavaScript Form Generator: from Java EE to Bootstrap 3

I've been asked to provide a complete example of using Metawidget to bridge the gap between an annotation-based, Java EE back-end and a JavaScript, Bootstrap 3 front-end.

This requires metadata to be fed from the 'Java world' into the 'JavaScript world'. Metawidget excels at this, using a process it calls 'remote inspection'. Metawidget's five-stage pipeline is designed to be split across multiple tiers and disparate architectures.

First, create the annotated Java object. We'll use Metawidget's built-in annotations here, but you can of course use JPA annotations, Hibernate Validator annotations etc.

public class Person {

   private String   mFirstname;

   private String   mSurname;

   private int      mAge;

   private boolean   mRetired;

   @UiRequired
   public String getFirstname() {...}

   @UiComesAfter( "firstname" )
   public String getSurname() {...}

   @UiComesAfter( "surname" )
   public int getAge() {...}


   ...other getters and setters...
}

Then, create a REST service that uses Metawidget's inspectors to inspect that object, and returns the inspection result in JSON format:

mInspector = new CompositeInspector( new CompositeInspectorConfig().setInspectors(
      new PropertyTypeInspector(),
      new MetawidgetAnnotationInspector()
      ) );

mInspectionResultProcessors = new DomInspectionResultProcessor[] {
      new ComesAfterInspectionResultProcessor<Object>(),
      new JsonSchemaMappingProcessor<Object>(),
      new JsonTypeMappingProcessor<Object>()
};

...

// Inspect

Element inspectionResult = mInspector.inspectAsDom( null, entityClass.getName() );
for ( DomInspectionResultProcessor<Element, Object> inspectionResultProcessor : mInspectionResultProcessors ) {
   inspectionResult = inspectionResultProcessor.processInspectionResultAsDom(
      inspectionResult, null, null, entityClass.getName(), (String[]) null );
}

// Convert to JSON Schema

return XmlUtils.elementToJsonSchema( inspectionResult );

Finally, create a JavaScript Metawidget that uses Bootstrap 3 and calls the REST service asynchronously:

<!DOCTYPE HTML>
<html>
   <head>
      <link href="lib/bootstrap/css/bootstrap.min.css" type="text/css" rel="stylesheet"/>
      <script src="lib/jquery/jquery.min.js"></script>
      <script src="lib/bootstrap/js/bootstrap.min.js"></script>
      <script src="js/metawidget-core.min.js"></script>
      <script src="js/metawidget-bootstrap.min.js"></script>
   </head>
<body>
   <div style="width: 500px; margin: 50px auto">
      <form class="form-horizontal">
         <div id="metawidget">
            <button class="btn btn-primary" onclick="save(); return false">Save</button>
         </div>
      </form>
   </div>
   <script type="text/javascript">
      var mw = new metawidget.Metawidget( document.getElementById( 'metawidget' ), {

         inspectionResultProcessors: [ function( inspectionResult, mw, toInspect, type, names ) {

            var xhr = new XMLHttpRequest();
            xhr.open( "GET", "rest/schema/person", true );

            xhr.onreadystatechange = function() {

               if ( xhr.readyState == 4 && xhr.status == 200 ) {

                  metawidget.util.combineInspectionResults( inspectionResult,
                     JSON.parse( xhr.responseText ) );

                  // Resume Metawidget operation

                  mw.buildWidgets( inspectionResult );
               }
            }

            xhr.send();

            // Return nothing to suspend Metawidget operation
         } ]
,
         
         addWidgetProcessors: [ new metawidget.bootstrap.widgetprocessor.BootstrapWidgetProcessor() ],
         layout: new metawidget.bootstrap.layout.BootstrapDivLayout()
      } );
      mw.toInspect = {};
      mw.buildWidgets();
      function save() {

         mw.getWidgetProcessor( function( widgetProcessor ) {

            return widgetProcessor instanceof metawidget.widgetprocessor.SimpleBindingProcessor;
         } ).save( mw );
         console.log( mw.toInspect );
      }
   </script>
</body>
</html>

This will produce:

Here's a link to a complete Eclipse project. Feedback welcome!

Sunday, January 26, 2014

Easy Forms For JavaScript: Dynamically Generating A Map Widget

I was recently asked if a JavaScript Metawidget could be used to display a map when given a location.

Metawidget is designed around a 5 stage pluggable pipeline. To incorporate a map widget, the best plugin point is a WidgetBuilder.

WidgetBuilders are passed all metadata for a given property, and try to return the most suitable widget. Or they can return nothing, and let another WidgetBuilder further down the chain have a try. In our case, we could inspect the property name (say, zip) and return either a map widget or nothing (in which case the standard HtmlWidgetBuilder can have a try).

Here's a complete example:

<html>
   <head>
      <script src="http://metawidget.org/js/3.7/metawidget-core.min.js"></script>
      <style>
         #metawidget {
            border: 1px solid #cccccc;
            width: 385px;
            border-radius: 10px;
            padding: 10px;
            margin: 50px auto;
         }
      </style>
   </head>
   <body>
      <div id="metawidget"></div>
      <script type="text/javascript">
         var config = {
            widgetBuilder: new metawidget.widgetbuilder.CompositeWidgetBuilder([
               function(elementName, attributes, mw) {

                     // If metadata indicates this property needs a map...

                     if (attributes.name === 'zip') {

                        // ...read the value...

                        var typeAndNames = metawidget.util.splitPath(mw.path);
                        var toInspect = metawidget.util.traversePath(mw.toInspect, typeAndNames.names);
                        var value = toInspect[attributes.name];

                        // ...and build a map widget

                        var img = document.createElement('img');
                        img.setAttribute('src', 'http://maps.googleapis.com/maps/api/staticmap?center=' + value + '&size=300x300&sensor=false');
                        return img;
                     }
               }
,
               new metawidget.widgetbuilder.HtmlWidgetBuilder()
            ])
         }
         var mw = new metawidget.Metawidget(document.getElementById('metawidget'), config);
         mw.toInspect = {
            firstname: 'Homer',
            surname: 'Simpson',
            zip: 90212
         };
         mw.buildWidgets();
      </script>
   </body>
</html>

This will display:

Of course in a real-world scenario inspecting a property's name may not be a good approach. Better to have some orthogonal metadata that determines whether to return a map widget. Metawidget supports many ways to supply such orthogonal metadata. Here's an example using JSON Schema:

<html>
   <head>
      <script src="http://metawidget.org/js/3.7/metawidget-core.min.js"></script>
      <style>
         #metawidget {
            border: 1px solid #cccccc;
            width: 385px;
            border-radius: 10px;
            padding: 10px;
            margin: 50px auto;
         }
      </style>
   </head>
   <body>
      <div id="metawidget"></div>
      <script type="text/javascript">
         var config = {
            inspector: new metawidget.inspector.CompositeInspector( [
               new metawidget.inspector.PropertyTypeInspector(),
               function() {
                  return { properties: { zip: { type: 'location' } } }
               }

            ] ),
            widgetBuilder: new metawidget.widgetbuilder.CompositeWidgetBuilder([
               function(elementName, attributes, mw) {

                     // If metadata indicates this property needs a map...

                     if (attributes.type === 'location') {

                        // ...read the value...

                        var typeAndNames = metawidget.util.splitPath(mw.path);
                        var toInspect = metawidget.util.traversePath(mw.toInspect, typeAndNames.names);
                        var value = toInspect[attributes.name];

                        // ...and build a map widget

                        var img = document.createElement('img');
                        img.setAttribute('src', 'http://maps.googleapis.com/maps/api/staticmap?center=' + value + '&size=300x300&sensor=false');
                        return img;
                     }
               },
               new metawidget.widgetbuilder.HtmlWidgetBuilder()
            ])
         }
         var mw = new metawidget.Metawidget(document.getElementById('metawidget'), config);
         mw.toInspect = {
            firstname: 'Homer',
            surname: 'Simpson',
            zip: 90212
         };
         mw.buildWidgets();
      </script>
   </body>
</html>

Hope that helps. Feedback welcome!

Saturday, January 4, 2014

Dynamic UI Generation: JQuery Mobile 1.4 Support

I ported one of my client's apps over to JQuery Mobile 1.4 today:
I was delighted to find Metawidget worked out-of-the-box, dynamically generating my UI screens for free. Plus everything received that new JQM modern look-and-feel goodness!