I've been asked to blog about "select boxes versus radio buttons versus checkboxes" in Metawidget. There are two answers:
Answer #1: WidgetBuilders
UIs often have exacting requirements about which widgets to use. Metawidget is designed for this. It has a pluggable WidgetBuilder architecture allowing you to plug-in (and chain together) custom WidgetBuilders to handle just your custom case, and fall back to built-in WidgetBuilders for more general cases. So if you find yourself needing a particular custom widget: write a little WidgetBuilder.
Here's an example:
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js" type="text/javascript"></script>
<script src="http://metawidget.org/js/3.5/metawidget-core.min.js" type="text/javascript"></script>
<script src="http://metawidget.org/js/3.5/metawidget-angular.min.js" type="text/javascript"></script>
<script type="text/javascript">
angular.module( 'myApp', [ 'metawidget' ] )
.controller( 'myController', function( $scope ) {
$scope.metawidgetConfig = {
widgetBuilder: new metawidget.widgetbuilder.CompositeWidgetBuilder( [
function( elementName, attributes, mw ) {
if ( attributes.name === 'hobby' ) {
var select = document.createElement( 'select' );
select.innerHTML = '<option/><option>Beer</option><option>TV</option><option>Eating</option>';
return select;
}
},
new metawidget.widgetbuilder.HtmlWidgetBuilder()
] )
};
$scope.person = {
firstname: 'Homer',
surname: 'Simpson',
age: 36,
hobby: 'Beer'
};
$scope.save = function() {
console.log( $scope.person );
}
} );
</script>
<style>
#metawidget {
border: 1px solid #cccccc;
width: 250px;
border-radius: 10px;
padding: 10px;
margin: 50px auto;
display: block;
}
#metawidget button {
display: block;
margin: 10px auto 0px;
}
</style>
</head>
<body ng-controller="myController">
<metawidget id="metawidget" ng-model="person" config="metawidgetConfig">
<button ng-click="save()">Save</button>
</metawidget>
</body>
</html>
Note that Metawidget's WidgetProcessors (in this case AngularWidgetProcessor) are still able to automatically data-bind your custom widget. And your widget choice can key off any piece of metadata, not just attributes.name.
Answer #2: The Default
Having said that, the built-in WidgetBuilders do a decent job. You may find them sufficient for your use case. Here's an example of using JSON Schema metadata to create the same dropdown:
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js" type="text/javascript"></script>
<script src="http://metawidget.org/js/3.5/metawidget-core.min.js" type="text/javascript"></script>
<script src="http://metawidget.org/js/3.5/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.CompositeInspector( [
new metawidget.inspector.PropertyTypeInspector(),
new metawidget.inspector.JsonSchemaInspector( {
properties: {
hobby: {
enum: [ 'Beer', 'TV', 'Eating' ]
}
}
} )
] )
};
$scope.person = {
firstname: 'Homer',
surname: 'Simpson',
age: 36,
hobby: 'Beer'
};
$scope.save = function() {
console.log( $scope.person );
}
} );
</script>
<style>
#metawidget {
border: 1px solid #cccccc;
width: 250px;
border-radius: 10px;
padding: 10px;
margin: 50px auto;
display: block;
}
#metawidget button {
display: block;
margin: 10px auto 0px;
}
</style>
</head>
<body ng-controller="myController">
<metawidget id="metawidget" ng-model="person" config="metawidgetConfig">
<button ng-click="save()">Save</button>
</metawidget>
</body>
</html>
Widget choice is often dictated by data type. If you want checkboxes instead of a dropdown, then your data type needs to be an array rather than a string, so that the user can select multiple values:
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js" type="text/javascript"></script>
<script src="http://metawidget.org/js/3.5/metawidget-core.min.js" type="text/javascript"></script>
<script src="http://metawidget.org/js/3.5/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.CompositeInspector( [
new metawidget.inspector.PropertyTypeInspector(),
new metawidget.inspector.JsonSchemaInspector( {
properties: {
hobby: {
enum: [ 'Beer', 'TV', 'Eating' ]
}
}
} )
] )
};
$scope.person = {
firstname: 'Homer',
surname: 'Simpson',
age: 36,
hobby: [ 'Beer' ]
};
$scope.save = function() {
console.log( $scope.person );
}
} );
</script>
<style>
#metawidget {
border: 1px solid #cccccc;
width: 250px;
border-radius: 10px;
padding: 10px;
margin: 50px auto;
display: block;
}
#metawidget button {
display: block;
margin: 10px auto 0px;
}
</style>
</head>
<body ng-controller="myController">
<metawidget id="metawidget" ng-model="person" config="metawidgetConfig">
<button ng-click="save()">Save</button>
</metawidget>
</body>
</html>
Sometimes widget choice purely is aesthetic, though. If you want radio buttons instead of a select box, the built-in WidgetBuilder recognises a componentType metadata:
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js" type="text/javascript"></script>
<script src="http://metawidget.org/js/3.5/metawidget-core.min.js" type="text/javascript"></script>
<script src="http://metawidget.org/js/3.5/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.CompositeInspector( [
new metawidget.inspector.PropertyTypeInspector(),
new metawidget.inspector.JsonSchemaInspector( {
properties: {
hobby: {
enum: [ 'Beer', 'TV', 'Eating' ],
componentType: 'radio'
}
}
} )
] )
};
$scope.person = {
firstname: 'Homer',
surname: 'Simpson',
age: 36,
hobby: 'Beer'
};
$scope.save = function() {
console.log( $scope.person );
}
} );
</script>
<style>
#metawidget {
border: 1px solid #cccccc;
width: 250px;
border-radius: 10px;
padding: 10px;
margin: 50px auto;
display: block;
}
#metawidget button {
display: block;
margin: 10px auto 0px;
}
</style>
</head>
<body ng-controller="myController">
<metawidget id="metawidget" ng-model="person" config="metawidgetConfig">
<button ng-click="save()">Save</button>
</metawidget>
</body>
</html>
Feedback welcome!