Page History
...
Code Block | ||||
---|---|---|---|---|
| ||||
name: String simple name of the component displayName: String more descriptive name that is shown in the designer definition: A reference to the js file of this component model: { propertyName: type description }, handlers: { functionName: function type }, api: { functionName: signature description }, types: { typename: { model: { propertyName: type description } } } |
Type A WebComponent specifies all its properties under the model . handlers all the events and api has the javascript api the webcomponent has that the server can call.
Types are internal complex object that describe a type that can be used as in a properties type description (for example a tabpanel component has a tab type that describes one tab inside the tabpanel) besides that the type description can be a simple type like:
string: A plain string property
tagstring: A string that can have tags inside it (so it will be processed by servoy to have tags replaced before it gets to the client)
color: A color property (#FFFFFF)
point: A point representation \{x:10,y:20\}
dimension: A dimension representation \{width:100,height:200\}
insets:
font:
border:
boolean: true/false
scrollbars:
byte:
double: A floating point number
float: A floating point number
int: A number
long: A number
short: A number
values: Fixed values can have real/display values.
dataprovider: Servoy maps this on a record or scope variable, This can be a complex object: \{ 'type':'dataprovider', 'ondatachange': \{ 'onchange':'onDataChangeMethodID', 'callback':'onDataChangeCallback'\}\} if support for ondatachange is needed.
valuelist: Servoy maps this on a valuelist referene
form: This property will hold a url point to a form (like a tab in a tabpanel)
format: format property, this must be specified with a complex object like: \{'for':'dataProviderID' ,'type':'format'\} so that we know which dataprovider property must be used to map this format property on
relation: Servoy maps this on a relation reference
media:
date: A date type property
For example if our field component can be expressed in html as:
Code Block |
---|
<datafield dataProviderID="record.order_id" toolTipText="hello world" onAction="true"/> |
which is expanded by angular to real html.
We only need to know the list of all parameters/properties and which types they are, so a beaninfo spec. (json) as below would suffice:The function description in the handlers section can be just "function" or a more complex type describing the arguments and return type {parameters: [{start: 'int'}, {end: 'int'}], returns: 'string'}
The signature description should also be like the complex function type, describing the arguments and return type {parameters: [{start: 'int'}, {end: 'int'}], returns: 'string'}
As an example we could have a datatextfield that has a definition like this
Code Block | ||
---|---|---|
| ||
name: 'datafielddatatextfield', displayName: 'DataText Fieldinput', definition: 'servoydefault/datafielddatatextfield/datafielddatatextfield.js', propertiesmodel: { dataProviderIDtoolTipText: "dataprovider"'string', toolTipTextbackground: "tagstring"'color', bgColor: "color", onAction: "function" dataProviderID: { 'type':'dataprovider', 'ondatachange': { 'onchange':'onDataChangeMethodID', 'callback':'onDataChangeCallback'}}, directionformat: { type: 'values', values [ { real: 1, display: 'left' }, { real: 2, display: 'right' } ] default: 0 } } |
Basically the stuff our content spec describes for element types.
Event handlers are pushed via handlers, for exanmple databutton.html:
Code Block |
---|
<input style="width:100%; height:100%; background-color:{{model.background}};" value="{{model.dataProviderID}}" type="button" title="{{model.toolTipText}}" ng-click="handlers.onActionMethodID($event)" /> |
The handler will return a promise object which can be used to get the value returned by the method on the server:
Code Block |
---|
'for':'dataProviderID' ,'type':'format'}, // value will be just the format string as a whole }, handlers: { onDataChangeMethodID: 'function', }, api: { requestFocus: { }, getSelectedText: { returns: 'string' }, setSelection: { parameters: [{start: 'int'}, {end: 'int'}] } } |
So it has a simple properties like toolTipText (a string) and background (a color) and a dataproviderID property that is of type 'dataprovider' which has an ondatachange that points to the handler onDataChangeMethodID function and the textfield wants to have a callback function called that is called 'onDataChangeCallback'
That field component will be expressed in the form html like this
Code Block |
---|
<datatextfield name="dataFieldFormatNumber" svy-model="model.dataFieldFormatNumber" svy-api="api.dataFieldFormatNumber" svy-handlers="handlers.dataFieldFormatNumber" svy-apply="handlers.dataFieldFormatNumber.svy_apply" svy-servoyApi="handlers.dataFieldFormatNumber.svy_servoyApi"/> |
which is expanded by angular to real html. So every webcomponent gets a number of objects pushed to the instance:
- model: This has all the properties set in the designer or at runtime (if they are data driven like a dataprovider property), it reflects the model object defined in the spec.
- handlers: This has all the event functions that are set in the designer like "onclick" or "ondatachange"
- api: On this object the webcomponents needs to add the api calls that the server can call. Like a requestFocus function.
- apply: This is a special method that a webcomponent can use to let the server know a property (of the model) is changed. So the value can be applied also on the server (pushed into the record), If a component has fields that uses ng-model then the directive "svy-autoapply" can be used in the html template instead of coding it out in the webcomponent javascript file.
- servoyApi: This is a component that holds some special servoy api functions to call, currently "setFormVisibility(form,visible,[relation]);
So the javascript file of the bean component can put those into its scope:
Code Block |
---|
servoyModule.directive('datatextfield', function($servoy) { return { restrict: 'E', transclude: true, scope: { model: "=svyModel", api: "=svyApi" }, controller: function($scope, $element, $attrs) { // fill in the api defined in the spec file $scope.api.callMyHandleronDataChangeCallback = function(evevent, returnval) { if(!returnval) { $element[0].focus(); var promise = this.handlers.onMyEvent(ev) } }, $scope.api.requestFocus = function() { $element[0].focus() }, promise.then($scope.api.getSelectedText = function(ret) { var elem = $element[0]; return elem.value.substr(elem.selectionStart, alert('Success: ' + ret); elem.selectionEnd - elem.selectionStart); } $scope.api.setSelection = function(start, end) { var elem = $element[0]; if (elem.createTextRange) { var selRange }, function(reason) {= elem.createTextRange(); selRange.collapse(true); alert('Failed: ' + reason selRange.moveStart('character', start); selRange.moveEnd('character', end); selRange.select(); elem.focus(); }, else if function(updateelem.setSelectionRange) { elem.focus(); elem.setSelectionRange(start, end); alert('Got notification: ' + update); } else if (typeof elem.selectionStart != 'undefined') { elem.selectionStart = start; elem.selectionEnd = end; } elem.focus(); } } } |
...
,
templateUrl: 'servoydefault/datatextfield/datatextfield.html',
replace: true
};
}) |
The model and api objects are stored in its own scope and then inside the controller function the various api calls are implemented besides the onDataChangeCallback function used as a callback of the ondatachange for a dataprovider.
The template then looks like this:
Code Block |
---|
<input type="text" style="width:100%; height:100%; background-color:{{model.background}};"
ng-model="model.dataProviderID" title="{{model.toolTipText}}"
svy-autoapply svy-format="model.format"/> |
Where the various properties are then taken from the model for specific html tags.
A handler call to the server does get a promise back (http://docs.angularjs.org/api/ng.$q) where the webcomponent could register a callback on so that an event that executes on the server can return a value to the webcomponents call.