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