Erfassen Sie Ihre Fortschritte
Trailhead-Startseite
Trailhead-Startseite

Erstellen einer Benutzeroberfläche für abhängige Auswahllisten

Lernziele

Nachdem Sie diese Lektion abgeschlossen haben, sind Sie in der Lage, die folgenden Aufgaben auszuführen:
  • Absetzen einer Anforderung an die User Interface API, um alle Auswahllistenwerte für einen Datensatztyp abzurufen
  • Nennen der Eigenschaft, die eine Zuordnung der abhängigen Felder eines Objekts enthält
  • Nennen der Eigenschaft, die eine Liste der Steuerfelder eines Felds enthält

Was ist so besonders an abhängigen Auswahllisten?

Es ist schwierig, eine Benutzeroberfläche für abhängige Auswahllistenfelder zu erstellen, doch mit der User Interface API ist es einfacher. Die Werte eines abhängigen Auswahllistenfelds werden auf der Grundlage einer Auswahl in einer anderen Auswahlliste oder einem Kontrollkästchen (dem so genannten Steuerfeld) gefiltert. Sehen Sie sich diesen Screenshot des abhängigen Auswahllisten-Editors in der Record Viewer-Anwendung an. Eine Auswahlliste "Country" steuert eine Auswahlliste "State/Province" (die von der Auswahlliste "Country" abhängt). Wenn ein Benutzer einen "Country"-Wert auswählt, werden die "State/Province"-Werte entsprechend gefiltert. Wenn ein Benutzer einen "State/Province"-Wert auswählt, bewirkt diese Auswahl die Filterung der "City"-Werte. Abhängiger Auswahllisten-Editor mit den Werten 'USA', 'California', 'Los Angeles'

Sie verstehen sicherlich die Grundidee dabei: Abhängige Auswahllisten beschleunigen das Ausfüllen eines Formulars, da die Werte gefiltert werden, so dass Sie weniger Zeit mit Scrollen verbringen. Und ein abhängiger Auswahllisten-Editor erleichtert die Bearbeitung zugehöriger Felder, besonders auf Mobilgeräten. Stellen Sie sich vor, wie schwierig es sein könnte, von Feld zu Feld zu scrollen, wenn sich abhängige Werte ändern. Es ist viel einfacher, alle zugehörigen Auswahllistenwerte in einem Dialogfeld zu ändern.

Aber genau diese Beziehungen zwischen den Steuerfeldern und den abhängigen Feldern sind es, die das Erstellen einer Benutzeroberfläche erschweren. Eine Auswahlliste (oder ein Kontrollkästchen) kann mehrere abhängige Auswahllisten steuern. Und eine abhängige Auswahllisten wird gesteuert, kann aber auch selbst steuern. Tatsächlich kann eine abhängige Auswahlliste mehrere andere abhängige Auswahllisten steuern. Die Hierarchie abhängiger Auswahllistenfelder hat eine Baumstruktur. Und ein Objekt kann einen ganzen Wald aus Bäumen besitzen.

Sinn und Zweck der User Interface API ist es, UI-Entwicklern das Leben leichter zu machen, und deshalb haben wir Eigenschaften offengelegt, die diese Feldbeziehungen beschreiben.
  • objectInfo.dependentFields enthält eine Zuordnung der abhängigen Felder eines Objekts.
  • objectInfo.fields[Feldname].controllingFields enthält eine Liste der Steuerfelder eines Felds.
Zudem haben wir eine Ressource bereitgestellt, die alle Auswahllistenwerte für einen bestimmten Datensatztyp abruft.
GET /ui-api/object-info/{objectApiName}/picklist-values/{recordTypeId}

Die Record Viewer-Anwendung nutzt diese Eigenschaften und die Ressource zum Erstellen ihres abhängigen Auswahllisten-Editors.

Verwenden des abhängigen Auswahllisten-Editors

Um den abhängigen Auswahllisten-Editor in der Record Viewer-Anwendung zu sehen zu bekommen, legen Sie eine abhängige Beziehung zwischen mindestens zwei Feldern eines Objekts an.

Erstellen Sie in Ihrem Trailhead Playground eine Feldabhängigkeit für das Account-Objekt. Anschließend bearbeiten wir einen Account in der Record Viewer-Anwendung, um den abhängigen Auswahllisten-Editor in Aktion zu sehen.

  1. Geben Sie in Setup den Begriff Objekt ein und wählen Sie Objekt-Manager aus.
  2. Wählen Sie Account | Felder & Beziehungen | Feldabhängigkeiten aus.
  3. Klicken Sie auf Neu.
  4. Nun erstellen wir eine Beziehung zwischen zwei bestehenden Feldern. Wählen Sie Bewertung als Steuerfeld aus. Als abhängiges Feld wählen Sie Customer Priority aus. Klicken Sie auf Weiter.
  5. Bearbeiten Sie die Feldabhängigkeiten so, dass die Spalte "Hot" die Angabe "High", die Spalte "Warm" die Angaben "Low" und "Medium" und die Spalte "Cold" die Angabe "Low" enthalten. Klicken Sie auf Speichern.Bearbeiten der Feldabhängigkeitsmatrix in Salesforce
  6. Öffnen Sie die Record Viewer-Anwendung und wählen Sie einen Account aus der Liste "Zuletzt verwendete Elemente".
  7. Klicken Sie auf Bearbeiten.
  8. Klicken Sie neben dem Feld "Accountbewertung" oder "Customer Priority" auf das Stiftsymbol. Stiftsymbol neben dem Feld 'Accountbewertung'

    Das Dialogfeld des abhängigen Auswahllisten-Editors wird geöffnet. Wählen Sie in diesem Dialogfeld Werte für beide Felder aus. Wenn Sie einen Wert für ein Feld auswählen, werden die Werte für das andere Feld auf Basis Ihrer Auswahl in Setup gefiltert.Abhängiger Auswahllisten-Editor mit den Feldern 'Accountbewertung' und 'Customer Priority'.

Wie abhängige Auswahllisten in der User Interface API sichtbar gemacht werden

Abhängige Auswahllistenfelder sind Teil einer Abhängigkeits-Baumstruktur, also einer Hierarchie aus Steuerfeldern und abhängigen Feldern. Jeder Knoten in einer Baumstruktur kann über beliebig viele untergeordnete Knoten verfügen. Ein Knoten ohne untergeordnete Knoten wird Blattknoten genannt.

Unsere Abhängigkeiten-Beispielstruktur ist einfach, da sie nur ein Stammfeld, Rating, enthält, das ein Feld, CustomerPriority__c, steuert. Würde Rating ein weiteres Feld steuern, sähe unsere Abhängigkeitshierarchie langsam wie eine Baumstruktur aus. Doch mit nur zwei Feldern hat unsere Abhängigkeits-Baumstruktur keine Zweige, sondern nur den Stamm. 'Rating' steuert 'CustomerPriority'

Ein Objekt kann über beliebig viele dieser Abhängigkeits-Baumstrukturen verfügen. Zum Erstellen einer Benutzeroberfläche, mit der Benutzer abhängige Auswahllisten bearbeiten können, müssen Sie die komplette Hierarchie jeder Baumstruktur kennen.

Das Account-Objekt könnte beispielsweise zwei Abhängigkeits-Baumstrukturen haben, einen mit dem Stammfeld "Land" und eine mit dem Stammfeld "Bewertung". Die Abhängigkeits-Baumstrukturen aus unseren Beispielen sind einfach, da jedes Steuerfeld nur ein abhängiges Feld steuert. Sie können sich jedoch sicherlich vorstellen, dass das Feld "Country" nicht nur das Feld "State/Province", sondern auch noch ein Feld "Language" und ein Feld "Time Zone" steuern könnte.

Wie Sie bereits wissen, gibt es in der User Interface API zwei Antworteigenschaften, die die Feldabhängigkeitsstruktur bereitstellen. Diese beiden Eigenschaften sind in der Nutzlast objectInfo enthalten, die Teil der Antwort von /ui-api/record-ui/{recordIds} ist. Zum Anzeigen der JSON-Antwort öffnen Sie ein Account-Objekt in der Record Viewer-Anwendung und klicken auf Show JSON. JSON in der RecordView-Anwendung

objectInfo.dependentFields
Diese Eigenschaft stellt die Baustrukturen für abhängige Felder eines Objekts bereit. Diese JSON-Beispielantwort enthält nur ein Stammfeld, Rating, ein Objekt kann jedoch mehrere Stammfelder haben.
"objectInfos" : {
    "Account" : {
      ...
      "dependentFields" : {
        "Rating" : {
          "CustomerPriority__c" : { }
        }
      },
      ...
Weist ein Objekt eine erweiterte Hierarchie abhängiger Felder auf, wie in unserem Beispiel mit "Country", "State/Province" und "City", verschachtelt die Eigenschaft dependentFields diese, bis sie einen Blattknoten wie "City" erreicht.
"objectInfos" : {
    "Account" : {
      ...
      "dependentFields": {
        "Country__c": {
          "StateProvince__c": {
            "City__c": {}
          }
        }
      },
      ...
objectInfo.fields[Feldname].controllingFields
Diese Eigenschaft liefert die Liste der Felder, die dieses spezielle Feld steuern, ausgehend von dem Feld, das dieses Feld unmittelbar steuert. In unserem einfachen Beispiel gibt es für das Feld CustomerPriority__c ein Steuerfeld: Rating.
"objectInfos" : {
    "Account" : {
      ...
      "fields" : {
       ...
        "CustomerPriority__c" : {
            "apiName" : "CustomerPriority__c",
            ...
            "controllingFields" : [ "Rating" ],
            ...
Weist ein Objekt eine erweiterte Hierarchie aus Steuerfeldern auf, wie in unserem Beispiel mit "Country", "State/Province" und "City", listet die Eigenschaft controllingFields diese ausgehend vom unmittelbaren Steuerfeld in der Reihenfolge ihres Auftretens auf.
"objectInfos" : {
    "Account" : {
      ...
      "fields" : {
       ...
        "City__c" : {
            "apiName" : "City__c",
            ...
            "controllingFields" : [ "StateProvince__c", "Country__c"],
            ...
Zusätzlich zu den Beziehungen zwischen den abhängigen Feldern müssen wir auch die Werte für jedes Auswahllistenfeld eines Objekts in Beziehung zu seinem unmittelbaren Steuerfeld kennen, da dies das Feld ist, das die Werte filtert. Die User Interface API bietet einen praktischen Endpunkt, mit dem wir alle diese Werte für einen Datensatztyp in einem einzigen Aufruf abrufen können.
GET /ui-api/object-info/{objectApiName}/picklist-values/{recordTypeId}
Dieser Auszug aus der JSON-Antwort zeigt die Werte für das Feld CustomerPriority__c.
"CustomerPriority__c" : {
      "controllerValues" : {
        "Hot" : 0,
        "Warm" : 1,
        "Cold" : 2
      },
      "defaultValue" : null,
      "url" : "/services/data/v48.0/ui-api/object-info/Account/picklist-values/012000000000000AAA/CustomerPriority__c",
      "values" : [ {
        "attributes" : null,
        "label" : "High",
        "validFor" : [ 0 ],
        "value" : "High"
      }, {
        "attributes" : null,
        "label" : "Low",
        "validFor" : [ 1, 2 ],
        "value" : "Low"
      }, {
        "attributes" : null,
        "label" : "Medium",
        "validFor" : [ 1 ],
        "value" : "Medium"
      } ]
    },

Die Eigenschaft controllerValues liefert die Auswahllistenwerte und Indizes des unmittelbaren Steuerfelds. In unserem Beispiel ist das Feld "Customer Priority" und das unmittelbare Steuerfeld ist "Rating". Die Werte für "Rating" sind Hot, Warm, und Cold und die Indizes 0, 1 und 2.

Für jeden "Customer Priority"-Wert (High, Low und Medium) enthält die Eigenschaft validFor die "Rating"-Werte, die bei Auswahl aus einer Auswahlliste den "Customer Priority"-Wert enthalten, anstatt ihn herauszufiltern.

Lautet der "Rating"-Wert beispielsweise Hot (0), wird die "Customer Priority"-Auswahlliste so gefiltert, dass sie nur den Wert High enthält. Lautet der "Rating"-Wert Warm (1), wird die "Customer Priority"-Auswahlliste so gefiltert, dass sie die Werte Low und Medium enthält. Bei einem "Rating"-Wert von Cold (2), wird die "Customer Priority"-Auswahlliste so gefiltert, dass sie nur den Wert Low enthält.

Wir wissen jetzt, welche Informationen wir benötigen und wie wir sie aus der User Interface API abrufen. Als Nächstes schauen wir uns an, wie die Record Viewer-Anwendung ihren abhängigen Auswahllisten-Editor erstellt.

Abrufen der Auswahllistenwerte

Wenn ein Benutzer auf Create, Clone oder Edit klickt, um einen Datensatz zu erstellen, zu duplizieren oder zu bearbeiten, ruft die Record Viewer-Anwendung die Auswahllistenwerte für alle Felder im Objekt für den angegebenen Datensatztyp ab.

Sie können sich den Code in RecordViewerWrapper.js ansehen. Suchen Sie nach einem Aufruf von dispatch(actions.fetchPicklists(creds, apiName, recordType)) für die einzelnen Szenarien: onNewRecordClick, onCloneClick und onEditClick.

Wenn Sie sich den Code ansehen möchten, der den UI API-URL zum Abrufen der Auswahllistenwerte bildet, schauen Sie sich die Saga picklistFetcher.js an.
/* /sagas/picklistFetcher.js */

let url = action.creds.instanceUrl + '/services/data/v48.0/ui-api/object-info/' 
          + action.apiName + '/picklist-values/' + action.recordType + '/';
Der Reducer "picklists.js" aktualisiert den Redux-Store mit den Auswahllistenwerten.
/* /reducers/picklists.js */

const picklists = (state = {values: undefined}, action) => {
  switch (action.type) {
    case 'RECEIVE_PICKLISTS':
      return {
        fieldValues : action.result.picklistFieldValues
      }
    case 'FETCH_PICKLISTS': // Clear values when new collection is requested.
      return {
        fieldValues: undefined
      }
    default:
      return state
  }
}

export default picklists

Anzeigen des abhängigen Auswahllisten-Editors

Wenn sich ein Datensatz im Edit-Modus befindet, zeigt die Anwendung neben abhängigen Feldern ein Stiftsymbol an, das angibt, dass der Benutzer den abhängigen Auswahllisten-Editor öffnen kann. Stiftsymbol neben abhängigen Auswahllistenfeldern

Wenn der Benutzer auf das Stiftsymbol klickt, öffnet die Anwendung den abhängigen Auswahllisten-Editor als modales Dialogfeld. Im Code wird der abhängige Auswahllisten-Editor als DepGraphEditor-Komponente bezeichnet.Abhängiger Auswahllisten-Editor

Der dafür zuständige Code befindet sich in der Komponente "RecordRow.js". Diese Komponente prüft, ob das Feld in einer Abhängigkeits-Baumstruktur enthalten ist, und identifiziert in diesem Fall das Stammfeld dieser Abhängigkeits-Baumstruktur. Der Code stellt das Stiftsymbol neben den Feldern dar und öffnet das modale Dialogfeld, wenn der Benutzer auf das Stiftsymbol klickt.
/* /components/RecordRow.js */

  if (objectInfo 
    && ((component.field && component.field in objectInfo.dependentFields)
       || (component.fieldInfo && component.fieldInfo.controllingFields.length > 0))) {
    // Last field in controlling fields is the root field
    let lastControllingIndex =  component.fieldInfo.controllingFields.length - 1
    let rootField = null
    if (component.field in objectInfo.dependentFields){
      rootField = component.field
    } else {
      rootField = component.fieldInfo.controllingFields[lastControllingIndex]
    }
    
    // Retrieve the picklist fields that need to show up.
    const subfieldTree = objectInfo.dependentFields[rootField]
    const modalFields = getFlattenedTree(objectInfo, subfieldTree, rootField)

    // Open a modal on click of the input field.
    let fieldTree = {}
    fieldTree[rootField] = subfieldTree

    return (
      <div>
        <label
          key={'componentInput' + itemLabel + ',' + i}
          onClick={(event) => onEditDepGraph(picklists, modalFields, editValues, fieldTree, uiMode.toString())}
          value={currPicklistValue}>
          {editValues[component.field].current}
        </label>
        <button className="fa fa-pencil"
        key={'componentInput' + itemLabel + 'button,' + i}
        onClick={(event) => onEditDepGraph(picklists, modalFields, editValues, fieldTree, uiMode.toString())}>
        </button>
      </div>
    );
  }

Zum Öffnen des modalen Dialogfelds ruft die Methode onClick() die Methode onEditDepGraph() auf, die die Aktion EDIT_DEP_GRAPH sendet, die den Modus in EditDepGraph ändern. Das modale Dialogfeld wird geöffnet, wenn der Modus geändert wird.

Die Modusänderung ist im Code des Reducers "record.js" zu sehen.
/* /reducers/record.js */

case 'EDIT_DEP_GRAPH':
  return {
    ...state,
    prevMode: action.prevMode, // save previous mode to return to on close
    mode: 'EditDepGraph'
  }
Der Code der Record-Komponente zeigt, wie das modale Dialogfeld bei der Modusänderung geöffnet wird. Dieser Code gibt die DepGraphEditor-Komponente für den Modus EditDepGraph zurück.
/* /components/Record.js */

<div>
    {uiMode === 'EditDepGraph' &&
      <DepGraphEditor 
          depGraph={depGraph}
          picklists={picklists}
          editValues={recordView.editValues}
          onFieldValueUpdate={onDepGraphFieldValueUpdate}
          onClose={() => onDepGraphClose(prevMode)}/> }

Aktualisieren der Auswahllistenwerte

Wenn ein Benutzer einen neuen Wert für ein Auswahllistenfeld auswählt, muss die Anwendung die Werte seiner untergeordneten Auswahllistenfelder aktualisieren. Und wenn diese untergeordneten Auswahllistenfelder wiederum über untergeordnete Auswahllistenfelder verfügen, muss die Anwendung auch diese aktualisieren, bis hinunter zu den Auswahllistenfeldern im Blattknoten, zu denen es keine untergeordneten Auswahllistenfelder mehr gibt. Um diese Aktualisierungen durchzuführen, ist es wichtig, die Abhängigkeits-Unterstruktur unter dem Feld zu kennen, dessen Wert sich geändert hat.

Wenn der vorausgewählte Wert für ein Feld weiterhin gültig bleibt, muss die Anwendung diesen Wert beibehalten.

Sie können sich den Code in der Saga depGraphValueUpdater.js anschauen. Der Code ruft die Abhängigkeits-Baumstruktur unter dem Feld mit dem neuen Wert mithilfe der Eigenschaft controllingFields und der Eigenschaft fieldTree ab, die mit der RecordRow-Komponente extrahiert wurde.
/* /sagas/depGraphValueUpdater.js */

// Traverse down to the target field in the tree.

const field = modalFieldsMap[action.field];
var treeNode = action.fieldTree;
for (var i = field.controllingFields.length -1; i>=0; i--) {
  var controllingField = field.controllingFields[i]
  treeNode = treeNode[controllingField];
}

treeNode = treeNode[action.field];

// Now treeNode is the subtree rooted at the target field.

Aus dieser extrahierten Unterstruktur und den Auswahllistenwerten, die abgerufen wurden, als der Benutzer auf Create, Clone oder Edit geklickt hat, um einen Datensatz zu erstellen, zu duplizieren oder zu bearbeiten, stellen wir die zulässigen Auswahllistenwerte für jedes Auswahllistenfeld in der Unterstruktur zusammen.

Im Abschnitt getLegalValues() von /helpers/depGraphHelper.js können Sie sich ansehen, wie die Anwendung die zulässigen Auswahllistenwerte für ein bestimmtes Feld abruft. Wenn Sie sehen möchten, wie der Code die Unterstruktur durchläuft und die zulässigen Werte für jedes untergeordnete Auswahllistenfeld rekursiv mithilfe einer breitangelegten ersten Suche auffüllt, schauen Sie sich die Saga depGraphValueUpdater.js an.

Herzlichen Glückwunsch! Sie haben es geschafft! Wir geben zu, dass wir das Erstellen einer Benutzeroberfläche für abhängige Auswahllisten nicht einfacher machen konnten als das Schneiden von Brot, hoffen aber, dass es einfacher ist als die Zubereitung eines Schokoladensoufflés und genauso lecker.

Kurze Zusammenfassung: Zur Erstellung der Benutzeroberfläche für einen abhängigen Auswahllisten-Editor stellt Ihnen die User Interface API alle erforderlichen Informationen an drei Stellen zur Verfügung, nämlich in der Eigenschaft objectInfo.dependentFields, in der Eigenschaft objectInfo.fields[Feldname].controllingFields und in der Antwort des Endpunkts /ui-api/object-info/{objectApiName}/picklist-values/{recordTypeId}.

Die User Interface API gibt Ihnen die Möglichkeiten und die Flexibilität, benutzerdefinierte Salesforce-Benutzeroberflächen zu erstellen, die Ihre Kunden begeistern. Wir hoffen, die Record Viewer-Anwendung ermöglicht Ihnen einen guten Einstieg. Scheuen Sie sich nicht, eigene Verzweigungen zum GitHub-Repo hinzuzufügen und Pull-Anforderungen abzusetzen. Wir freuen uns darauf, mehr über Ihre Anwendungen zu erfahren!