Dateiuploads in Realtime-Formularen

Eine kreative Lösung für Dynamics 365 Customer Insights.

Wer mit Dynamics 365 Customer Insights arbeitet, weiß: Der Versand von Dateien über Realtime-Formulare ist eine häufige Anforderung – und doch fehlt diese Funktion im Standard. In diesem Blogartikel zeige ich dir einen Ansatz, wie du diese Lücke mit Kreativität und den richtigen Tools schließen kannst. Mit einer Kombination aus SharePoint, Power Automate und etwas JavaScript entwickle ich eine leicht anpassbare Lösung, die sich nahtlos in Dynamics 365 integrieren lässt.

Der Artikel basiert auf einer komplexeren Kundenlösung, wurde jedoch für diesen Blog vereinfacht, um die Kernfunktion verständlich und ohne unnötige Komplexität darzustellen. Du erhältst Schritt-für-Schritt-Anleitungen und praktische Tipps, wie du Dynamics 365 um eine leistungsstarke Funktion erweitern kannst. Und falls du alternative Wege oder Feedback hast, freue ich mich, davon zu hören!

Bist du bereit, Dynamics 365 um eine spannende Funktion zu erweitern? Dann lass uns loslegen!

Inhaltsverzeichnis

SharePoint Integration

Typischerweise werden Dokumente / Dateien über die SharePoint Integration im CRM abgebildet, nicht zuletzt um den kostengünstigeren SharePointspeicher verwenden zu können. Dateien, die auf diese Weise einem Datensatz zugeordnet werden, können im CRM über den Reiter „Dokumente“ innerhalb des Datensatzes angezeigt und verwendet werden. In diesem Ansatz nutze ich die SharePoint Integration, um die Datei in einem dem Lead zugeordneten Speicherort zu hinterlegen.

Damit dies möglich ist, muss die SharePoint Integration für die entsprechende Dataverseumgebung einmalig initialisiert werden, falls nicht bereits aktiv. Dazu kann eine neue SharePointseite angelegt werden und über den Wizard in den Dokumenteneinstellungen der erweiterten Einstellungen in Dynamics 365 mit der Umgebung verbunden werden. Wie dies im Einzelnen funktioniert, kann in der Microsoft Dokumentation nachgelesen werden.

Wir verwenden in unserem Beispiel ein Leadformular, die Lead-Tabelle ist standardmäßig für die SharePoint Integration aktiviert. Ich verwende hier den absoluten Standard der SharePoint Integration, es gibt also keine komplexen Abhängigkeiten von Dokumentorten oder Ähnliches. Jeder Lead erhält einen eigenen Dokumentort, dessen übergeordneter Dokumentort der allgemeine Ordner für Leads ist. Dieser übergeordnete Dokumentort kann im Rahmen der initialen Einrichtung manuell erstellt werden, falls er noch nicht existiert. Relevant ist dabei, dass die „Parent Site“ auf die Standardwebsite festgelegt wird und die relative URL mit dem Wert „lead“ definiert wird.

Nicht gemapptes Datei Inputfeld

Künftig wird es noch einfacher sein, sogenannte „unmapped fields“ zu Realtimeformularen hinzuzufügen, bis dahin kann dies aber bereits heute über entsprechende Manipulation des HTML Codes erreicht werden. Solange diese Felder normale Textinputfelder sind, werden die Ergebnisse sogar nach Dynamics 365 übertragen. Wie das geht, zeigt dieser fantastische Artikel von Peter Krause: Enhanced data collection and journey personalization with unmapped form fields. Ein ähnlicher Ansatz ermöglicht es, ein eigenes Feld mit dem Typ file zu integrieren. Da Realtime Formulare diesen Feldtyp ignorieren, übernehmen wir die Verarbeitung des Inhalts über ein eigenes Script.

Um ein passend gestyltes Feld zu erhalten, können wir irgendein zufälliges Textfeld im Editor zum Formular hinzuzufügen und dann den HTML Code an den markierten Stellen zu verändern, sodass es zu einem Datei Inputfeld wird und die ursprüngliche Zuordnung entfernt wird.

In diesem Beispiel verwende ich das Feld „Address 2 Line 3“ und verändere es den Anforderungen entsprechend.

// Vorher
<div
  class="textFormFieldBlock"
  data-editorblocktype="TextFormField"
  data-targetaudience="lead"
  data-targetproperty="address2_line3"
  data-prefill="false">
  <label title="Adresse 2: Straße 3" for="address2_line3-1735898935877">
    <div
      id="editorIdPrefixc402ba0e025bf1735899029321"
      aria-readonly="false"
      tabindex="0"
      spellcheck="true"
      aria-multiline="true"
      aria-describedby="cke_217"
      aria-controls="cke_218"
      aria-activedescendant=""
      aria-autocomplete="list"
      aria-expanded="false">
      File upload field
    </div>
  </label>
  <input
    id="address2_line3-1735898935877"
    type="text"
    name="address2_line3"
    placeholder=""
    title="Adresse 2: Straße 3"
    maxlength="250" />
</div>

// Nachher
<div
  class="textFormFieldBlock"
  data-editorblocktype="TextFormField"
  data-prefill="false">
  <label title="File Upload" for="fileupload">
    <div
      id="editorIdPrefixc402ba0e025bf1735899029321"
      aria-readonly="false"
      tabindex="0"
      spellcheck="true"
      aria-multiline="true"
      aria-describedby="cke_217"
      aria-controls="cke_218"
      aria-activedescendant=""
      aria-autocomplete="list"
      aria-expanded="false">
      File upload field
    </div>
  </label>
  <input
    id="fileupload"
    type="file"
    accept=".pdf"
    name="fileupload_field"
    title="File Upload" />
</div>

Nachdem das Feld in dieser Form angepasst wurde, sieht es im Formeditor so aus:

Script zum Versand der Datei

Wenn im Verlauf des Prozesses die Datei verarbeitet und an den Power Automate Flow geschickt wird, darf das Browserfenster nicht geschlossen werden. Um den Nutzer darauf aufmerksam zu machen, fügen wir ein Modal hinzu, welches wir später über das Script sichtbar machen, solange der Prozess läuft.

Anpassungen im HTML des Formulars

Als erstes fügen wir vor dem schließenden </body>-Tag folgendes <div>-Element ein.

<div id="uploadOverlay"></div>
<div id="uploadModal">
  <p>Please wait until file is uploaded.</p>
  <p id="uploadResponseText"></p>
</div>

Anpassungen im CSS des Formulars

Anschließend fügen wir den Styles des Formulars folgende Klassen hinzu. Das führt zu einem weißen Hintergrund und einem grauen Modal mit unserem Hinweistext. Standardmäßig ist das Modal unsichtbar und wird erst durch das Script sichtbar gemacht.

/* Styles for the overlay */
#uploadOverlay {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: white;
  z-index: 1000;
}

/* Styles for the Modal */
#uploadModal {
  display: none;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: #ededed;
  padding: 60px;
  border-radius: 10px;
  z-index: 1001;
  text-align: center;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  max-width: 400px;
  width: 90%;
}

/* Message text in modal */
#uploadModal p {
  margin: 0px;
  padding: 0px;
  line-height: 125%;
  line-height: 1.25;
  font-family: 'Segoe UI', Arial, sans-serif;
  font-size: 18px;
}

Script für den File Upload Handler

Das folgende Script ist ein möglichst simpler Ansatz, der dennoch die wesentliche Aspekte der Dateiverarbeitung berücksichtigt. Unterhalb des Scripts gehe ich auf die einzelnen Absätze kurz ein. Dieses Script muss im <body>-Tag direkt an erster Stelle untergebracht werden (Mehr Infos).

// Author: Johannes Fleischhut
// Date: January 2025
// Description: Simplified class to handle file uploads

class FileUploadHandler {
  constructor() {
    this.fileInput = document.querySelector('#fileupload');
    this.uploadUrl =
      '{YOUR FLOW REQUEST URL}'; // File upload endpoint from Power Automate Flow

    this.events();
  }

  events() {
    if (this.fileInput) {
      this.fileInput.addEventListener('change', () =>
        this._validateFile(this.fileInput)
      ); // Validate file on every change of the field

      document.addEventListener(
        'd365mkt-formsubmit',
        this._handleFormSubmit.bind(this)
      ); // Initiate event listener on form submission to start upload logic
    }
  }

  _validateFile(fileInput) {
    const file = fileInput.files[0];
    if (!file) return;

    const allowedExtension = 'pdf';
    const maxSize = 5 * 1024 * 1024; // Allowed file type and size (5MB)
    const fileExtension = fileName.split('.').pop(); // Extract the file extension from the file name
    const fileSize = file.size; // Get file details
    if (fileExtension !== allowedExtension || fileSize > maxSize)
      fileInput.value = ''; // Clear input if validation fails
  }

  async _handleFormSubmit(event) {
    const file = this.fileInput?.files[0]; // Get selected file

    const emailField = document.querySelector('input[name="emailaddress1"]');
    const lastNameField = document.querySelector('input[name="lastname"]');

    if (!file || !lastNameField || !emailField) return; // Exit if no file or no sufficient lead information

    this._showUploadModal(); // Display upload modal

    const createFilePayload = async () => {
      // Generate payload with file details
      const base64File = await new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = () => resolve(reader.result.split(',')[1]); // Extract base64 content
        reader.onerror = reject;
        reader.readAsDataURL(file);
      });
      return {
        leadLastName: lastNameField?.value,
        leadEmail: emailField?.value,
        fileName: file.name,
        fileType: file.type,
        fileSize: file.size,
        fileContent: base64File
      }; // Return formatted payload
    };

    try {
      const jsonPayload = await createFilePayload(); // Prepare JSON payload

      const response = await fetch(this.uploadUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(jsonPayload)
      }); // Send file to server

      const responseTextElement = document.getElementById('uploadResponseText'); // Get response text element

      if (response.ok) {
        const responseData = await response.json();
        responseTextElement.textContent = responseData.message;
      } // Show success message
      else
        responseTextElement.textContent = `Error during upload: ${response.statusText}`; // Show error message
      responseTextElement.style.display = 'block';
    } catch (error) {
      const responseTextElement = document.getElementById('uploadResponseText'); // Handle upload error
      responseTextElement.textContent = `Error during upload: ${error.message}`;
      responseTextElement.style.display = 'block';
    } finally {
      setTimeout(() => {
        this._hideUploadModal();
      }, 3000); // Hide modal after delay
    }
  }

  _showUploadModal() {
    document.getElementById('uploadOverlay').style.display = 'block';
    document.getElementById('uploadModal').style.display = 'block'; // Show modal
  }

  _hideUploadModal() {
    document.getElementById('uploadOverlay').style.display = 'none';
    document.getElementById('uploadModal').style.display = 'none'; // Hide modal
  }
}

// Initialize the class after the form is loaded
document.addEventListener('d365mkt-afterformload', function () {
  new FileUploadHandler();
}); // Create instance of FileUploadHandler

Erläuterungen zum Code

Zeilen 6-11Zuordnung des Datei Inputfelds und der individuellen Flow Request URL, die bei Erstellung des Flows generiert wird (dazu später mehr). Außerdem Aufrufen der events()-Methode als Startpunkt der Instanz der Klasse.
Zeilen 14-25Prüfen, ob das Input-Feld vorhanden ist und wenn ja, hinzufügen der EventListener.
Der erste EventListener sorgt bei jeder Veränderung des Input-Felds dafür, dass die hinterlegte Datei geprüft wird.
Der zweite EventListener sorgt bei Formularübermittlung dafür, dass die Upload Logik startet.
Zeilen 27 – 37Validierung der hinterlegten Datei. Wenn die Größe überschritten oder die erlaubte Dateiendung nicht erkannt wird, wird die Datei wieder entfernt. Dateien bis 10MB wurden getestet und konnten problemlos übertragen werden.
Zeilen 39 – 94Zunächst wird geprüft, ob die Datei, sowie notwendige Informationen zum Lead für die spätere Identifikation im Flow vorhanden sind. Wenn nicht, bricht der Code ab (Zeile 45).
Anschließend wird das Modal sichtbar gemacht (Zeile 47).
Die Zeilen 49-65 definieren eine Funktion, die alle für den Versand notwendigen Informationen in ein JSON-Payload gießt und dafür die hinterlegte PDF Datei in einen base64 String konvertiert.
Im folgenden Try-Block wird nun die zuvor definierte Funktion aufgerufen, als Ergebnis erhalten wir das benötigte Payload für den nun folgenden POST Request an den Power Automate Flow.
Gibt der Flow als Response sein „OK“, wird der Responsetext in unserem Modal hinzugefügt (Zeilen 78-81).
Falls der Flow einen Fehler zurückgibt, wird dieser Text entsprechend ausgegeben (Zeilen 82-84).
Läuft schon auf der Frontendseite etwas schief, wird der catch()-Teil ausgeführt (Zeilen 85-88) und ein entsprechender Fehlertext wird angezeigt.
Zum Schluss läuft ein Counter für 3 Sekunden um anschließend das Modal zu schließen (Zeilen 89-93).
Zeilen 96-104Hier werden die Methoden zum Anzeigen und Verstecken des Modals definiert.
Zeilen 107-110Hier wird nach erfolgreichem Laden des Realtime Formulars eine neue Instanz der zuvor definierten Klasse erstellt und somit der Code initialisiert.

Flow zum Verarbeiten der Datei

Trigger des Flows

Der zweite Part zur Verarbeitung der Datei erfolgt in einem Power Automate Flow. Als Startpunkt verwenden wir den Trigger „When a HTTP request is received“. In meinem Fall konnte ich den Trigger bei der Erstellung eines neuen Flows finden (warum auch immer). Sollte dieses Phänomen auftreten, nimm irgendeinen anderen Trigger, sodass Du in den Flow-Editor gelangst, lösche den Trigger und erstelle einen neuen. Hier habe ich den benötigten Trigger immer gefunden.

Damit der Trigger von überall aufgerufen werden kann, muss „Who can trigger the flow“ auf „Anyone“ eingestellt werden.

Um das „Request Body JSON Schema“ zu erstellen, nutze ich einen simplen Trick: Im ersten Schritt erstelle ich nur eine „Compose“-Action im Flow und definiere den Wert mit dem „body“ des Triggers. Nun teste ich erstmals den Flow, indem ich das Formular absende. Läuft alles korrekt, erhalte ich die von meinem Script erstellte JSON-Payload in meiner Compose-Action. Diese kann ich nun verwenden, um daraus automatisch das JSON-Schema zu generieren.

Für das oben erstellte Script gilt folgendes JSON Schema:

{
    "type": "object",
    "properties": {
        "leadLastName": {
            "type": "string"
        },
        "leadEmail": {
            "type": "string"
        },
        "fileName": {
            "type": "string"
        },
        "fileType": {
            "type": "string"
        },
        "fileSize": {
            "type": "integer"
        },
        "fileContent": {
            "type": "string"
        }
    }
}

Prüfen der Dateien

Nun muss die übermittelte Datei überprüft werden, dies ist insbesondere erforderlich, da die Logik zum Versand der Datei im Browser geschieht und somit rein theoretisch für jedermann einsehbar und manipulierbar ist. Wir müssen also auch aus der Serverseite sichergehen, dass die Datei unseren Richtlinien entspricht. Um dies so simpel wie möglich zu halten, dient folgende Condition dazu und schickt gleichsam den Response zurück an das Script. Wird der Test der Datei nicht bestanden, wird der Flow beendet.

Die Condition überprüft die Dateigröße, welche in Bytes übermittelt wird. 5MB entsprechen 5*1024*1024 = 5242880 Bytes. Der akzeptierte Dateityp ist „application/pdf“.

Response 200 OK

Status Code200
HeadersContent-Type: application/json
Body{
„message“: [WHATEVER MESSAGE YOU WANT TO SEND]
}

Response 403 Forbidden

Status Code403
HeadersContent-Type: application/json
Body{
„message“: [WHATEVER MESSAGE YOU WANT TO SEND]
}

Identifizierung des Leads

An dieser Stelle sollten wir uns bewusst machen, dass die Übermittlung des Realtimeformulars und der daraus resultierende Lead ein asynchroner Prozess ist, der eine Weile beansprucht. Wir haben im Flow keine Möglichkeit, den exakten Zeitpunkt festzustellen, wann der Lead erstellt wurde. Daher nutze ich an dieser Stelle gern eine „Do until“-Schleife, mit der ich eine Abfolge von Actions so lange wiederholen kann, bis ich zum gewünschten Ergebnis komme.

Wir benötigen eine neue Boolean-Variable „Lead exists“, die zunächst auf „false“ gesetzt wird. Die „Do until“-Schleife lassen wir nun so lange laufen, bis die Variable „true“ ist.

Innerhalb der Schleife suche ich nach einem Lead, der auf meine übermittelten Werte zutrifft. In diesem simplen Beispiel ist das die Kombination aus Nachname und Emailadresse. In einem etwas ausgereifteren Szenario könnte dafür auch ein eigenes Submission ID Feld genutzt werden, welches über das Script im Formular generiert wird und dann als Wert im Lead gespeichert wird.

Find lead

Table nameLeads
Selected columnsleadid,lastname,emailaddress1
Filter rowsemailaddress1 eq ‚@{triggerBody()?[‚leadEmail‘]}‘ and lastname eq ‚@{triggerBody()?[‚leadLastName‘]}‘
Row count1

Wird der Lead gefunden, wird die zuvor als „false“ initialisierte Variable „Lead exists“ auf „true“ gesetzt, außerdem speichere ich die Lead ID und den Nachnamen des Leads für spätere Zwecke. Wird der Lead nicht gefunden, setze ich ein Delay auf 30 Sekunden und wiederhole dann den Vorgang.

Wird der Lead über eine Stunde bzw. 60 Wiederholungen nicht gefunden, wird der Flow beendet. Dafür erstelle ich nach der „Do until“-Schleife eine Terminate-Action und konfiguriere „Run after“ so, dass sie nur im Falle eines Fehlers oder eines Timeouts ausgeführt wird.

// Condition
length(outputs('Find_lead')?['body/value']) eq 1

// Compose lead id
@{first(outputs('Find_lead')?['body/value'])?['leadid']}

// Compose lead lastname
@{first(outputs('Find_lead')?['body/value'])?['lastname']}

// Terminate missing lead
Status: Failes
Code: 404
Message: Lead could not be found.

Dokumentort erstellen

Zunächst müssen wir überprüfen, ob nicht evtl. bereits ein Dokumentort existiert, denn ansonsten würden wir einen zweiten anlegen, was zu Inkonsistenz führen würde. Im Normalfall wird der Dokumentort noch nicht existieren, da der Lead gerade erst angelegt wurde. Es ist dennoch theoretisch möglich, dass durch Nutzerverhalten oder andere Automatisierungen innerhalb des kurzen Zeitfensters nach Erstellung des Leads automatisch ein Dokumentort angelegt wurde. Um in diesem Fall nicht einen zweiten Dokumentort anzulegen, sondern den bereits existierenden zu nutzen, prüfen wir diese Situation.

Die Abfrage machen wir mit der „List rows“ Action und können den folgenden Fetch XML Query verwenden. Den dynamischen Wert für die Lead ID haben wir im vorherigen Scope festgelegt, in meinem Fall in der Action „Compose lead id“.

// Fetch XML
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
  <entity name="SharePointdocumentlocation">
    <order attribute="name" descending="false" />
    <filter type="and">
      <condition attribute="regardingobjectid" operator="eq" uitype="lead" value="@{outputs('Compose_lead_id')}" />
    </filter>
  </entity>
</fetch>

Im nächsten Schritt prüfen wir, ob ein Ergebnis gefunden wurde. Wurde kein Ergebnis gefunden, müssen wir einen neuen Dokumentort anlegen. Wurde ein Wert gefunden, legen wir die relative URL, die wir im nächsten Schritt zur Erstellung der Datei benötigen, auf den ersten gefundenen Wert fest.

Die relative URL für den neuen Dokumentort kann den eigenen Anforderungen nach frei generiert werden. In meinem Fall nutze ich die Form [Nachname]_[Lead ID]. Diese relative URL findet sich später als Pfad in der URL zum SharePoint Ordner wieder. Da wir die relative URL an diversen Stellen noch benötigen, binden wir den Wert in der Variable „Relative URL Document Location“.

// Condition
length(outputs('Find_lead')?['body/value']) eq 0

// Set relative URL to default value (links)
@{outputs('Compose_lead_lastname')}_@{outputs('Compose_lead_id')}

// Set relative URL to first found value (rechts)
@{first(outputs('Find_document_location_of_lead')?['body/value'])?['relativeurl']}

Nun können wir den Dokumentort anlegen. Folgende Parameter sind dafür notwendig:

Create document location

Table nameDocument Locations
Name@{variables(‚Relative URL Document Location‘)}
ServicetypSharePoint
Regarding (Lead)leads(@{outputs(‚Compose_lead_id‘)})
Relative URL@{variables(‚Relative URL Document Location‘)}
Parent Website or Document LocationSharePointdocumentlocations({GUID des übergeordneten Lead Dokumentorts})*

Create new folder

Anschließend muss der zugehörige SharePointordner noch entsprechend angelegt werden. Hierfür verwenden wir folgende Parameter:

Site AddressWähle die SharePointseite aus, die entweder bereits existierte oder die initial angelegt wurde.
List or LibraryLead
Folder Path@{variables(‚Relative URL Document Location‘)}

*Die GUID des übergeordneten Lead Dokumentorts kann am einfachsten aus der Browser URL gezogen werden.

Datei im SharePoint speichern

Da wir nun den Dokumentort im CRM und den korrespondierenden SharePoint Ordner identifiziert haben, bleibt uns abschließend nur noch, die Datei aus dem base64-String, der an den Flow übermittelt wurde, in diesem Ordner zu erstellen. Mit einer Compose-Action und der integrierten Funktion base64ToBinary() stellen wir den originalen Binärcode der Datei wieder her.

Anschließend nutzen wir die SharePoint Action „Create file“, um die Datei zu erstellen.

Compose binary

Inputs@{base64ToBinary(triggerBody()?[‚fileContent‘])}

Create file in SharePoint

Site AddressWähle die SharePointseite aus, die entweder bereits existierte oder die initial angelegt wurde.
Folder Path/lead/@{variables(‚Relative URL Document Location‘)}
File Name@{triggerBody()?[‚fileName‘]}
File Content@{outputs(‚Compose_binary‘)}

Geschafft! Sobald der Lead in Dynamics 365 geöffnet wird, kann die übermittelte Datei im Bereich „Related“ -> „Dokumente“ eingesehen werden.

Alternativ kann die Datei auch direkt im SharePointordner gefunden werden. Dazu gehe über „Site Contents“ – „Lead“ – „[Nachname]_[Lead ID]“.

Erweiterungsmöglichkeiten

Was für ein umfangreicher Artikel…der hier vorgestellte Prozess funktioniert und bietet eine grundlegende Möglichkeit, Dateien über Realtime Formulare im SharePoint Ordner des erstellten Leads zu speichern. Dennoch: während ich diesen Artikel geschrieben habe, habe ich mich von diversen Features aus dem Referenzprojekt verabschiedet, um nicht vollständig den Rahmen zu sprengen und mich auf die Basics konzentriert. Zu den entfernten Punkten gehören vor allem die ALM-Tauglichkeit des Flows, aber auch einigen Funktionen im Frontend, allen voran ein visualisiertes Userfeedback bei der Dateiprüfung. Im Folgenden liste ich einige Punkte auf, die den oben präsentierten Prozess noch verfeinern können und als Inspiration dienen sollen.

  • Ergänze eine visuelle Rückmeldung für die Frontend-Validierung, z. B. durch das Einblenden eines roten Textes, wenn die Datei die Anforderungen nicht erfüllt.
  • Erweitere den Prozess, um mehrere Dateien gleichzeitig verarbeiten zu können.
  • Mache den Flow ALM tauglich, sodass er aus der Entwicklungsumgebung problemlos in eine Produktionsumgebung importiert werden kann.
    • Umgebungsvariablen für die SharePointseiten und SharePointlibraries
    • Generieren von benötigten GUIDs im Flow selbst (z.B. Suchen des übergeordneten Dokumentorts für Leads anhand der relativen URL) oder Nutzung von Umgebungsvariablen
  • Nutze XMLHttpRequest statt FetchAPI für ein verbessertes Nutzerfeedback.
    • In diesem Script nutze ich die etwas einfachere FetchAPI Methode, um den POST Request abzusetzen. Alternativ kann XMLHttpRequest verwendet werden, welche einen entscheidenden Vorteil bietet: Sie kann während des Vorgangs den Fortschritt zurückgeben und ermöglicht es auf diese Weise, einen Fortschrittsbalken oder eine Prozentangabe einzubauen.
  • Erstelle das Modal inklusive Stylings vollständig über das Script, sodass der Code einfacher zu transportieren wird und nicht mehrere Stellen im Formular manuell angepasst werden müssen.
  • Verbessere die Identifikation des Leads durch ein eigenes Formsubmission ID Feld, welches live aus z.B. Email Adresse und dem aktuellen Timestamp generiert wird und sowohl im Lead gespeichert wird, als auch an den Flow übergeben wird zur eindeutigen Identifikation.
  • Baue zusätzliche Sicherheitsfunktionen ein, z.B. einen externen Virenscanner (SharePoint hat jedoch auch einen integriert) oder verlege den Code in den Serverbereich der Website, um die URL des Flows nicht offenzulegen.

Bild von pikisuperstar auf Freepik


Bleibe informiert

Verpasse keinen neuen Beitrag und abonniere einfach den Newsletter.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert