From d2309e0b11e540154b9925e2b00ee3b4cf5e7407 Mon Sep 17 00:00:00 2001
From: Mathias Chouet <mathias.chouet@irstea.fr>
Date: Mon, 18 May 2020 09:35:11 +0200
Subject: [PATCH] Simplified ServiceFactory singleton

---
 src/app/app.component.ts                      | 12 +++---
 .../base-param-input.component.ts             |  4 +-
 .../calculator-list.component.ts              | 30 +++++++-------
 .../dialog-load-session.component.ts          |  2 +-
 .../fixedvar-results/results.component.ts     |  2 +-
 .../param-field-line.component.ts             |  6 +--
 .../jalhyd-model-validation.directive.ts      |  8 ++--
 .../formulaire/definition/form-definition.ts  |  4 +-
 src/app/formulaire/definition/form-section.ts |  2 +-
 .../definition/form-verificateur.ts           |  2 +-
 .../formulaire/elements/formulaire-element.ts |  2 +-
 src/app/formulaire/elements/ngparam.ts        |  4 +-
 .../elements/select-field-custom.ts           |  8 ++--
 src/app/formulaire/elements/select-field.ts   |  4 +-
 src/app/results/calculator-results.ts         |  6 +--
 src/app/results/macrorugo-compound-results.ts |  2 +-
 src/app/results/pab-results.ts                |  2 +-
 src/app/results/plottable-pab-results.ts      |  2 +-
 src/app/results/remous-results.ts             |  2 +-
 src/app/results/var-results.ts                | 14 +++----
 .../services/internationalisation.service.ts  |  2 +-
 src/app/services/service-factory.ts           | 41 +++++++++----------
 src/app/util.ts                               |  2 +-
 23 files changed, 80 insertions(+), 83 deletions(-)

diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index e90029baf..f308e323b 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -97,11 +97,11 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
     private matomoInjector: MatomoInjector,
     private matomoTracker: MatomoTracker
   ) {
-    ServiceFactory.instance.httpService = httpService;
-    ServiceFactory.instance.applicationSetupService = appSetupService;
-    ServiceFactory.instance.i18nService = intlService;
-    ServiceFactory.instance.formulaireService = formulaireService;
-    ServiceFactory.instance.notificationsService = notificationsService;
+    ServiceFactory.httpService = httpService;
+    ServiceFactory.applicationSetupService = appSetupService;
+    ServiceFactory.i18nService = intlService;
+    ServiceFactory.formulaireService = formulaireService;
+    ServiceFactory.notificationsService = notificationsService;
 
     if (! isDevMode()) {
       // évite de mettre en place un bandeau RGPD
@@ -150,7 +150,7 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
    */
   public static onHotkey(func: any, that: any) {
     return (event: KeyboardEvent): boolean => {
-      if (ServiceFactory.instance.applicationSetupService.enableHotkeys) {
+      if (ServiceFactory.applicationSetupService.enableHotkeys) {
         func.call(that);
         return false; // Prevent bubbling
       } else {
diff --git a/src/app/components/base-param-input/base-param-input.component.ts b/src/app/components/base-param-input/base-param-input.component.ts
index aab6cebb6..25573571b 100644
--- a/src/app/components/base-param-input/base-param-input.component.ts
+++ b/src/app/components/base-param-input/base-param-input.component.ts
@@ -69,7 +69,7 @@ export class NgBaseParam extends Observable {
 
         if (v === null || v === "") {
             // NULL values are always invalid
-            msg = ServiceFactory.instance.i18nService.localizeText("ERROR_PARAM_NULL");
+            msg = ServiceFactory.i18nService.localizeText("ERROR_PARAM_NULL");
         } else {
             try {
                 this._param.checkValueAgainstDomain(v);
@@ -77,7 +77,7 @@ export class NgBaseParam extends Observable {
             } catch (e) {
                 if (e instanceof Message) {
                     // ici au début le service de localisation n'a pas encore chargé ses messages…
-                    msg = ServiceFactory.instance.i18nService.localizeMessage(e);
+                    msg = ServiceFactory.i18nService.localizeMessage(e);
                 } else {
                     msg = "invalid value";
                 }
diff --git a/src/app/components/calculator-list/calculator-list.component.ts b/src/app/components/calculator-list/calculator-list.component.ts
index de8820b9d..e3c286fbe 100644
--- a/src/app/components/calculator-list/calculator-list.component.ts
+++ b/src/app/components/calculator-list/calculator-list.component.ts
@@ -31,15 +31,15 @@ export class CalculatorListComponent implements OnInit {
         private intlService: I18nService,
         private appSetupService: ApplicationSetupService
     ) {
-        ServiceFactory.instance.i18nService.addObserver(this);
-        ServiceFactory.instance.applicationSetupService.addObserver(this);
+        ServiceFactory.i18nService.addObserver(this);
+        ServiceFactory.applicationSetupService.addObserver(this);
     }
 
     /** triggered on init */
     private loadCalculatorsThemes() {
         this._items = [];
         const unusedCalculators = EnumEx.getValues(CalculatorType);
-        const themes = ServiceFactory.instance.applicationSetupService.themes;
+        const themes = ServiceFactory.applicationSetupService.themes;
         if (themes) {
             // group by themes
             for (const theme of themes) {
@@ -47,10 +47,10 @@ export class CalculatorListComponent implements OnInit {
                     // get theme details from config
                     const themeTitleKey = "INFO_THEME_" + theme.name + "_TITRE";
                     const themeDescriptionKey = "INFO_THEME_" + theme.name + "_DESCRIPTION";
-                    const credits = ServiceFactory.instance.i18nService.localizeText("INFO_THEME_CREDITS");
+                    const credits = ServiceFactory.i18nService.localizeText("INFO_THEME_CREDITS");
                     const item = {
-                        title: ServiceFactory.instance.i18nService.localizeText(themeTitleKey),
-                        description: ServiceFactory.instance.i18nService.localizeText(themeDescriptionKey),
+                        title: ServiceFactory.i18nService.localizeText(themeTitleKey),
+                        description: ServiceFactory.i18nService.localizeText(themeDescriptionKey),
                         image: {
                             path: "assets/images/themes/" + theme.image.path,
                             credits: credits + " : " + theme.image.credits
@@ -61,7 +61,7 @@ export class CalculatorListComponent implements OnInit {
                     for (const calcType of theme.calculators) {
                         item.calculators.push({
                             type: calcType,
-                            label: ServiceFactory.instance.formulaireService.getLocalisedTitleFromCalculatorType(calcType),
+                            label: ServiceFactory.formulaireService.getLocalisedTitleFromCalculatorType(calcType),
                             buttonId: "create-calc-" + calcType
                         });
                         // mark as used
@@ -79,8 +79,8 @@ export class CalculatorListComponent implements OnInit {
                 const unusedThemeConfig = themes.find(i => i.name === undefined);
                 const unusedTheme: any = {};
                 unusedTheme.calculators = [];
-                unusedTheme.title = ServiceFactory.instance.i18nService.localizeText("INFO_THEME_MODULES_INUTILISES_TITRE");
-                unusedTheme.description = ServiceFactory.instance.i18nService.localizeText("INFO_THEME_MODULES_INUTILISES_DESCRIPTION");
+                unusedTheme.title = ServiceFactory.i18nService.localizeText("INFO_THEME_MODULES_INUTILISES_TITRE");
+                unusedTheme.description = ServiceFactory.i18nService.localizeText("INFO_THEME_MODULES_INUTILISES_DESCRIPTION");
                 unusedTheme.image = {
                     path: "assets/images/themes/" + unusedThemeConfig.image.path
                 };
@@ -94,7 +94,7 @@ export class CalculatorListComponent implements OnInit {
                     ) {
                         unusedTheme.calculators.push({
                             type: t,
-                            label: ServiceFactory.instance.formulaireService.getLocalisedTitleFromCalculatorType(t),
+                            label: ServiceFactory.formulaireService.getLocalisedTitleFromCalculatorType(t),
                             buttonId: "create-calc-" + t
                         });
                     }
@@ -107,7 +107,7 @@ export class CalculatorListComponent implements OnInit {
     }
 
     public create(t: CalculatorType) {
-        const p: Promise<FormulaireDefinition> = ServiceFactory.instance.formulaireService.createFormulaire(t);
+        const p: Promise<FormulaireDefinition> = ServiceFactory.formulaireService.createFormulaire(t);
         p.then(f => {
             this.router.navigate(["/calculator", f.uid]);
             return f;
@@ -210,19 +210,19 @@ export class CalculatorListComponent implements OnInit {
     }
 
     public get uitextWelcomeSubtitle() {
-        return ServiceFactory.instance.i18nService.localizeText("INFO_WELCOME_SUBTITLE");
+        return ServiceFactory.i18nService.localizeText("INFO_WELCOME_SUBTITLE");
     }
 
     public get uitextWelcomeContent() {
-        return ServiceFactory.instance.i18nService.localizeText("INFO_WELCOME_CONTENT");
+        return ServiceFactory.i18nService.localizeText("INFO_WELCOME_CONTENT");
     }
 
     public get uitextExamplesTitle() {
-        return ServiceFactory.instance.i18nService.localizeText("INFO_EXAMPLES_TITLE");
+        return ServiceFactory.i18nService.localizeText("INFO_EXAMPLES_TITLE");
     }
 
     public get uitextExamplesSubtitle() {
-        return ServiceFactory.instance.i18nService.localizeText("INFO_EXAMPLES_SUBTITLE");
+        return ServiceFactory.i18nService.localizeText("INFO_EXAMPLES_SUBTITLE");
     }
 
     public onKC() {
diff --git a/src/app/components/dialog-load-session/dialog-load-session.component.ts b/src/app/components/dialog-load-session/dialog-load-session.component.ts
index a8f7aa817..35db621eb 100644
--- a/src/app/components/dialog-load-session/dialog-load-session.component.ts
+++ b/src/app/components/dialog-load-session/dialog-load-session.component.ts
@@ -148,7 +148,7 @@ export class DialogLoadSessionComponent {
         this.loadingError = false;
         this.loadingComplete = false;
 
-        const formService = ServiceFactory.instance.formulaireService;
+        const formService = ServiceFactory.formulaireService;
         formService.calculatorInfosFromSessionFile(this.file).then(
           calcInfos => {
             this.fileFormatVersion = calcInfos.formatVersion;
diff --git a/src/app/components/fixedvar-results/results.component.ts b/src/app/components/fixedvar-results/results.component.ts
index 550cff912..8ba53061a 100644
--- a/src/app/components/fixedvar-results/results.component.ts
+++ b/src/app/components/fixedvar-results/results.component.ts
@@ -102,7 +102,7 @@ export class ResultsComponentDirective {
         } else if (typeof p === "number") {
             originalValue = p;
         }
-        const nDigits = ServiceFactory.instance.applicationSetupService.displayPrecision;
+        const nDigits = ServiceFactory.applicationSetupService.displayPrecision;
         const minRenderableNumber = Number("1E-" + nDigits);
         // if required precision is too low, avoid rendering only zeroes
         if (originalValue < minRenderableNumber) {
diff --git a/src/app/components/param-field-line/param-field-line.component.ts b/src/app/components/param-field-line/param-field-line.component.ts
index a9dae488e..f0601b32a 100644
--- a/src/app/components/param-field-line/param-field-line.component.ts
+++ b/src/app/components/param-field-line/param-field-line.component.ts
@@ -22,8 +22,8 @@ import { ParamValuesComponent } from "../param-values/param-values.component";
 export class ParamFieldLineComponent implements OnChanges {
 
     constructor() {
-        this.intlService = ServiceFactory.instance.i18nService;
-        this._formService = ServiceFactory.instance.formulaireService;
+        this.intlService = ServiceFactory.i18nService;
+        this._formService = ServiceFactory.formulaireService;
         this.valid = new EventEmitter();
         this.inputChange = new EventEmitter();
     }
@@ -80,7 +80,7 @@ export class ParamFieldLineComponent implements OnChanges {
     }
 
     public get formHasResults(): boolean {
-        return ServiceFactory.instance.formulaireService.currentFormHasResults;
+        return ServiceFactory.formulaireService.currentFormHasResults;
     }
 
     @Input()
diff --git a/src/app/directives/jalhyd-model-validation.directive.ts b/src/app/directives/jalhyd-model-validation.directive.ts
index 71445d72f..758242ff9 100644
--- a/src/app/directives/jalhyd-model-validation.directive.ts
+++ b/src/app/directives/jalhyd-model-validation.directive.ts
@@ -110,7 +110,7 @@ export function jalhydModelValidatorMin(ngParam: NgParameter): ValidatorFn {
                 "jalhydModelMin": {
                     value: control.value,
                     message: sprintf(
-                        ServiceFactory.instance.i18nService.localizeText("ERROR_MINMAXSTEP_MIN"),
+                        ServiceFactory.i18nService.localizeText("ERROR_MINMAXSTEP_MIN"),
                         ngParam.domain.minValue,
                         ngParam.maxValue
                     )
@@ -130,7 +130,7 @@ export function jalhydModelValidatorMax(ngParam: NgParameter): ValidatorFn {
                 "jalhydModelMax": {
                     value: control.value,
                     message: sprintf(
-                        ServiceFactory.instance.i18nService.localizeText("ERROR_MINMAXSTEP_MAX"),
+                        ServiceFactory.i18nService.localizeText("ERROR_MINMAXSTEP_MAX"),
                         ngParam.minValue,
                         ngParam.domain.maxValue
                     )
@@ -153,8 +153,8 @@ export function jalhydModelValidatorStep(ngParam: NgParameter): ValidatorFn {
                 "jalhydModelStep": {
                     value: control.value,
                     message: sprintf(
-                        // ServiceFactory.instance.i18nService.localizeText("ERROR_MINMAXSTEP_STEP"),
-                        ServiceFactory.instance.i18nService.localizeText("ERROR_PARAM_MUST_BE_POSITIVE"),
+                        // ServiceFactory.i18nService.localizeText("ERROR_MINMAXSTEP_STEP"),
+                        ServiceFactory.i18nService.localizeText("ERROR_PARAM_MUST_BE_POSITIVE"),
                         ngParam.stepRefValue.toString()
                     )
                 }
diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
index 7de69e2b6..140741beb 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -108,7 +108,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
             "name": name
         }, this);
         // convenient trick to notify param-link components
-        ServiceFactory.instance.formulaireService.propagateFormNameChange(this, name);
+        ServiceFactory.formulaireService.propagateFormNameChange(this, name);
     }
 
     public get jsonConfig(): {} {
@@ -493,7 +493,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         // reset model results
         this.currentNub.resetResult();
         // reset the result panels of all forms depending on this one
-        ServiceFactory.instance.formulaireService.resetAllDependingFormsResults(this, visited, symbol, forceResetAllDependencies);
+        ServiceFactory.formulaireService.resetAllDependingFormsResults(this, visited, symbol, forceResetAllDependencies);
     }
 
     protected abstract compute();
diff --git a/src/app/formulaire/definition/form-section.ts b/src/app/formulaire/definition/form-section.ts
index 30cdd2c40..fd45ceb50 100644
--- a/src/app/formulaire/definition/form-section.ts
+++ b/src/app/formulaire/definition/form-section.ts
@@ -21,7 +21,7 @@ export class FormulaireSection extends FormulaireFixedVar {
             // show / hide dependent fields
             this.refreshFieldsets();
             // empty fields ? only those belonging to the specific section type
-            if (ServiceFactory.instance.applicationSetupService.enableEmptyFieldsOnFormInit) {
+            if (ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit) {
                 // "LargeurBerge" is hackily used as LargeurFond in Rectangular and Trapez sections, omit it here
                 this.emptyFields([ "Ks", "Q", "If", "YB", "iPrec", "Y" ]);
             }
diff --git a/src/app/formulaire/definition/form-verificateur.ts b/src/app/formulaire/definition/form-verificateur.ts
index ad7f3fffc..217298e80 100644
--- a/src/app/formulaire/definition/form-verificateur.ts
+++ b/src/app/formulaire/definition/form-verificateur.ts
@@ -39,7 +39,7 @@ export class FormulaireVerificateur extends FormulaireFixedVar {
     protected findPassVariatedParameters(): NgParameter[] {
         let pvp = []
         const passUid = this.verificateurNub.nubToVerify.uid;
-        const passForm = ServiceFactory.instance.formulaireService.getFormulaireFromNubId(passUid);
+        const passForm = ServiceFactory.formulaireService.getFormulaireFromNubId(passUid);
         pvp = passForm.getVariatedParameters();
         return pvp;
     }
diff --git a/src/app/formulaire/elements/formulaire-element.ts b/src/app/formulaire/elements/formulaire-element.ts
index ae565987e..95c14c76d 100644
--- a/src/app/formulaire/elements/formulaire-element.ts
+++ b/src/app/formulaire/elements/formulaire-element.ts
@@ -30,7 +30,7 @@ export abstract class FormulaireElement extends FormulaireNode {
     constructor(parent: FormulaireNode) {
         super(parent);
         this._isDisplayed = true;
-        this.intlService = ServiceFactory.instance.i18nService;
+        this.intlService = ServiceFactory.i18nService;
     }
 
     get isDisplayed(): boolean {
diff --git a/src/app/formulaire/elements/ngparam.ts b/src/app/formulaire/elements/ngparam.ts
index 183c4e241..063bd5796 100644
--- a/src/app/formulaire/elements/ngparam.ts
+++ b/src/app/formulaire/elements/ngparam.ts
@@ -44,7 +44,7 @@ export class NgParameter extends InputField implements Observer {
      */
     public static preview(p: ParamDefinition, compact: boolean = false): string {
         let valuePreview: string;
-        const i18n = ServiceFactory.instance.i18nService;
+        const i18n = ServiceFactory.i18nService;
 
         switch (p.valueMode) {
             case ParamValueMode.SINGLE:
@@ -102,7 +102,7 @@ export class NgParameter extends InputField implements Observer {
      */
     public static linkedValuePreview(ref: LinkedValue): string {
         let valuePreview: string;
-        const i18n = ServiceFactory.instance.i18nService;
+        const i18n = ServiceFactory.i18nService;
 
         if (ref.isParameter()) {
             const targetParam = (ref.element as ParamDefinition);
diff --git a/src/app/formulaire/elements/select-field-custom.ts b/src/app/formulaire/elements/select-field-custom.ts
index 47a73730d..7044c06d2 100644
--- a/src/app/formulaire/elements/select-field-custom.ts
+++ b/src/app/formulaire/elements/select-field-custom.ts
@@ -57,7 +57,7 @@ export class SelectFieldCustom extends SelectField {
      * Populates entries with available options
      */
     protected populate() {
-        const fs = ServiceFactory.instance.formulaireService;
+        const fs = ServiceFactory.formulaireService;
         let candidateNubs: any[];
         switch (this.source) {
 
@@ -133,8 +133,8 @@ export class SelectFieldCustom extends SelectField {
                             this._entriesBaseId + en.uid,
                             en.uid,
                             sprintf(
-                                ServiceFactory.instance.i18nService.localizeText("INFO_VERIFICATEUR_CUSTOM_SPECIES"),
-                                ServiceFactory.instance.formulaireService.getFormulaireFromNubId(en.uid).calculatorName
+                                ServiceFactory.i18nService.localizeText("INFO_VERIFICATEUR_CUSTOM_SPECIES"),
+                                ServiceFactory.formulaireService.getFormulaireFromNubId(en.uid).calculatorName
                             )
                         )
                     );
@@ -146,7 +146,7 @@ export class SelectFieldCustom extends SelectField {
                         new SelectEntry(
                             this._entriesBaseId + spgId,
                             FishSpecies[j],
-                            ServiceFactory.instance.i18nService.localizeText("INFO_ENUM_" + FishSpecies[j])
+                            ServiceFactory.i18nService.localizeText("INFO_ENUM_" + FishSpecies[j])
                         )
                     );
                 }
diff --git a/src/app/formulaire/elements/select-field.ts b/src/app/formulaire/elements/select-field.ts
index 70d1bf2d1..d80ba9707 100644
--- a/src/app/formulaire/elements/select-field.ts
+++ b/src/app/formulaire/elements/select-field.ts
@@ -158,7 +158,7 @@ export class SelectField extends Field {
                 // 1. calculated param
                 const ntc = (nub as Solveur).nubToCalculate;
                 if (ntc !== undefined && ntc.calculatedParam !== undefined) { // some nubs have no calculatedParam, for ex. SectionParam
-                    const varName = ServiceFactory.instance.formulaireService.expandVariableName(ntc.calcType, ntc.calculatedParam.symbol);
+                    const varName = ServiceFactory.formulaireService.expandVariableName(ntc.calcType, ntc.calculatedParam.symbol);
                     this.addEntry(new SelectEntry(
                         this._entriesBaseId + "none",
                         "",
@@ -168,7 +168,7 @@ export class SelectField extends Field {
                 // 2. extra results
                 if (ntc !== undefined && ntc.resultsFamilies !== undefined) {
                     for (const er of Object.keys(ntc.resultsFamilies)) {
-                        const varName = ServiceFactory.instance.formulaireService.expandVariableName(ntc.calcType, er);
+                        const varName = ServiceFactory.formulaireService.expandVariableName(ntc.calcType, er);
                         const e: SelectEntry = new SelectEntry(
                             this._entriesBaseId + er,
                             er,
diff --git a/src/app/results/calculator-results.ts b/src/app/results/calculator-results.ts
index e4b420907..36c23bbf9 100644
--- a/src/app/results/calculator-results.ts
+++ b/src/app/results/calculator-results.ts
@@ -24,10 +24,10 @@ export abstract class CalculatorResults {
             const children = referenceNub.getChildren();
             const parameterNub = p.paramDefinition.parentNub;
             if (children.includes(parameterNub)) {
-                const cn = capitalize(ServiceFactory.instance.i18nService.childName(parameterNub.parent));
+                const cn = capitalize(ServiceFactory.i18nService.childName(parameterNub.parent));
                 isChildParam = true;
                 const pos = parameterNub.findPositionInParent() + 1;
-                res = sprintf(ServiceFactory.instance.i18nService.localizeText("INFO_STUFF_N"), cn) + pos + " : ";
+                res = sprintf(ServiceFactory.i18nService.localizeText("INFO_STUFF_N"), cn) + pos + " : ";
             }
         }
         if (displaySymbol && ! isChildParam) {
@@ -58,7 +58,7 @@ export abstract class CalculatorResults {
     public getHelpLink(symbol: string): string {
         // add help link if any
         if (this.helpLinks !== undefined && this.helpLinks[symbol] !== undefined) {
-            const helpURL = "assets/docs/" + ServiceFactory.instance.applicationSetupService.language
+            const helpURL = "assets/docs/" + ServiceFactory.applicationSetupService.language
                 + "/calculators/" + this.helpLinks[symbol];
             // pseudo-<mat-icon> dirty trick because <mat-icon> renderer cannot be
             // triggered when code is set through innerHTML
diff --git a/src/app/results/macrorugo-compound-results.ts b/src/app/results/macrorugo-compound-results.ts
index a5c609205..8aba75366 100644
--- a/src/app/results/macrorugo-compound-results.ts
+++ b/src/app/results/macrorugo-compound-results.ts
@@ -52,7 +52,7 @@ export class MacrorugoCompoundResults extends MultiDimensionResults {
                     unit = p.unit;
                 }
             } catch (e) { /* silent fail */ }
-            let label = ServiceFactory.instance.formulaireService.expandVariableNameAndUnit(ct , h, unit);
+            let label = ServiceFactory.formulaireService.expandVariableNameAndUnit(ct , h, unit);
             label += this.getHelpLink(h);
             return label;
         });
diff --git a/src/app/results/pab-results.ts b/src/app/results/pab-results.ts
index bcf4b2b68..d08b381f1 100644
--- a/src/app/results/pab-results.ts
+++ b/src/app/results/pab-results.ts
@@ -52,7 +52,7 @@ export class PabResults extends MultiDimensionResults {
             if (sn.parent) {
                 ct = sn.parent.calcType;
             }
-            let label = ServiceFactory.instance.formulaireService.expandVariableNameAndUnit(ct , h);
+            let label = ServiceFactory.formulaireService.expandVariableNameAndUnit(ct , h);
             label += this.getHelpLink(h);
             return label;
         });
diff --git a/src/app/results/plottable-pab-results.ts b/src/app/results/plottable-pab-results.ts
index 7f52a5717..0d45afb05 100644
--- a/src/app/results/plottable-pab-results.ts
+++ b/src/app/results/plottable-pab-results.ts
@@ -31,7 +31,7 @@ export class PlottablePabResults implements PlottableData {
      */
     public getChartAxisLabel(symbol: string): string {
         if (symbol === "x") { // specific case for wall abscissa
-            return ServiceFactory.instance.i18nService.localizeText("INFO_LIB_ABSCISSE_CLOISON");
+            return ServiceFactory.i18nService.localizeText("INFO_LIB_ABSCISSE_CLOISON");
         } else {
             return this.pabResults.headers[this.pabResults.columns.indexOf(symbol)];
         }
diff --git a/src/app/results/remous-results.ts b/src/app/results/remous-results.ts
index a96934ca7..c6c9e3b8a 100644
--- a/src/app/results/remous-results.ts
+++ b/src/app/results/remous-results.ts
@@ -86,7 +86,7 @@ export class RemousResults extends CalculatorResults {
         // série de valeurs de X
         this._xValues = new ParamDefinition(
             p,
-            ServiceFactory.instance.i18nService.localizeText("INFO_REMOUSRESULTS_ABSCISSE"),
+            ServiceFactory.i18nService.localizeText("INFO_REMOUSRESULTS_ABSCISSE"),
             ParamDomainValue.POS_NULL
         );
     }
diff --git a/src/app/results/var-results.ts b/src/app/results/var-results.ts
index a6322e0f6..6e73b5d03 100644
--- a/src/app/results/var-results.ts
+++ b/src/app/results/var-results.ts
@@ -136,10 +136,10 @@ export class VarResults extends CalculatedParamResults implements PlottableData
             const pos = +match[1];
             // only parent translation file is loaded; look for children translations in it // ct = sn.getChildren()[pos].calcType;
             symbol = match[2];
-            const cn = capitalize(ServiceFactory.instance.i18nService.childName(sn));
-            ret += sprintf(ServiceFactory.instance.i18nService.localizeText("INFO_STUFF_N"), cn) + (pos + 1) + " : ";
+            const cn = capitalize(ServiceFactory.i18nService.childName(sn));
+            ret += sprintf(ServiceFactory.i18nService.localizeText("INFO_STUFF_N"), cn) + (pos + 1) + " : ";
         }
-        ret += ServiceFactory.instance.formulaireService.expandVariableNameAndUnit(ct, symbol);
+        ret += ServiceFactory.formulaireService.expandVariableNameAndUnit(ct, symbol);
         return ret;
     }
 
@@ -378,19 +378,19 @@ export class VarResults extends CalculatedParamResults implements PlottableData
                     unit = p.unit;
                 }
             } catch (e) { /* silent fail */ }
-            let rh = ServiceFactory.instance.formulaireService.expandVariableNameAndUnit(ct, k, unit);
+            let rh = ServiceFactory.formulaireService.expandVariableNameAndUnit(ct, k, unit);
             rh += this.getHelpLink(k);
             this._resultHeaders.push(rh);
         }
         // entêtes des résultats des enfants
         for (const c of sn.getChildren()) {
             if (c.result) {
-                const cn = capitalize(ServiceFactory.instance.i18nService.childName(sn));
+                const cn = capitalize(ServiceFactory.i18nService.childName(sn));
                 // using latest ResultElement; results count / types are supposed to be the same on every iteration
                 for (const k of c.result.resultElement.keys) {
-                    let rh = sprintf(ServiceFactory.instance.i18nService.localizeText("INFO_STUFF_N"), cn)
+                    let rh = sprintf(ServiceFactory.i18nService.localizeText("INFO_STUFF_N"), cn)
                         + (c.findPositionInParent() + 1) + " : "
-                        + ServiceFactory.instance.formulaireService.expandVariableNameAndUnit(ct, k);
+                        + ServiceFactory.formulaireService.expandVariableNameAndUnit(ct, k);
                     rh += this.getHelpLink(k);
                     this._resultHeaders.push(rh);
                 }
diff --git a/src/app/services/internationalisation.service.ts b/src/app/services/internationalisation.service.ts
index 321b572e0..7774b0069 100644
--- a/src/app/services/internationalisation.service.ts
+++ b/src/app/services/internationalisation.service.ts
@@ -176,7 +176,7 @@ export class I18nService extends Observable implements Observer {
         // replace "FORM_ID_X" by form name in current session, if any
         m = m.replace(/FORM_ID_(\w{6})/g, (match, p1) => {
             // cannot inject FormulaireService => cyclic dependency :/
-            const form = ServiceFactory.instance.formulaireService.getFormulaireFromNubId(p1);
+            const form = ServiceFactory.formulaireService.getFormulaireFromNubId(p1);
             let formName = "**UNKNOWN_FORM**";
             if (form !== undefined) {
                 formName = form.calculatorName;
diff --git a/src/app/services/service-factory.ts b/src/app/services/service-factory.ts
index 78d182b91..6d3c7b4ed 100644
--- a/src/app/services/service-factory.ts
+++ b/src/app/services/service-factory.ts
@@ -4,25 +4,22 @@ import { I18nService } from "./internationalisation.service";
 import { HttpService } from "./http.service";
 import { NotificationsService } from "./notifications.service";
 
-export class ServiceFactory {
-    private static _instance: ServiceFactory; // instance pour le pattern singleton
-
-    private constructor() { }
-
-    public applicationSetupService: ApplicationSetupService;
-
-    public formulaireService: FormulaireService;
-
-    public i18nService: I18nService;
-
-    public httpService: HttpService;
-
-    public notificationsService: NotificationsService;
-
-    public static get instance() {
-        if (ServiceFactory._instance === undefined) {
-            ServiceFactory._instance = new ServiceFactory();
-        }
-        return ServiceFactory._instance;
-    }
-}
+ /**
+  * A "Singleton" the TS way, that holds pointers to all services, to be accessed
+  * at any time by classes that do not support injection; fed by AppComponent at
+  * construction time
+  */
+ export const ServiceFactory: {
+    applicationSetupService: ApplicationSetupService;
+    formulaireService: FormulaireService;
+    i18nService: I18nService;
+    httpService: HttpService;
+    notificationsService: NotificationsService;
+ } = {
+    applicationSetupService: undefined,
+    formulaireService: undefined,
+    i18nService: undefined,
+    httpService: undefined,
+    notificationsService: undefined
+ };
+ 
\ No newline at end of file
diff --git a/src/app/util.ts b/src/app/util.ts
index 146002b23..48b0981cc 100644
--- a/src/app/util.ts
+++ b/src/app/util.ts
@@ -26,7 +26,7 @@ export function fv(p: NgParameter | number): string {
     } else if (typeof p === "number") {
         value = p;
     }
-    const nDigits = ServiceFactory.instance.applicationSetupService.displayPrecision;
+    const nDigits = ServiceFactory.applicationSetupService.displayPrecision;
 
     return formattedValue(value, nDigits);
 }
-- 
GitLab