Child pages
  • Specification (.spec file)

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagejs
titlespec file definition
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
titledatafield.spec
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.