Not really a question but I could not find a lot of information in the documentation or the existing contributed projects.
I have a form with SIREN / SIRET fields (those are identification numbers for french companies). A siren is 9 digits and a siret is 14. I could easily use standard widgets for the length but that was all.
So I created a custom widget starting with pbInput standard widget (workspace/default/web_widgets). I removed minLength, maxLength, type, min value, max value and and added an inputType property which value can be siren or siret (default: siren).
The template I used is derivated from pbInput:
- <!-- The custom widget template is defined here
- - Custom widget properties defined on the right can be used as variables in a templates with properties.newProperty
- - Functions exposed in the controller can be used with ctrl.newFunction()
- -->
- <div ng-class="{
- 'form-horizontal': properties.labelPosition === 'left'&& !properties.labelHidden,
- 'row': properties.labelPosition === 'top'&& !properties.labelHidden || properties.labelHidden
- }">
- <div class="form-group">
- <label
- ng-if="!properties.labelHidden"
- ng-class="{ 'control-label--required': properties.required }"
- class="control-label col-xs-{{ !properties.labelHidden && properties.labelPosition === 'left' ? properties.labelWidth : 12 }}">
- {{ properties.label | uiTranslate }}
- </label>
- <div class="col-xs-{{ 12 - (!properties.labelHidden && properties.labelPosition === 'left' ? properties.labelWidth : 0) }}">
- <input
- type="text"
- class="form-control {{ properties.inputType }}"
- placeholder="{{ properties.placeholder | uiTranslate }}"
- ng-model="properties.value"
- name="{{ ctrl.name }}"
- sirensiret
- ng-required="properties.required"
- ng-readonly="properties.readOnly">
- <div ng-messages="$form[ctrl.name].$dirty&& $form[ctrl.name].$error" ng-messages-include="forms-generic-errors.html" role="alert">
- <div class="text-danger" ng-show="$form[ctrl.name].$error.integer">Cette valeur n'est pas un nombre valide</div>
- <div class="text-danger" ng-show="$form[ctrl.name].$error.inputLength">La longueur d'un {{ properties.inputType | uppercase }} est de {{ ctrl.inputLen }} chiffres.</div>
- <div class="text-danger" ng-show="$form[ctrl.name].$error.sirenSiretKey">La clé de validation de ce {{ properties.inputType | uppercase }} est invalide</div>
- </div>
- </div>
- </div>
- </div>
You will note the following changes: I added some new messages to the ng-messages div and added a "sirensiret" directive. I also added a class to detect input type.
The controller is really simple:
- /**
- * The controller is a JavaScript function that augments the AngularJS scope and exposes functions that can be used in the custom widget template
- *
- * Custom widget properties defined on the right can be used as variables in a controller with $scope.properties
- * To use AngularJS standard services, you must declare them in the main function arguments.
- *
- * You can leave the controller empty if you do not need it.
- */
- function($scope,$log, widgetNameFactory){
- this.name = widgetNameFactory.getName($scope.properties.inputType);
- this.inputLen =$scope.properties.inputType =='siren' ? 9:14;
- $log.error ("tiersSirenSiretInput controler is here to serve!");
- if(!$scope.properties.isBound('value')){
- $log.error('the pbInput property named "value" need to be bound to a variable');
- }
- }
This is almost the standard controller. I just initialize the default length for error messages.
Then I added a custom asset checkSirenSiret.js that add some directives to bonitasoft.ui.extensions:
- var app = angular.module ('bonitasoft.ui.extensions',[]);
- var INTEGER_REGEXP =/^\-?\d+$/;
- var SIREN_REGEXP =/^\d{9}$/;
- var SIRET_REGEXP =/^\d{14}$/;
- app.directive('sirensiret',function(){
- return{
- require:'ngModel',
- function validateSirenSiret(ngModelValue, ngViewValue){
- // Default is OK.
- ctrl.$setValidity('integer',true);
- ctrl.$setValidity('inputLength',true);
- ctrl.$setValidity('sirenSiretKey',true);
- // non empty => make additional controls!
- if(!ctrl.$isEmpty(ngModelValue)){
- // Only numbers
- ctrl.$setValidity('integer', INTEGER_REGEXP.test(ngModelValue));
- // Check length
- var isSiren = angular.element(elm).hasClass('siren');
- var lengthOk =false;
- if(isSiren){
- lengthOk = SIREN_REGEXP.test(ngModelValue);
- }else{
- lengthOk = SIRET_REGEXP.test(ngModelValue);
- }
- ctrl.$setValidity('inputLength', lengthOk);
- // Check key
- if(lengthOk){
- var i;
- var check =0;
- var x;
- for(i =0; i < nb.length; i++){
- x = nb[nb.length - i -1]*((i %2)+1);
- if(x <10){
- check += x;
- }else{
- }
- }
- if((check %10)!=0){
- ctrl.$setValidity('sirenSiretKey',false);
- }
- }
- }
- // Return ngModelValue to display it
- return ngModelValue;
- }
- ctrl.$parsers.push(validateSirenSiret);
- }
- };
- });
I use $parsers as it is a little bit more flexible than $validators (I would have to write multiple validators, I can use only one parser). Nothing special about this code: first check if the input is a number, then the length, then the Luhn key used to validate the input.
Hope this helps some others.