Bildschirmfoto 2025-03-07 um 18.51.45.

In FileMaker große Datenmengen zu verarbeiten, kann schnell zu Performance-Problemen führen. Besonders wenn FileMaker noch im Hintergrund sortiert oder aggregiert, kann die Benutzeroberfläche einfrieren oder es dauert mehrere Sekunden, bis die Daten sichtbar sind. Das Problem stellt sich immer wieder bei Altlösungen die 10 oder 20 Jahre alt sind. Häufig sind diese Datenbanken bis ins kleinste an die Kunden-Prozesse angepasst. Ein Neubau unrealistisch bis unbezahlbar. Performance-Probleme nur in den langen Listenansichten mit Unmengen an Datensätzen, diese dann noch mit Sortierungen und Formelfeldern.

Doch es gibt eine Möglichkeit, Daten sofort anzuzeigen, auch wenn FileMaker noch weiterarbeitet: Daten per POST an einen WebViewer übergeben und dort asynchron anzeigen.

Warum nicht einfach FileMaker-Listen?

Standardmäßig lädt FileMaker Listenansichten synchron – das heißt, es wartet, bis alle Datensätze verarbeitet sind. Das führt zu Problemen, wenn: • Tausende Datensätze geladen werden, • FileMaker noch sortiert, • eine Suche viele Treffer hat, • Zusatzinformationen aus mehreren Tabellen geladen werden müssen.

Die Lösung: Daten mit -X POST effizient an eine externe Webanwendung übergeben und dort direkt rendern – unabhängig davon, ob FileMaker noch weiter rechnet.

Datenübergabe aus FileMaker: So geht’s richtig

Wir nutzen den Insert from URL-Befehl, um die Daten per POST an eine Webanwendung zu übergeben. Hierbei setzen wir auf application/x-www-form-urlencoded, da diese Methode stabil mit großen Datenmengen arbeitet.

Set Variable [ $url ; Value: "http://meinserver.de/daten.php" ]  
Set Variable [ $payload ; Value:  
    "projects=" & $id_projects &  
    "&staff=" & $id_staff &  
    "&anlage=" & $anlage &  
    "&status=" & $status &  
    "&task=" & $id_task &  
    "&image=" & $image &  
    "&inhalt=" & $inhalt &  
    "&historyColors=" & $historyColors &  
    "&planungsmonat=" & $planungsmonat &  
    "&date_von=" & $date_von &  
    "&date_bis=" & $date_bis &  
    "&zeit_von=" & $zeit_von &  
    "&zeit_bis=" & $zeit_bis &  
    "&anzahl_staff=" & $anzahl_staff &  
    "&staff2=" & $id_staff_2 &  
    "&staff3=" & $id_staff_3 &  
    "&erstellt=" & $erstellt &  
    "&prio=" & $prio &  
    "¬es=" & $notes  
]  

Insert from URL [  
    $url ;  
    "-X POST " &  
    "--header \"Content-Type: application/x-www-form-urlencoded\" " &  
    "--data " & Zitat ( $payload )  
]  

Der Vorteil, ich kann unabhängig von URL-Begrenzungen Daten übergeben, ich erspare mir den Aufbau komplexer JSON-Strukturen innerhalb von FileMaker. Datentrennung geschieht bei mir vorzugsweise mit einem Pipe. Es ist natürlich auch anderes möglich. Datensammlung innerhalb von FileMaker über Schleifen, das verspricht bessere Kontrolle oder wenn es mal schnell gehen soll, geht natürlich auch die List-Funktion. Das ist aber Geschmacksache.

Unser PHP-Script empfängt die Daten und kann mit der Verarbeitung beginnen. Sobald die Daten per POST an PHP gesendet wurden, werden sie in einzelne Arrays zerlegt, sodass sie flexibel weiterverarbeitet werden können. Durch das entdecken von Strings anhand eines Trennzeichens (z. B. |) lassen sich in einer einzigen Anfrage übertragen:

$projects = isset($_POST['projects']) ? explode('|', $_POST['projects']) : [];  
$staff = isset($_POST['staff']) ? explode('|', $_POST['staff']) : [];  
$anlage = isset($_POST['anlage']) ? explode('|', $_POST['anlage']) : [];  
$status = isset($_POST['status']) ? explode('|', $_POST['status']) : [];  
$task = isset($_POST['task']) ? explode('|', $_POST['task']) : [];  
$image = isset($_POST['image']) ? explode('|', $_POST['image']) : [];  
$inhalt = isset($_POST['inhalt']) ? explode('|', $_POST['inhalt']) : [];  
$planungsmonat = isset($_POST['planungsmonat']) ? explode('|', $_POST['planungsmonat']) : [];  

Die Daten aus PHP werden dann über eine Schleife in HTML überführt. In diesem Beispiel erzeugen wir eine dynamische Tabelle, die aus den übergebenen Daten generiert wird:

<table border="1">
    <tr>
        <th>Projekt</th>
        <th>Aufgabe</th>
        <th>Mitarbeiter</th>
        <th>Status</th>
    </tr>
    <?php foreach ($task as $index => $taskName): ?>
        <tr>
            <td><?= htmlspecialchars($projects[$index] ?? 'Unbekannt') ?></td>
            <td><?= htmlspecialchars($taskName) ?></td>
            <td><?= htmlspecialchars($staff[$index] ?? 'Kein Mitarbeiter') ?></td>
            <td><?= htmlspecialchars($status[$index] ?? 'Unbekannt') ?></td>
        </tr>
    <?php endforeach; ?>
</table>

Mit ein wenig CSS kann die Liste angepasst werden, Zwischesortierungen, Statusfarben, nichts was nicht möglich ist.

.task-list { width: calc(100% - 20px); /* Verhindert das Überlaufen nach rechts / max-width: 100%; margin: 10px auto; background: white; padding: 10px; border-radius: 5px; box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2); font-size: 14px; overflow-x: hidden; / Falls nötig, um Überlauf zu vermeiden */ }

	.task-group {
		margin-top: 15px;
		padding: 8px;
		background: #3773B5;
		font-size: 14px;
		font-weight: bold;
		color: white;
		border-radius: 5px;
		text-align: left;
	}
	
	.task-item {
		width: 98%; /* Damit es nicht über den Container hinausragt */
		max-width: 100%;
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: 5px 10px;
		border-radius: 3px;
		box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
		font-size: 13px;
		line-height: 1.2;
		background-color: white;
		flex-wrap: wrap;
		box-sizing: border-box; /* Sorgt dafür, dass Padding berücksichtigt wird */
	}

Eine sequentielle Suche, die in ihrer Schnelligkeit niemals in FileMaker abzubilden ist, runden die Tabelle ab.

<script>
document.getElementById("taskSearch").addEventListener("keyup", function() {
    let searchQuery = this.value.toLowerCase();
    let taskGroups = document.querySelectorAll(".task-group-container");
    let resultCount = 0; // Zähler für die Anzahl der gefundenen Datensätze

    taskGroups.forEach(group => {
        let hasMatch = false;
        let tasks = group.querySelectorAll(".task-item");

        tasks.forEach(task => {
            let text = task.innerText.toLowerCase(); // Gesamten Inhalt durchsuchen
            if (text.includes(searchQuery)) {
                task.style.display = ""; // Zeigen
                hasMatch = true;
                resultCount++; // Treffer zählen
            } else {
                task.style.display = "none"; // Verstecken
            }
        });

        // Gruppe ausblenden, wenn keine Aufgabe übrig ist
        group.style.display = hasMatch ? "" : "none";
    });

    // Anzeige der Trefferanzahl aktualisieren
    document.getElementById("searchResultsCount").textContent = resultCount + " Ergebnisse gefunden";
});
</script>

Natürlich darf die Möglichkeit aus dem WebViewer heraus mit FileMaker zu kommunizieren nicht fehlen. In diesem Fall noch mit einer Bedingung.

document.addEventListener("DOMContentLoaded", function () {
    document.querySelectorAll(".status-dropdown").forEach(function (dropdown) {
        dropdown.addEventListener("change", function () {
            let taskId = this.getAttribute("data-task-id");
            let newStatus = this.value;

            if (newStatus === "Angebot folgt") {
                // PopOver anzeigen
                let modal = document.getElementById("offerModal");
                modal.style.display = "flex";

                // Speichern-Button im PopOver
                document.getElementById("confirmOffer").onclick = function () {
                    let priority = document.getElementById("offerPriority").value;
                    let note = document.getElementById("offerNote").value.trim();

                    if (note === "") {
                        alert(" Bitte eine Notiz eingeben!");
                        return;
                    }

                    modal.style.display = "none"; // Fenster schließen

                    // FileMaker-Skript aufrufen mit Priorität & Notiz
                    let fileMakerScriptURL = "fmp://$/AVAGmbH?script=UpdateTaskStatus¶m=" +
                        encodeURIComponent(taskId + "|" + newStatus + "|" + priority + "|" + note);

                    console.log(" FileMaker-Skript aufrufen:", fileMakerScriptURL);
                    window.location = fileMakerScriptURL;
                };

                // Abbrechen-Button im PopOver
                document.getElementById("cancelOffer").onclick = function () {
                    modal.style.display = "none"; // Fenster schließen
                    dropdown.value = "In Planung"; // Status zurücksetzen
                };

                return; // Stoppe die normale Ausführung, solange PopOver offen ist
            }

            // Falls NICHT "Angebot folgt", normales Verhalten
            let fileMakerScriptURL = "fmp://$/AVAGmbH?script=UpdateTaskStatus¶m=" +
                encodeURIComponent(taskId + "|" + newStatus);

            console.log("FileMaker-Skript aufrufen:", fileMakerScriptURL);
            window.location = fileMakerScriptURL;

            // Seite nach kurzer Verzögerung aktualisieren
            setTimeout(function () {
                window.location.reload();
            }, 1000);
        });
    });
});

Es gibt unendliche Optimierungsmöglichkeiten. Das wichtigste ist aber, wir können mit recht wenig Aufwand, alte schwergewichtige FileMaker-Anwendungen wieder flott machen.