Power Apps: SharePoint Formular – App.OnStart, Screen.OnVisible, Concurrent, Patch, ForAll und UpdateIf

Bei der Anpassung eines SharePoint Formulars mit Hilfe von Power Apps erhält man im Power Apps Studio eine Power App mit folgenden Basis Elementen:

  • App: Das allgemeines Power Apps App Element mit z.B. der OnStart Methode
  • SharePointIntegration: Dieses Element ist nur bei SharePoint Fomularen enthalten. Es stellt einem die ID des selektieren SharePoint Elements (fast sofort) und das Element mit seinen Eigenschaften bereit.
  • FormScreen1: Nach der Anlage der erste und einzige Bildschirm der App.
  • SharePointForm1: Ein „Bearbeiten“ Formular, das mit der SharePoint Liste und dem aktuell selektierten Element verbunden ist. Man kann ein neues Element anlegen, ein vorhandenes anschauen oder bearbeiten.

Beim Benutzen der Power App, also im SharePoint beim Aufrufen von „Neu“, „Ansehen“ oder „Bearbeiten“ wird die Power App geladen und stellt sich je nach Einstellungen als neues eingebettetes Fenster von der rechten Seite des Fensters dar. Beim ersten Laden wird die App.OnStart Methode aufgerufen, danach die OnVisible Methode des FormScreen1.

ACHTUNG: OnVisible wird nicht nach Beendigung von App.OnStart aufgerufen, sondern einfach danach!!!

Das bedeutet, wenn Ihr in App.OnStart für Eure Anwendung noch Dinge vorladen wollt, die lange zum Laden dauern, dann könnt Ihr Euch in OnVisible vom FormScreen1 nicht darauf verlassen, dass die Werte bereits geladen sind und zur Verfügung stehen.

Beispiel: In einer SharePoint Liste soll es darum gehen, dass nur bestimmte Personen in einem mehrfach Personenfeld eingetragen werden können. Dazu erstellt man ein entsprechendes Personenfeld im SharePoint und könnte jetzt entweder festlegen, dass nur Personen aus einer benannten Gruppe verwendet werden dürfen, oder Ihr legt eine weitere Liste im SharePoint an, wo die Personen enthalten sind, die verwendet werden dürfen und nutzt diese in der Power App oder Ihr hinterlegt die Personen fest in der Power App.

Der Einfachheit halber hinterlegen wir die Personen in der App. Wir wollen den Namen und ein Foto zu der Person haben und die Personen in einer vertikalen Gallery anzeigen. Um an die Daten zu kommen, verwenden wir den Office365 Verbinder und befüllen in App.OnStart eine Sammlung mit den entsprechenden Daten.

Der Vorgang kann schon mal ein paar Sekunden dauern, so dass es hier Sinn macht, den Vorgang bei App.OnStart durchzuführen. Die jeweiligen Datensätze werden hier nacheinander geladen. Um das zu beschleunigen, könnte man die Concurrent Funktion verwenden.

Concurrent(

Collect(

colGenehmiger;{…}

};

Collect(

colGenehmiger;{…}

};

….

)

Das geht so aber nicht, weil man in Concurrent nicht zweimal ein Collect auf die gleiche Collection machen kann! Das App Studio gibt da eine Fehlermeldung aus!

Der Trick, um das zu umgehen ist, innerhalb von Concurrent verschiedene Collections zu befüllen und am Ende die Inhalte der einzelnen Collections in eine Ergebniscollection zu überführen. Das würde so aussehen:

Clear(colGenehmiger);; // Ergebniscollection
Clear(colGenehmiger2);;
Clear(colGenehmiger3);;
Clear(colGenehmiger4);;
Concurrent(
  Collect(
    colGenehmiger2;
    {
      Usermail: "<Email1>";
      Selected: false;
      Photo: If(
        'Office365-Benutzer'.UserPhotoMetadata("<Email1>").HasPhoto;
        'Office365-Benutzer'.UserPhotoV2("<Email1>");
        SampleImage
        );
      Name: 'Office365-Benutzer'.UserProfileV2("<Email1>").displayName
    }
  );
  Collect(
    colGenehmiger3;
    {
      Usermail: "<Email2>";
      Selected: false;
      Photo: If(
        'Office365-Benutzer'.UserPhotoMetadata("<Email2>").HasPhoto;
        'Office365-Benutzer'.UserPhotoV2("<Email2>");
        SampleImage
      );
      Name: 'Office365-Benutzer'.UserProfileV2("<Email2>").displayName
    }
  );
  Collect(
    colGenehmiger4;
    {
      Usermail: "<Email3>";
      Selected: false;
      Photo: If(
        'Office365-Benutzer'.UserPhotoMetadata("<Email3>").HasPhoto;
        'Office365-Benutzer'.UserPhotoV2("<Email3>");
        SampleImage
      );
      Name: 'Office365-Benutzer'.UserProfileV2("<Email2>").displayName
    }
  )
);;
Collect(
  colGenehmiger;
  colGenehmiger2;
  colGenehmiger3;
  colGenehmiger4
);;

Damit enthält am Ende von App.OnStart die Collection colGenehmiger die gewünschten Werte.

Diese Collection kann an eine Gallery gebunden werden und stellt dann z.B. den Namen und ein Bild der Person dar. Die Selected-Eigenschaft soll dann aufzeigen, ob die Person im Datensatz ausgewählt ist oder nicht. Das wird dadurch erreicht, das man das Feld aus dem SharePoint auswerten muss um zu schauen, welcher Person ist dort vorhanden und welches Selected Flag muss gesetzt werden. Das kann man beim Binden des von Power Apps generierten Kombinationsfeld machen. Dort in der OnChange Eigenschaft kann man mit Hilfe einer ForAll und Patch Konstruktion die Werte in der globalen Collection ändern:

ForAll(
ThisItem.Genehmiger As Genehmiger;
Patch(
colGenehmiger;
LookUp(
colGenehmiger;
Lower(Usermail) = Lower(Genehmiger.Email)
);
{Selected: true}
)
)

Dazu wird durch alle Elemente der SharePoint Spalte Genehmiger gegangen. Mit Hilfe der LoopUp Funktion werden dann in der globalen Liste jeweils die Elemente gesucht, die die gleich Mailadresse haben. Auf den gefundenen Einträgen (es sollte nur einen oder keinen Eintrage geben) wird die Eigenschaft Selected auf True gesetzt. Soweit so gut. Bei einem zweiten SharePoint Datensatz mit anderen Genehmigern werden allerdings die alten Selektionen nicht weggenommen. Hierzu müssen die Selected Werte der globalen Collection erstmal wieder auf false gesetzt werden, um die neuen Werte dann korrekt zu setzen.

Alles klar, dann mal los mit einem Patch! (1)

Patch(
   colGenehmiger;
   {Selected:true}
)

Damit passiert in der globalen Collection nichts. Mit folgendem (2):

ForAll(
  colGenehmiger;
  {
    Selected: true
  }
)

passiert auch nichts! Die Power App ist „korrekt“, es gibt keine Anzeige in der App Überprüfung, aber die Werte in der globalen Collection ändern sich nicht. Warum?

(1) Liefert einen Laufzeitfehler: Die der Funktion übergebene Datenquelle ist ungültig! Ist ja auch klar, es ist ein einzelner Datensatz als zweiter Parameter angegeben, der nicht in der globalen Collection ist, nur die Spalte „Selected“ mit dem Wert true enthält und mit nichts gepatched wird, da ein dritter Parameter fehlt.

(2) Diese ForAll Schleife durchläuft alle Elemente der globalen Collection und erstellt mit dem zweiten Parameter in geschweiften Klammern einen neuen Record, der aber nicht weiterverarbeitet wird (z.B. mit einem Collect). Man könnte hier über Collect eine neue Collection mit den Werten der alten Collection füllen, wo man nur die Selected Eigenschaft auf true setzt und alle anderen Werte beibehält. Sie ändern sich auch nicht. Am Ende würde man den Inhalt der alten Collection löschen und die neuen Werte dort zuweisen.

Man könnte könnte das übere ForAll/Patch/LookUp Konstrukt verwenden, das klappt jedoch nicht. Man bekommt im Power Apps Studio gleich die Anzeige: Diese Funktion kann nicht dieselbe Datenquelle bearbeiten, die in „ForAll“ verwendet wird.

Da gibt es bestimmt noch mehr in der Entwicklungszeit syntaktisch korrekte Formeln, die nicht das tun, was man erwartet. Wenn Ihr noch mehr habt, gerne als Kommentar hier drunter oder mir über Twitter zusenden.

Wie geht es nur einfach, die Werte in der globalen Collection zurückzusetzen? Die Verwendung von der Funktion UpdateIf ist einfach von der Syntax und tut was sie soll:

UpdateIf(colGenehmiger;true;{Selected:false})

UpdateIf bekommt die Datensammlung, einen Filter der true ergeben muss und die zu ändernde Eigenschaft mit dem neuen Wert in geschweiften Klammern als dritten Parameter. Mit der festen Wert true, werden alle Elemente genommen und die Filterung fällt werden, was etwas Performance spart. Schöne ist, die korrekte Filterung zu verwenden:

UpdateIf(colGenehmiger;Selected=true;{Selected:false})

Beachtet die jeweilige Schreibweise. Der zweite Parameter der UpdateIf Funktion ist eine Bedingung, die true ergeben muss und daher einen Vergleich über ein „=“ beinhaltet, wohingegen der dritte Parameter eine Wertezuweisung ist.

Falls Ihr solche oder ähnliche Dinge herausgefunden habt, lasst es mich gerne wissen!

Danke für´s Lesen!