Services are similar to WebComponents except they have no user interface. They are mapped in solution code to the "plugins" scope - in order to be able to call their api from scripting.
A service must contain at least the specification file and the client-side js file.
The service specification file is mostly the same as for web components. See the specification (.spec file) section. However, as there is no UI, there is no support for handlers. Another difference is that default values and initial values for model properties are currently ignored for services.
It is recommended to have the suffix "services" in your service package name (for example default servoy services are found into "servoyservices" directory) - to avoid naming collisions between component and service packages. Furthermore, in order to avoid naming collisions among services themselves, a new service name should adhere to the same naming convention as WebComponents.
A service can get it's client side scope from the $services angular service/factory that the system provides. On that you can ask for the service scope:
When a service scope (the model object) is changed by a server push-to-client, or when a service api function is called, the system will call the angular $digest() function on the scope object of the service. This way all the watches that are on that service scope will be evaluated by angular. If your service can be used throughout the whole page - so webcomponents are using your service to get state from it (webcomponent do have watches on your service) then you have to make sure that you call the rootScope digest so that a full digest cycle will happen:
if (!$rootScope.$$phase) $rootScope.$digest();
The if is for checking if there is already a digest cycle happening, else you call the $rootScope $digest method so that all the watches of the page are evaluated and webcomponents or other services that have watches on your state will see the change.
Services can also have server side api - just like webcomponents, The same kind of object structure is then also provided, so there is a $scope object which has a model property that is the object that is synced between server and client.
An example service:
The service js file must define the api from the spec:
From scripting, when calling plugins.testservice.talk() it should execute the service talk method. The service model is automatically synchronized with the server. In order to observe server side modifications the service must add a watch to the service state.
A service can have a method called "cleanup" that will be called when solution is closed in order to clear its state.
It is possible to use TypeScript for writing the service code, see How to use TypeScript for Web Package projects