**TITLE**: Define Multiple Table Views (SelectionVariants) for Analytical List Page (Single Table Mode)

**INTRODUCTION**: Configure multiple pre-filtered views for an Analytical List Page table using UI.SelectionVariant annotations and activate them in single table mode via manifest.json quickVariantSelection. Users can switch views through a segmented button (<=3 views) or a drop-down (>3 views). Optionally show counts per view.

**TAGS**: fiori-elements-framework, analytical-list-page, selectionvariant, manifest.json, annotations, OData V2, quickVariantSelection

**STEP**: 1 — Add SelectionVariant annotations to your annotations file

**DESCRIPTION**: Create UI.SelectionVariant records in your OData V2 annotations XML. Each SelectionVariant qualifier represents one view and must include a Text and SelectOptions specifying filter ranges. Add these records to your annotations file (e.g., annotations.xml) targeting the relevant entity type.

**LANGUAGE**: XML

**CODE**:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm" Target="SEPMRA_ALP_SO_ANA_SRV.SEPMRA_C_ALP_SlsOrdItemCubeALPResult">
   <Annotation Term="UI.SelectionVariant" Qualifier="Expensive">
      <Record>
         <PropertyValue Property="Text" String="Expensive" />
         <PropertyValue Property="SelectOptions">
            <Collection>
               <Record Type="UI.SelectOptionType">
                  <PropertyValue Property="PropertyName" PropertyPath="Product" />
                  <PropertyValue Property="Ranges">
                     <Collection>
                        <Record Type="UI.SelectionRangeType">
                           <PropertyValue Property="Sign" EnumMember="UI.SelectionRangeSignType/I" />
                           <PropertyValue Property="Option" EnumMember="UI.SelectionRangeOptionType/EQ" />
                           <PropertyValue Property="Low" String="HT-1000" />
                        </Record>
                     </Collection>
                  </PropertyValue>
               </Record>
            </Collection>
         </PropertyValue>
      </Record>
   </Annotation>
   <Annotation Term="UI.SelectionVariant" Qualifier="Cheap">
      <Record>
         <PropertyValue Property="Text" String="Cheap" />
         <PropertyValue Property="SelectOptions">
            <Collection>
               <Record Type="UI.SelectOptionType">
                  <PropertyValue Property="PropertyName" PropertyPath="Product" />
                  <PropertyValue Property="Ranges">
                     <Collection>
                        <Record Type="UI.SelectionRangeType">
                           <PropertyValue Property="Sign" EnumMember="UI.SelectionRangeSignType/I" />
                           <PropertyValue Property="Option" EnumMember="UI.SelectionRangeOptionType/EQ" />
                           <PropertyValue Property="Low" String="HT-1050" />
                        </Record>
                     </Collection>
                  </PropertyValue>
               </Record>
            </Collection>
         </PropertyValue>
      </Record>
   </Annotation>
   <Annotation Term="UI.SelectionVariant" Qualifier="Economic">
      <Record>
         <PropertyValue Property="Text" String="Economic" />
         <PropertyValue Property="SelectOptions">
            <Collection>
               <Record Type="UI.SelectOptionType">
                  <PropertyValue Property="PropertyName" PropertyPath="Product" />
                  <PropertyValue Property="Ranges">
                     <Collection>
                        <Record Type="UI.SelectionRangeType">
                           <PropertyValue Property="Sign" EnumMember="UI.SelectionRangeSignType/I" />
                           <PropertyValue Property="Option" EnumMember="UI.SelectionRangeOptionType/EQ" />
                           <PropertyValue Property="Low" String="HT-1002" />
                        </Record>
                     </Collection>
                  </PropertyValue>
               </Record>
            </Collection>
         </PropertyValue>
      </Record>
   </Annotation>
   <Annotation Term="UI.SelectionVariant" Qualifier="Budget">
      <Record>
         <PropertyValue Property="Text" String="Budget" />
         <PropertyValue Property="SelectOptions">
            <Collection>
               <Record Type="UI.SelectOptionType">
                  <PropertyValue Property="PropertyName" PropertyPath="Product" />
                  <PropertyValue Property="Ranges">
                     <Collection>
                        <Record Type="UI.SelectionRangeType">
                           <PropertyValue Property="Sign" EnumMember="UI.SelectionRangeSignType/I" />
                           <PropertyValue Property="Option" EnumMember="UI.SelectionRangeOptionType/EQ" />
                           <PropertyValue Property="Low" String="HT-1022" />
                        </Record>
                     </Collection>
                  </PropertyValue>
               </Record>
            </Collection>
         </PropertyValue>
      </Record>
   </Annotation>
</Annotations>
```

**STEP**: 2 — Configure quickVariantSelection in manifest.json to enable multiple views

**DESCRIPTION**: In your application manifest.json under "sap.ui.generic.app" → analytical list page settings, enable quickVariantSelection to reference the SelectionVariant annotations you created. Each variant entry must include a unique key and an annotationPath that points to UI.SelectionVariant with the qualifier (#QualifierName). This activates multiple view switching in single table mode.

**LANGUAGE**: JSON

**CODE**:
```json
"quickVariantSelection":{
   "variants":{
      "0":{
         "key":"_tab1",
         "annotationPath":"com.sap.vocabularies.UI.v1.SelectionVariant#Expensive"
      },
      "1":{
         "key":"_tab2",
         "annotationPath":"com.sap.vocabularies.UI.v1.SelectionVariant#Cheap"
      },
      "2":{
         "key":"_tab3",
         "annotationPath":"com.sap.vocabularies.UI.v1.SelectionVariant#Economic"
      },
      "3":{
         "key":"_tab4",
         "annotationPath":"com.sap.vocabularies.UI.v1.SelectionVariant#Budget"
      }
   }
},
```

**STEP**: 3 — (Optional) Enable counts per view

**DESCRIPTION**: To display the number of entries for each view, set showCounts to true inside quickVariantSelection. This will render counts next to each variant in the UI (both drop-down and segmented button).

**LANGUAGE**: JSON

**CODE**:
```json
"quickVariantSelection":{
   "showCounts": true,
   "variants":{
      "0":{
         "key":"_tab1",
         "annotationPath":"com.sap.vocabularies.UI.v1.SelectionVariant#Expensive"
      },
      "1":{
         "key":"_tab2",
         "annotationPath":"com.sap.vocabularies.UI.v1.SelectionVariant#Cheap"
      },
      "2":{
         "key":"_tab3",
         "annotationPath":"com.sap.vocabularies.UI.v1.SelectionVariant#Economic"
      },
      "3":{
         "key":"_tab4",
         "annotationPath":"com.sap.vocabularies.UI.v1.SelectionVariant#Budget"
      }
   }
},
```

**STEP**: 4 — UI behavior and recommendations

**DESCRIPTION**: Rendering behavior:
- If number of defined variants <= 3, the UI displays them as a segmented button.
- If number of variants > 3, the UI displays a drop-down list.
- showCounts true displays counts in either control type.
- Ensure annotation qualifiers match exactly in manifest.json annotationPath (use #Qualifier).

**LANGUAGE**: Text

**CODE**:
```text
- Segmented button when variants count <= 3
- Drop-down when variants count > 3
- Use annotationPath: "com.sap.vocabularies.UI.v1.SelectionVariant#<Qualifier>"
- Set "showCounts": true to show counts for each variant
```

**STEP**: 5 — Reference for OData V4

**DESCRIPTION**: For OData V4 or List Report single table mode, consult the Fiori Elements documentation: Defining Multiple Views on a List Report Table - Single Table Mode.

**LANGUAGE**: Text

**CODE**:
```text
See: Defining Multiple Views on a List Report Table - Single Table Mode (defining-multiple-views-on-a-list-report-table-single-table-mode-0d390fe.md)
```

fiori-elements-framework
analytical-list-page
selectionvariant
manifest.json
annotations
OData V2
quickVariantSelection


**TITLE**: Defining Multiple Views on a List Report Table (Multiple Table Mode)

**INTRODUCTION**: Steps and code examples to define multiple table views (tabs) on a Fiori Elements list report using SelectionVariant / SelectionPresentationVariant annotations and (optionally) UI.Chart annotations. Covers OData V2 (sap.ui.generic.app quickVariantSelectionX) and OData V4 (sap.fe.templates ListReport views.paths) manifest configurations, chart support (actions, navigation), stable ID behavior, and controlConfiguration usage.

**TAGS**: fiori-elements, annotations, UI.Chart, SelectionVariant, SelectionPresentationVariant, manifest.json, quickVariantSelectionX, multiple-table-mode, ODataV2, ODataV4

STEP: 1 — Define a UI.Chart annotation (optional, required if you want chart views)

DESCRIPTION: Create a UI.Chart annotation with a qualifier. Use XML, ABAP CDS, or CAP CDS depending on your project. Reference this chart in a SelectionPresentationVariant/PresentationVariant to show charts as a view.

LANGUAGE: XML

CODE:
```xml
<Annotation Term="UI.Chart" Qualifier="Chart1">
    <Record Type="UI.ChartDefinitionType">
        <PropertyValue Property="Title" String="Revenue by Customer"/>
        <PropertyValue Property="Description" String="Net Revenue by Customer"/>
        <PropertyValue Property="ChartType" EnumMember="UI.ChartType/Column"/>
        <PropertyValue Property="Dimensions">
            <Collection>
                <PropertyPath>ProductCategory</PropertyPath>
            </Collection>
        </PropertyValue>
        <PropertyValue Property="Measures">
            <Collection>
                <PropertyPath>NetAmount</PropertyPath>
            </Collection>
        </PropertyValue>
    </Record>
</Annotation>
```

LANGUAGE: ABAP CDS

CODE:
```abap
@UI.Chart: [
  {
    title: 'Revenue by Customer',
    description: 'Net Revenue by Customer',
    chartType: #COLUMN,
    dimensions: [
      'PRODUCTCATEGORY'
    ],
    measures: [
      'NETAMOUNT'
    ],
    qualifier: 'Chart1'
  }
]
annotate view SALESORDERMANAGE with {

}
```

LANGUAGE: CAP CDS

CODE:
```cds
UI.Chart #Chart1 : {
    $Type : 'UI.ChartDefinitionType',
    Title : 'Revenue by Customer',
    Description : 'Net Revenue by Customer',
    ChartType : #Column,
    Dimensions : [
        ProductCategory
    ],
    Measures : [
        NetAmount
    ],
}
```

STEP: 2 — Reference the UI.Chart from a SelectionPresentationVariant/PresentationVariant

DESCRIPTION: Reference the chart qualifier in PresentationVariant.Visualizations or SelectionPresentationVariant so it is available as a view. Use XML, ABAP CDS, or CAP CDS.

LANGUAGE: XML

CODE:
```xml
<Annotation Term="UI.SelectionPresentationVariant" Qualifier="Chart1">
    <Record>
        <PropertyValue Property="Text" String="Chart1"/>
            <PropertyValue Property="SelectionVariant">
                <Record>
                    ....
                </Record>
            </PropertyValue>
        <PropertyValue Property="PresentationVariant">
            <Record>
                <PropertyValue Property="Visualizations">
                    <Collection>
                        <AnnotationPath>@UI.Chart#Chart1</AnnotationPath>
                    </Collection>
                </PropertyValue>
            </Record>
        </PropertyValue>
    </Record>
</Annotation>
```

LANGUAGE: ABAP CDS

CODE:
```abap
@UI.selectionPresentationVariant: [{
  text: 'Chart1',
  selectionVariantQualifier: '',
  presentationVariantQualifier: 'Default',
  qualifier: 'Chart1'
}]

@UI.presentationVariant: [
  {
    qualifier: 'Default',
    sortOrder: [{by: 'GrossAmount', direction: #ASC }],
    visualizations: [{type: #AS_CHART, qualifier: 'Chart1'}]
  }
]
annotate view SALESORDERMANAGE with {

}
```

LANGUAGE: CAP CDS

CODE:
```cds
UI.SelectionPresentationVariant #Chart1 : {
    Text : 'Chart1',
    SelectionVariant : {
        ....
    },
    PresentationVariant : {
        Visualizations : [
            '@UI.Chart#Chart1'
        ]
    }
},
```

STEP: 3 — Add SelectionVariant / SelectionPresentationVariant annotations for tabs (OData V2 & V4)

DESCRIPTION: Define SelectionVariant or SelectionPresentationVariant annotations (with qualifiers if you want named variants). These provide the filtering, text, and presentation settings per tab. Supported SelectionRangeOptionTypes: EQ, BT, LE, GE, NE, GT, LT (no wildcards). PresentationVariant supports SortOrder and Visualizations.

LANGUAGE: XML

CODE:
```xml
<!-- Example SelectionVariant 'Expensive' filtering GrossAmount > 5000 -->
<Annotations Target="STTA_SALES_ORDER_ITEM_AGGR_SRV.STTA_C_SO_ItemAggrType">
<Annotation Term="UI.SelectionVariant" Qualifier="Expensive">
    <Record>
        <PropertyValue Property="Text" String="Expensive">
        </PropertyValue>
        <PropertyValue Property="SelectOptions">
            <Collection>
                <Record Type="UI.SelectOptionType">
                    <PropertyValue Property="PropertyName" PropertyPath="GrossAmount" />
                    <PropertyValue Property="Ranges">
                        <Collection>
                            <Record Type="UI.SelectionRangeType">
                                 <PropertyValue Property="Sign" EnumMember="UI.SelectionRangeSignType/E"/>
                                 <PropertyValue Property="Option" EnumMember="UI.SelectionRangeOptionType/LT"/>
                                 <PropertyValue Property="Low" String="5000"/>
                            </Record>
                        </Collection>
                    </PropertyValue>
                </Record>
            </Collection>
        </PropertyValue>
    </Record>
</Annotation>
```

LANGUAGE: XML

CODE:
```xml
<!-- Example SelectionPresentationVariant 'Cheap' with SelectionVariant and SortOrder -->
<Annotations Target="STTA_SALES_ORDER_ITEM_AGGR_SRV.STTA_C_SO_ItemAggrType">
<Annotation Term="UI.SelectionPresentationVariant" Qualifier="Cheap">
    <Record>
        <PropertyValue Property="Text" String="Cheap">
        </PropertyValue>
        <PropertyValue Property="SelectionVariant">
            <Record>
                <PropertyValue Property="Text" String="Cheap">
                </PropertyValue>
                <PropertyValue Property="SelectOptions">
                    <Collection>
                        <Record Type="UI.SelectOptionType">
                            <PropertyValue Property="PropertyName"
                                PropertyPath="GrossAmount" />
                            <PropertyValue Property="Ranges">
                                <Collection>
                                    <Record Type="UI.SelectionRangeType">
                                        <PropertyValue Property="Option"
                                            EnumMember="UI.SelectionRangeOptionType/LT" />
                                        <PropertyValue Property="Low" String="5000" />
                                    </Record>
                                </Collection>
                            </PropertyValue>
                        </Record>
                    </Collection>
                </PropertyValue>
            </Record>
        </PropertyValue>
        <PropertyValue Property="PresentationVariant">
            <Record>
                <PropertyValue Property="SortOrder">
                    <Collection>
                        <Record>
                            <PropertyValue Property="Property"
                                PropertyPath="GrossAmount" />
                            <PropertyValue Property="Descending" Bool="false" />
                        </Record>
                    </Collection>
                </PropertyValue>
            </Record>
        </PropertyValue>
    </Record>
</Annotation>
</Annotations>
```

LANGUAGE: ABAP CDS

CODE:
```abap
@UI.selectionPresentationVariant: [{
  id: '',
  text: 'Cheap',
  selectionVariantQualifier: 'Default',
  presentationVariantQualifier: 'Default',
  qualifier: 'Cheap'
}]

@UI.selectionVariant: [
  {
    text: 'Cheap',
    qualifier: 'Default'
  }
]

@UI.presentationVariant: [
  {
    qualifier: 'Default',
    sortOrder: [{by: 'GrossAmount', direction: #ASC }]
  }
]
annotate view SALESORDERMANAGE with {

}
```

STEP: 4 — Enable multiple table mode in manifest.json for OData V2 (quickVariantSelectionX)

DESCRIPTION: In manifest.json under sap.ui.generic.app > pages > settings use quickVariantSelectionX. Define variants objects where each variant has a mandatory "key" and "annotationPath" pointing to the SelectionVariant or SelectionPresentationVariant annotation. Keys are used to suffix stable IDs for per-tab table instances (avoid duplicates). Example snippet shows two variants "Expensive" and "Cheap".

LANGUAGE: JSON

CODE:
```json
1 ...
2 "sap.ui.generic.app": {
3     "pages": [
4         {
5             "entitySet": "C_STTA_SalesOrder_WD_20",
6             "component": {
7                 "name": "sap.suite.ui.generic.template.ListReport",
8                 "list": true,
9                 "settings": {
10                    "quickVariantSelectionX": {
11                        "variants": {
12                            "Expensive": {
13                                "key": "Expensive",
14                                "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant#Expensive"
15                            },
16                            "Cheap": {
17                                "key": "Cheap",
18                                "annotationPath": "com.sap.vocabularies.UI.v1.SelectionPresentationVariant#Cheap"
19                            }
20                        }
21                    }
22                    ...
```

NOTE: Use keys composed of letters, digits, underscores and not starting with a digit. Table-specific IDs will get suffix "-<key>".

STEP: 5 — Enable multiple table mode in manifest.json for OData V4 (sap.fe.templates ListReport views.paths)

DESCRIPTION: For OData V4 / sap.fe, define views in the ListReport target options.settings > views.paths. Each path object requires "key" and "annotationPath". You can set "showCounts" and "keepPreviousPersonalization". Configure controlConfiguration per annotation visualization to set table types and settings.

LANGUAGE: JSON

CODE:
```json
"SalesOrderManageList": {
    "type": "Component",
    "id": "SalesOrderManageList",
    "name": "sap.fe.templates.ListReport",
    "options": {
        "settings": {
            "contextPath": "/SalesOrderManage",
            "views": {
                "paths": [
	            {
	                "key": "tab1",
	                "annotationPath":        "com.sap.vocabularies.UI.v1.SelectionVariant#Good"
	            },
	            {
	                "key": "tab2",
	                "annotationPath": "com.sap.vocabularies.UI.v1.SelectionPresentationVariant#UncompletePV"
	            },
	            {
	                "key": "tab3",
	                "annotationPath": "com.sap.vocabularies.UI.v1.SelectionPresentationVariant#PVandSV"
	            }
	        ],
	        "showCounts" : false
	    },
	    "controlConfiguration": {
	        ...
            }
	},
	...
    }
}
```

DESCRIPTION (controlConfiguration example): Map an annotation visualization ID to a tableSettings block to customize table type and features.

LANGUAGE: JSON

CODE:
```json
"controlConfiguration": {
   "@com.sap.vocabularies.UI.v1.LineItem#withPrice ": {
      "tableSettings": {
         "type": "ResponsiveTable",
         "enableExport": false,
          ...
      },
   }
}
```

STEP: 6 — Charts in multiple table mode: actions and navigation

DESCRIPTION: Charts support annotation-defined actions (UI.Chart/Actions) and custom extension-point actions. For chart navigation, set showItemNavigationOnChart=true on that variant's manifest entry and define an internal navigation target in manifest. Ensure chart service/entity is not draft-enabled or read-only.

LANGUAGE: XML

CODE:
```xml
<Annotation Term="UI.Chart" Qualifier="Chart4">
    <Record Type="UI.ChartDefinitionType">
        <PropertyValue Property="ChartType" EnumMember="UI.ChartType/Column"/>
        <PropertyValue Property="Dimensions">
            <Collection>
                <PropertyPath>CompanyCode</PropertyPath>
                <PropertyPath>Customer</PropertyPath>
            </Collection>
        </PropertyValue>
        <PropertyValue Property="Measures">
            <Collection>
                <PropertyPath>AmountInTransactionCurrency</PropertyPath>
            </Collection>
        </PropertyValue>
        <PropertyValue Property="Actions">
            <Collection>
                <Record Type="UI.DataFieldForAction">
                    <PropertyValue Property="Action" String="ZFAR_CUSTOMER_LINE_ITEMS2_SRV.ZFAR_CUSTOMER_LINE_ITEMS2_SRV_Entities/Create"/>
                    <PropertyValue Property="Label" String="Action 1"/>
                </Record>
                <Record Type="UI.DataFieldForIntentBasedNavigation">
                    <PropertyValue Property="SemanticObject" String="Customer"/>
                    <PropertyValue Property="Action" String="postPayment2"/>
                    <PropertyValue Property="Label" String="SO Navigation (M)"/>
                    <Annotation Term="com.sap.vocabularies.UI.v1.Importance" EnumMember="com.sap.vocabularies.UI.v1.ImportanceType/Medium"/>
                </Record>
            </Collection>
        </PropertyValue>
    </Record>
</Annotation>
```

LANGUAGE: JSON

CODE:
```json
"quickVariantSelectionX": {
    "variants": {
       "SalesOrderTable": {
            "key": "SalesOrderTable",
            "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant#VAR1"
            },
        "Amount_CustomerChart": {
            "key": "Amount_CustomerChart",
            "annotationPath": "com.sap.vocabularies.UI.v1.SelectionPresentationVariant#VAR4",
            "showItemNavigationOnChart": true
             }
    }
}
```

NOTE: When showItemNavigationOnChart is true, the Show details button appears in the chart popup after selecting a bar and Details. Maintain an internal navigation target in the manifest (see internal navigation configuration). Service/entity for the chart must not be draft-enabled or read-only.

STEP: 7 — Additional examples: SelectionVariant / SelectionPresentationVariant without qualifier and LineItem variations

DESCRIPTION: Examples for unqualified (no qualifier) SelectionVariant and SelectionPresentationVariant usage and using different LineItem qualifiers for tabs.

LANGUAGE: XML

CODE:
```xml
<!-- SelectionVariant without a Qualifier -->
<Annotation Term="UI.SelectionVariant">
     <Record>
          <PropertyValue Property="Text" String="Expensive">
          </PropertyValue>
          <PropertyValue Property="SelectOptions">
               <Collection>
                    <Record Type="UI.SelectOptionType">
                         <PropertyValue Property="PropertyName"
                                        PropertyPath="GrossAmount" />
                         <PropertyValue Property="Ranges">
                              <Collection>
                                   <Record Type="UI.SelectionRangeType">
                                        <PropertyValue Property="Option"
                                                       EnumMember="UI.SelectionRangeOptionType/GE" />
                                        <PropertyValue Property="Low" String="5000" />
                                   </Record>
                              </Collection>
                         </PropertyValue>
                    </Record>
               </Collection>
          </PropertyValue>
     </Record>
</Annotation>
```

LANGUAGE: JSON

CODE:
```json
"settings": {
     "quickVariantSelectionX": {
          "variants": {
               "ExpensiveOrdersTable": {
                    "key": "ExpensiveOrdersTable",
                    "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant"
               }
          }
     }
},
```

LANGUAGE: XML

CODE:
```xml
<!-- SelectionPresentationVariant without Qualifier referencing LineItem#Reduced  -->
<Annotation Term="UI.SelectionPresentationVariant">
     <Record>
          <PropertyValue Property="Text" String="Cheap">
          </PropertyValue>
          <PropertyValue Property="SelectionVariant">
               <Record>
                    <PropertyValue Property="Text" String="Cheap">
                    </PropertyValue>
                    <PropertyValue Property="SelectOptions">
                         <Collection>
                              <Record Type="UI.SelectOptionType">
                                   <PropertyValue Property="PropertyName"
                                                  PropertyPath="GrossAmount" />
                                   <PropertyValue Property="Ranges">
                                        <Collection>
                                             <Record Type="UI.SelectionRangeType">
                                                  <PropertyValue Property="Option"
                                                                 EnumMember="UI.SelectionRangeOptionType/LT" />
                                                  <PropertyValue Property="Low" String="5000" />
                                             </Record>
                                        </Collection>
                                   </PropertyValue>
                              </Record>
                         </Collection>
                    </PropertyValue>
               </Record>
          </PropertyValue>
          <PropertyValue Property="PresentationVariant">
               <Record>
                    <PropertyValue Property="Visualizations">
                         <Collection>
                              <AnnotationPath>@UI.LineItem#Reduced</AnnotationPath>
                         </Collection>
                    </PropertyValue>
                    <PropertyValue Property="SortOrder">
                         <Collection>
                              <Record>
                                   <PropertyValue Property="Property"
                                                  PropertyPath="GrossAmount" />
                                   <PropertyValue Property="Descending" Bool="false" />
                              </Record>
                         </Collection>
                    </PropertyValue>
               </Record>
          </PropertyValue>
     </Record>
</Annotation>
```

LANGUAGE: JSON

CODE:
```json
"quickVariantSelectionX": {
     "variants": {
          "ExpensiveOrdersTable": {
               "key": "ExpensiveOrdersTable",
               "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant"
          },
          "CheapOrdersTable": {
               "key": "CheapOrdersTable",
               "annotationPath": "com.sap.vocabularies.UI.v1.SelectionPresentationVariant"
          }
     }
}
```

LANGUAGE: XML

CODE:
```xml
<!-- Example: LineItem with qualifier "Simplified" and a SelectionPresentationVariant using it -->
<Annotation Term="UI.LineItem" Qualifier="Simplified">
     <Collection>
          <Record Type="UI.DataField">
               <PropertyValue Property="Value" Path="ID" />
          </Record>
          <Record Type="UI.DataField">
               <PropertyValue Property="Value" Path="ImageUrl" />
          </Record>
          <Record Type="UI.DataFieldForAnnotation">
               <PropertyValue Property="Target" AnnotationPath="@UI.FieldGroup#multipleActionFields" />
               <PropertyValue Property="Label" String="Sold-To Party" />
          </Record>
     </Collection>
</Annotation>

<Annotation Term="UI.SelectionPresentationVariant" Qualifier="PVandSV">
     <Record Type="UI.SelectionPresentationVariantType">
          <PropertyValue Property="Text" String="Medium Rating/PVandSV">
          </PropertyValue>
          <PropertyValue Property="SelectionVariant">
               <Record Type="UI.SelectionVariantType">
                    <PropertyValue Property="SelectOptions">
                         <Collection>
                              <Record Type="UI.SelectOptionType">
                                   <PropertyValue Property="PropertyName" PropertyPath="Rating" />
                                   <PropertyValue Property="Ranges">
                                        <Collection>
                                             <Record Type="UI.SelectionRangeType">
                                                  <PropertyValue Property="Option" EnumMember="UI.SelectionRangeOptionType/BT" />
                                                  <PropertyValue Property="Low" String="2" />
                                                  <PropertyValue Property="High" String="4" />
                                             </Record>
                                        </Collection>
                                   </PropertyValue>
                              </Record>
                         </Collection>
                    </PropertyValue>
                    <PropertyValue Property="Text" String="Medium Rating" />
               </Record>
          </PropertyValue>
          <PropertyValue Property="PresentationVariant">
               <Record Type="UI.PresentationVariantType">>
                    <PropertyValue Property="MaxItems" Int="2" />
                    <PropertyValue Property="SortOrder">
                         <Collection>
                              <Record Type="Common.SortOrderType">
                                   <PropertyValue Property="Property" PropertyPath="ID" />
                                   <PropertyValue Property="Ascending" Bool="false" />
                              </Record>
                              <Record Type="Common.SortOrderType">
                                   <PropertyValue Property="Property" PropertyPath="SalesOrderType" />
                                   <PropertyValue Property="Descending" Bool="true" />
                              </Record>
                         </Collection>
                    </PropertyValue>
                    <PropertyValue Property="Visualizations">
                         <Collection>
                              <AnnotationPath>@UI.LineItem#Simplified</AnnotationPath>
                         </Collection>
                    </PropertyValue>
               </Record>
          </PropertyValue>
     </Record>
</Annotation>
```

STEP: 8 — Important notes and behavior (stable IDs, personalization, supported features)

DESCRIPTION: Quick checklist to apply while implementing:

- Stable IDs: Per-tab tables get suffix "-<key>" where <key> is the manifest variant key. Use alphanumeric + underscore keys that do not begin with a digit.
- keepPreviousPersonalization: Can keep a previous single-table personalization on one tab. Add this at the view definition level in OData V4 views.paths.
- Supported SelectionRangeOptionTypes: EQ, BT, LE, GE, NE, GT, LT (no wildcards).
- PresentationVariant must include a Visualization to be applied; otherwise the default LineItem is used.
- For charts: actions from UI.Chart and custom extension actions supported; custom actions tied to selection will be disabled unless a chart bar is selected.
- Control configuration: Customize each tab/table using controlConfiguration entries keyed by annotation visualization (see examples).
- When mixing entity sets: Each tab can display different entity sets/table settings; configure entitySet or table settings in manifest per view (see referenced topic on different entity sets).


**TITLE**: Defining Multiple Views on a List Report Table (Single Table Mode)

**INTRODUCTION**: Instructions and code examples to define multiple table views (selection variants) and enable switching between them with a segmented button in single table mode for SAP Fiori Elements (OData V2 and V4). Include annotations (XML/ABAP/CDS/CAP) and manifest.json settings for quickVariantSelection.

**TAGS**: fiori-elements-framework, odata-v2, odata-v4, annotations, SelectionVariant, SelectionPresentationVariant, quickVariantSelection, manifest.json, segmented-button

**STEP**: 1 — Add SelectionVariant annotations (OData V2)

**DESCRIPTION**: Create SelectionVariant annotations in your annotations file to define preconfigured filters (views). Example shows a SelectionVariant qualifier "Expensive" filtering GrossAmount >= 5000.

**LANGUAGE**: XML

**CODE**:
```xml
<Annotation Term="UI.SelectionVariant" Qualifier="Expensive">
    <Record>
        <PropertyValue Property="Text" String="Expensive">
        </PropertyValue>
        <PropertyValue Property="SelectOptions">
            <Collection>
                <Record Type="UI.SelectOptionType">
                    <PropertyValue Property="PropertyName"
                        PropertyPath="GrossAmount" />
                    <PropertyValue Property="Ranges">
                        <Collection>
                            <Record Type="UI.SelectionRangeType">
                                <PropertyValue Property="Option"
                                    EnumMember="UI.SelectionRangeOptionType/GE" />
                                <PropertyValue Property="Low" String="5000" />
                            </Record>
                        </Collection>
                    </PropertyValue>
                </Record>
            </Collection>
        </PropertyValue>
    </Record>
</Annotation>
```

**LANGUAGE**: ABAP CDS

**CODE**:
```
@UI.SelectionVariant: [
  {
    text: 'Expensive',
    qualifier: 'Expensive'
  }
]
annotate view STTA_C_MP_Product with {

}
```

**DESCRIPTION (Notes)**:
- The SelectionVariant's FilterExpression is not supported.
- Supported SelectionRangeOptionTypes (no wildcards): EQ, BT, LE, GE, NE, GT, LT.
- For PresentationVariant, SortOrders are supported.

---

**STEP**: 2 — Enable multiple views in manifest.json (OData V2, sap.ui.generic.app quickVariantSelection)

**DESCRIPTION**: In manifest.json under sap.ui.generic.app -> pages -> component -> settings, enable quickVariantSelection and point each variant entry to an annotationPath. Each variant must include a mandatory "key" used to initialize the SegmentedButton item.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "sap.ui.generic.app": {
    "pages": [
      {
        "entitySet": "C_STTA_SalesOrder_WD_20",
        "component": {
          "name": "sap.suite.ui.generic.template.ListReport",
          "list": true,
          "settings": {
            "quickVariantSelection": {
              "variants": {
                "0": {
                  "key": "_tab1",
                  "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant#Expensive"
                },
                "1": {
                  "key": "_tab2",
                  "annotationPath": "com.sap.vocabularies.UI.v1.SelectionPresentationVariant#Cheap"
                }
              }
            }
            ...
          }
        }
      }
    ]
  }
}
```

**DESCRIPTION (Note)**: The PresentationVariant part of a SelectionPresentationVariant is not considered for filtering — SelectionPresentationVariant is used only to find the SelectionVariant and its filters.

---

**STEP**: 3 — SelectionVariant / SelectionPresentationVariant examples (OData V2)

**DESCRIPTION**: Additional annotation examples (qualified/unqualified) and manifest.json settings demonstrating quickVariantSelection options including showCounts and hideTableTitle.

**LANGUAGE**: XML

**CODE**:
```xml
<Annotation Term="UI.SelectionVariant" Qualifier="Expensive">
     <Record>
          <PropertyValue Property="Text" String="{@i18n>@Expensive}">
          </PropertyValue>
          <PropertyValue Property="SelectOptions">
               <Collection>
                    <Record Type="UI.SelectOptionType">
                         <PropertyValue Property="PropertyName" PropertyPath="GrossAmount" />
                         <PropertyValue Property="Ranges">
                              <Collection>
                                   <Record Type="UI.SelectionRangeType">
                                        <PropertyValue Property="Sign" EnumMember="UI.SelectionRangeSignType/E"/>
                                        <PropertyValue Property="Option" EnumMember="UI.SelectionRangeOptionType/LT" />
                                        <PropertyValue Property="Low" String="5000" />
                                   </Record>
                              </Collection>
                         </PropertyValue>
                    </Record>
               </Collection>
          </PropertyValue>
     </Record>
</Annotation>
```

**LANGUAGE**: JSON

**CODE**:
```json
"settings": {
          "smartVariantManagement": true,
          "quickVariantSelection": {
               "showCounts": true,
               "variants": {
                    "0": {
                         "key": "_tab1",
                         "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant#Expensive"
                    },
                    "1": {
                         "key": "_tab2",
                         "annotationPath": "com.sap.vocabularies.UI.v1.SelectionPresentationVariant#Cheap"
                    }
               }
          }
     }
```

**LANGUAGE**: XML

**CODE**:
```
<Annotation Term="UI.SelectionVariant" >
     <Record>
          <PropertyValue Property="Text" String="{@i18n>@Expensive}">
          </PropertyValue>
          <PropertyValue Property="SelectOptions">
               <Collection>
                     <Record Type="UI.SelectOptionType">
                          <PropertyValue Property="PropertyName" PropertyPath="GrossAmount" />
                          <PropertyValue Property="Ranges">
                               <Collection>
                                    <Record Type="UI.SelectionRangeType">
                                         <PropertyValue Property="Sign" EnumMember="UI.SelectionRangeSignType/E"/>
                                         <PropertyValue Property="Option" EnumMember="UI.SelectionRangeOptionType/LT" />
                                         <PropertyValue Property="Low" String="5000" />
                                    </Record>
                               </Collection>
                          </PropertyValue>
                     </Record>
                </Collection>
           </PropertyValue>
      </Record>
</Annotation>
```

**LANGUAGE**: JSON

**CODE**:
```json
"settings": {
     "smartVariantManagement": true,
     "quickVariantSelection": {
          "showCounts": true,
          "variants": {
               "0": {
               "key": "_tab1",
               "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant"
               },
               "1": {
                    "key": "_tab2",
                    "annotationPath": "com.sap.vocabularies.UI.v1.SelectionPresentationVariant#Cheap"
               }
          }
     }
}
```

**LANGUAGE**: XML

**CODE**:
```xml
<Annotation Term="UI.SelectionPresentationVariant"Qualifier="Cheap">
     <Record>
          <PropertyValue Property="Text" String="{@i18n>@Cheap}">
          </PropertyValue>
          <PropertyValue Property="SelectionVariant">
               <Record>
                    <PropertyValue Property="Text" String="Cheap">
                    </PropertyValue>
                    <PropertyValue Property="SelectOptions">
                         <Collection>
                              <Record Type="UI.SelectOptionType">
                                   <PropertyValue Property="PropertyName"
                                                  PropertyPath="GrossAmount" />
                                   <PropertyValue Property="Ranges">
                                        <Collection>
                                             <Record Type="UI.SelectionRangeType">
                                                  <PropertyValue Property="Option"
                                                                 EnumMember="UI.SelectionRangeOptionType/LT" />
                                                  <PropertyValue Property="Low" String="5000" />
                                             </Record>
                                        </Collection>
                                   </PropertyValue>
                              </Record>
                         </Collection>
                    </PropertyValue>
               </Record>
          </PropertyValue>
          <PropertyValue Property="PresentationVariant">
               <Record>
                    <PropertyValue Property="Visualizations">
                         <Collection>
                              <AnnotationPath>@UI.LineItem#Reduced</AnnotationPath>
                         </Collection>
                    </PropertyValue>
                    <PropertyValue Property="SortOrder">
                         <Collection>
                              <Record>
                                   <PropertyValue Property="Property"
                                                  PropertyPath="GrossAmount" />
                                   <PropertyValue Property="Descending" Bool="false" />
                              </Record>
                         </Collection>
                    </PropertyValue>
               </Record>
          </PropertyValue>
     </Record>
</Annotation>
```

**LANGUAGE**: JSON

**CODE**:
```json
"settings": {
     "smartVariantManagement": true,
     "quickVariantSelection": {
          "showCounts": true,
          "variants": {
               "0": {
                    "key": "_tab1",
                    "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant#Expensive"
               },
               "1": {
                    "key": "_tab2",
                    "annotationPath": "com.sap.vocabularies.UI.v1.SelectionPresentationVariant#Cheap"
               }
          }
     }
}
```

**LANGUAGE**: XML

**CODE**:
```
<Annotation Term="UI.SelectionPresentationVariant">
     <Record>
          <PropertyValue Property="Text" String="{@i18n>@Cheap}">
          </PropertyValue>
          <PropertyValue Property="SelectionVariant">
               <Record>
                    <PropertyValue Property="Text" String="Cheap">
                    </PropertyValue>
                    <PropertyValue Property="SelectOptions">
                         <Collection>
                              <Record Type="UI.SelectOptionType">
                                   <PropertyValue Property="PropertyName"
                                                  PropertyPath="GrossAmount" />
                                   <PropertyValue Property="Ranges">
                                        <Collection>
                                             <Record Type="UI.SelectionRangeType">
                                                  <PropertyValue Property="Option"
                                                                 EnumMember="UI.SelectionRangeOptionType/LT" />
                                                  <PropertyValue Property="Low" String="5000" />
                                             </Record>
                                        </Collection>
                                   </PropertyValue>
                              </Record>
                         </Collection>
                    </PropertyValue>
               </Record>
          </PropertyValue>
          <PropertyValue Property="PresentationVariant">
               <Record>
                    <PropertyValue Property="Visualizations">
                         <Collection>
                              <AnnotationPath>@UI.LineItem#Reduced</AnnotationPath>
                         </Collection>
                    </PropertyValue>
                    <PropertyValue Property="SortOrder">
                         <Collection>
                              <Record>
                                   <PropertyValue Property="Property"
                                                  PropertyPath="GrossAmount" />
                                   <PropertyValue Property="Descending" Bool="false" />
                              </Record>
                         </Collection>
                    </PropertyValue>
               </Record>
          </PropertyValue>
     </Record>
</Annotation>
```

**LANGUAGE**: JSON

**CODE**:
```json
"settings": {
     "smartVariantManagement": true,
     "quickVariantSelection": {
          "showCounts": true,
          "variants": {
               "0": {
                    "key": "_tab1",
                    "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant"
                    },
               "1": {
                    "key": "_tab2",
                    "annotationPath": "com.sap.vocabularies.UI.v1.SelectionPresentationVariant"
                    }
          }
     }
}
```

---

**STEP**: 4 — Add SelectionVariant annotations (OData V4)

**DESCRIPTION**: For OData V4, add SelectionVariant annotations in the annotations file. Examples include XML Annotations, ABAP CDS, and CAP CDS variants.

**LANGUAGE**: XML

**CODE**:
```xml
<Annotations Target="com.c_salesordermanage_sd.SalesOrderManage">
     <Annotation Term="UI.SelectionVariant" Qualifier="Completed">
          <Record Type="UI.SelectionVariantType">
               <PropertyValue Property="SelectOptions">
                    <Collection>
                         <Record Type="UI.SelectOptionType">
                              <PropertyValue Property="PropertyName" PropertyPath="OverallSDProcessStatus" />
                              <PropertyValue Property="Ranges">
                                   <Collection>
                                        <Record Type="UI.SelectionRangeType">
                                             <PropertyValue Property="Option" EnumMember="UI.SelectionRangeOptionType/BT" />
                                             <PropertyValue Property="Low" String="A" />
                                             <PropertyValue Property="High" String="D" />
                                        </Record>
                                        <Record Type="UI.SelectionRangeType">
                                             <PropertyValue Property="Option" EnumMember="UI.SelectionRangeOptionType/BT" />
                                             <PropertyValue Property="Low" String="B" />
                                             <PropertyValue Property="High" String="C" />
                                        </Record>
                                   </Collection>
                              </PropertyValue>
                         </Record>
                    </Collection>
               </PropertyValue>
               <PropertyValue Property="Text" String="completed (2 Ranges)" />
          </Record>
     </Annotation>
     <Annotation Term="UI.SelectionVariant" Qualifier="InProcess">
          <Record Type="UI.SelectionVariantType">
               <PropertyValue Property="SelectOptions">
                    <Collection>
                         <Record Type="UI.SelectOptionType">
                              <PropertyValue Property="PropertyName" PropertyPath="OverallSDProcessStatus" />
                              <PropertyValue Property="Ranges">
                                   <Collection>
                                        <Record Type="UI.SelectionRangeType">
                                             <PropertyValue Property="Option" EnumMember="UI.SelectionRangeOptionType/EQ" />
                                             <PropertyValue Property="Low" String="B" />
                                        </Record>
                                   </Collection>
                              </PropertyValue>
                         </Record>
                    </Collection>
               </PropertyValue>
               <PropertyValue Property="Text" String="In Process" />
          </Record>
     </Annotation>
</Annotations>
```

**LANGUAGE**: ABAP CDS

**CODE**:
```
@UI.SelectionVariant: [
  {
    text: 'completed (2 Ranges)',
    qualifier: 'Completed'
  },
  {
    text: 'In Process',
    qualifier: 'InProcess'
  }
]
annotate view SALESORDERMANAGE with {

}
```

**LANGUAGE**: CAP CDS

**CODE**:
```
annotate com.c_salesordermanage_sd.SalesOrderManage with @(
  UI.SelectionVariant #Completed : {
    $Type : 'UI.SelectionVariantType',
    SelectOptions : [
        {
            $Type : 'UI.SelectOptionType',
            PropertyName : OverallSDProcessStatus,
            Ranges : [
                {
                    $Type : 'UI.SelectionRangeType',
                    Option : #BT,
                    Low : 'A',
                    High : 'D'
                },
                {
                    $Type : 'UI.SelectionRangeType',
                    Option : #BT,
                    Low : 'B',
                    High : 'C'
                }
            ]
        }
    ],
    Text : 'completed (2 Ranges)'
  },
  UI.SelectionVariant #InProcess : {
    $Type : 'UI.SelectionVariantType',
    SelectOptions : [
        {
            $Type : 'UI.SelectOptionType',
            PropertyName : OverallSDProcessStatus,
            Ranges : [
                {
                    $Type : 'UI.SelectionRangeType',
                    Option : #EQ,
                    Low : 'B'
                }
            ]
        }
    ],
    Text : 'In Process'
  },
);
```

**DESCRIPTION (Notes)**:
- The SelectionVariant FilterExpression is not supported.
- Supported SelectionRangeOptionTypes (no wildcards): EQ, BT, LE, GE, NE, GT, LT.
- For PresentationVariant, SortOrders are supported.

---

**STEP**: 5 — Enable multiple views in manifest.json (OData V4, controlConfiguration quickVariantSelection)

**DESCRIPTION**: In V4 manifest.json routing targets (or component options), configure controlConfiguration for the LineItem table with quickVariantSelection.paths array. Each path entry uses annotationPath pointing to SelectionVariant/SelectionPresentationVariant qualifiers. Optional keys: showCounts (adds $count requests), hideTableTitle (show only segmented buttons).

**LANGUAGE**: JSON

**CODE**:
```json
"SalesOrderManageList": {
  "type": "Component",
  "id": "SalesOrderManageList",
  "name": "sap.fe.templates.ListReport",
  "options": {
    "settings": {
      "contextPath": "/SalesOrderManage",
      "controlConfiguration": {
        "@com.sap.vocabularies.UI.v1.LineItem": {
          "tableSettings": {
            "type": "ResponsiveTable",
            "quickVariantSelection": {
              "paths": [
                {
                  "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant#Open"
                },
                {
                  "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant#Completed"
                },
                {
                  "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant#NotRelevant"
                },
                {
                  "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant#InProcess"
                }
              ],
              "hideTableTitle": true,
              "showCounts": true
            }
          }
        }
      },
      ...
    }
  }
}
```

**DESCRIPTION (Notes)**:
- paths: entries pointing to annotationPath of SelectionVariant/SelectionPresentationVariant.
- showCounts: when true, segmented buttons show counts and no count is shown next to the table title; when false, count is not shown next to buttons and is shown next to the table title.
- showCounts=true triggers additional $count requests (performance impact).
- hideTableTitle=true hides the title and shows only segmented buttons — enable only if variant titles are explicit.

---

**STEP**: 6 — Required fields and behavior summary

**DESCRIPTION**: Quick actionable checklist to implement multiple views in single table mode.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "checklist": [
    "Add one or more UI.SelectionVariant or UI.SelectionPresentationVariant annotations (XML/ABAP/CDS/CAP).",
    "For V2: reference variants in manifest.json under sap.ui.generic.app.pages[].component.settings.quickVariantSelection. Each variant must have a 'key' and 'annotationPath'.",
    "For V4: reference variants in manifest.json under options.settings.controlConfiguration['@com.sap.vocabularies.UI.v1.LineItem'].tableSettings.quickVariantSelection.paths[].annotationPath.",
    "Optionally set 'showCounts': true to display counts (beware of $count requests).",
    "Optionally set 'hideTableTitle': true to hide the table title and display only segmented buttons.",
    "Supported SelectionRangeOptionTypes: EQ, BT, LE, GE, NE, GT, LT. FilterExpression is not supported."
  ]
}
```

fiori-elements-framework odata-v2 odata-v4 annotations SelectionVariant SelectionPresentationVariant quickVariantSelection manifest.json segmented-button


**TITLE**: Configuring Multiple List-Report Views with Different Entity Sets and Table Settings

**INTRODUCTION**: Configure a Fiori Elements List Report to display multiple views (tabs) that use different entity sets and per-tab table settings. Applicable for OData V2 (sap.ui.generic.app / ListReport) and OData V4 (sap.fe / ListReport). This guide shows manifest.json changes, XML/CAP annotations for SelectionVariant/SelectionPresentationVariant, and how to use controlConfiguration to set per-entity-set personalization.

**TAGS**: fiori-elements-framework, list-report, multiple-views, entity-set, manifest.json, odata-v2, odata-v4, selectionvariant, selectionpresentationvariant, controlConfiguration, quickVariantSelectionX

**STEP**: 1 — Prerequisites & high-level behavior

**DESCRIPTION**: Ensure you already implemented "Multiple Table Mode" for a List Report. Key behaviors to account for when using multiple entity sets:
- The leading entitySet (under sap.ui.generic.app/pages or sap.fe/targets/contextPath) defines the smart filter bar and footer.
- Filters in the filter bar come from the main (leading) entity set; you cannot add filters that belong only to an additional entity set.
- Filters are applied to each table only if the corresponding property exists on that table's entity type; otherwise ignored.
- Counts for each tab are always shown in the icon tab bar and reflect filters when those filters are relevant for the entity set.
- Do not mix draft and non-draft entity sets; do not mix responsive and non-responsive table types in the same app. Ensure charts/services are not draft-enabled when required.

**LANGUAGE**: PlainText

**CODE**:
```PlainText
Prerequisite: Completed "Defining Multiple Views on a List Report Table - Multiple Table Mode".
System behavior summary:
- Leading entitySet controls the smart filter bar.
- Additional tabs can set entitySet per variant/annotation.
- Filters applied only if property exists on entitySet.
- Counts shown in icon tab bar; reflect only relevant filters.
- Avoid mixing draft/non-draft; avoid mixing responsive/non-responsive tables.
```

**STEP**: 2 — OData V2: Add entitySet and tableSettings per variant in manifest.json (quickVariantSelectionX)

**DESCRIPTION**: For sap.ui.generic.app (classic List Report), specify the leading entitySet under pages[].entitySet. To add additional views (tabs) that use different entity sets and table types, add an entitySet and an annotationPath per variant inside quickVariantSelectionX. Use tableSettings per variant to set table type (GridTable, TreeTable, AnalyticalTable, ResponsiveTable as applicable). If entitySet is omitted inside a variant, the leading entitySet is used.

**LANGUAGE**: JSON

**CODE**:
```json
"sap.ui.generic.app": {
         "pages": [{
             "entitySet": "C_RequirementTrackingPurReq",
             "component": {
                 "name": "sap.suite.ui.generic.template.ListReport",
                 "list": true,
                 "settings": {
                     "condensedTableLayout": true,
                     "smartVariantManagement": false,
                     "quickVariantSelectionX": {
                        "variants": {
                            "1": {
                                "key": "1",
                                "entitySet": "C_RequirementTrackingPurReq",
                                "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant#VAR1",
                                "tableSettings": {
                                      "type": "GridTable",
                        }
                            },
                            "2": {
                                "key": "2",
                                "entitySet": "C_RequirementTrackingPurOrd",
                                "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant#VAR5",
                                "tableSettings": {
                                      "type": "GridTable",
                        }
                            },
                            "3": {
                                "key": "3",
                                "entitySet": "C_RequirementTrackingPurReq",
                                "annotationPath": "com.sap.vocabularies.UI.v1.SelectionPresentationVariant#VAR6",
                                "showItemNavigationOnChart": true,
                                       "tableSettings": {
                                            "type": "TreeTable",
                                }
                            }
                        }
                    }
                }
            }
        }]
	}
```

**STEP**: 3 — OData V2: Table type and UX constraints

**DESCRIPTION**: Rules to enforce when specifying table types per variant:
- Do not mix responsive and non-responsive table types within the same list report. Either all tables are responsive or you have only non-responsive types (GridTable, TreeTable, AnalyticalTable) mixed.
- Different tabs can render different (non-responsive) table types (e.g., tab1 = TreeTable, tab2 = GridTable).
- Table settings not specified per variant will fall back to the overall table settings defined at the list level.

**LANGUAGE**: PlainText

**CODE**:
```PlainText
Guidelines:
- If tableSettings not provided for a variant, overall list table settings apply.
- Do not combine responsive and non-responsive tables in the same app.
- Validate performance and usability when adding entity sets and table types.
```

**STEP**: 4 — System behavior for filters and counts (detailed)

**DESCRIPTION**: How the runtime applies filters and updates counts across tabs:
- The filter bar uses properties from the main entity set only.
- When a filter is applied that matches a property in some but not all entity sets, only the tabs whose entity sets contain that property will update their counts and results.
- If a user navigates to a tab where active filters are not relevant, the application shows an informational message listing the filters that were ignored for that entity set.

**LANGUAGE**: PlainText

**CODE**:
```PlainText
Behavior:
- Filters applied globally but evaluated per-tab: applied only if property exists.
- Counts in icon tab bar reflect only relevant filters per entity set.
- UI informs users when active filters are not relevant to the selected tab.
```

**STEP**: 5 — OData V4: Define SelectionVariant (SV) and SelectionPresentationVariant (SPV) annotations (XML)

**DESCRIPTION**: For OData V4 (sap.fe), define XML annotations for the entity sets you want to render on each tab. Use UI.SelectionVariant on the target entity or UI.SelectionPresentationVariant to combine selection and presentation (sorting, MaxItems). Qualify the annotation to reference it in manifest views/paths.

**LANGUAGE**: XML

**CODE**:
```xml
<Annotations Target="myService.entityB">
   <Annotation Term="UI.SelectionVariant" Qualifier="Good">
   <Record Type="UI.SelectionVariantType">
      <PropertyValue Property="SelectOptions">
         <Collection>
            <Record Type="UI.SelectOptionType">
               <PropertyValue Property="PropertyName" PropertyPath="propertyInteger" />
               <PropertyValue Property="Ranges">
                  <Collection>
                     <Record Type="UI.SelectionRangeType">
                        <PropertyValue Property="Option" EnumMember="UI.SelectionRangeOptionType/EQ" />
                        <PropertyValue Property="Low" String="1" />
                     </Record>
                  </Collection>
               </PropertyValue>
            </Record>
         </Collection>
      </PropertyValue>
      <PropertyValue Property="Text" String="entityA with one follower" />
   </Record>
  </Annotation>
</Annotations>

<Annotations Target="myService.entityA">
<Annotation Term="UI.SelectionPresentationVariant" Qualifier="trueSPV">
      <Record Type="UI.SelectionPresentationVariantType"
           <PropertyValue Property="Text" String="entityB with true value"></PropertyValue>
           <PropertyValue Property="SelectionVariant">
              <Record Type="UI.SelectionVariantType">
                 <PropertyValue Property="SelectOptions">
                    <Collection>
                       <Record Type="UI.SelectOptionType">
                          <PropertyValue Property="PropertyName" PropertyPath="propertyBoolean" />
                          <PropertyValue Property="Ranges">
                             <Collection>
                                <Record Type="UI.SelectionRangeType">
                                   <PropertyValue Property="Option" EnumMember="UI.SelectionRangeOptionType/EQ" />
                                   <PropertyValue Property="Low" String="true" />                                </Record>
                             </Collection>
                          </PropertyValue>
                       </Record>
                    </Collection>
                 </PropertyValue>
                 <PropertyValue Property="Text" String="Medium Rating" />
              </Record>
            </PropertyValue>
            <PropertyValue Property="PresentationVariant">
                  <Record Type="UI.PresentationVariantType">>
                      <PropertyValue Property="MaxItems" Int="3" />
                      <PropertyValue Property="SortOrder">
                           <Collection>
                              <Record Type="Common.SortOrderType">
                                  <PropertyValue Property="Property" PropertyPath="propertyInteger" />
                              </Record>
                          </Collection>
                      </PropertyValue>
                   </Record>
              </PropertyValue>
          </Record>
      </Annotation>
```

**STEP**: 6 — OData V4: Define SelectionVariant/SPV using CAP CDS (alternative)

**DESCRIPTION**: If you use CAP CDS annotations, annotate entities with UI.SelectionVariant and UI.SelectionPresentationVariant qualifiers and SelectOptions/Ranges. Use these qualifiers in manifest views.

**LANGUAGE**: CDS

**CODE**:
```cds
annotate entityB with @(
UI.SelectionVariant#One :
{
    Text: 'entityA with one follower',
    SelectOptions:
    [
        {
            $Type : 'UI.SelectOptionType',
            PropertyName : propertyInteger,
             Ranges:
             [
                 {
                     $Type: 'UI.SelectionRangeType',
                     Option: #EQ,
                     Low: '1'
                }
             ]
        }
    ]
}

...
annotate entityA with @(

UI.SelectionPresentationVariant#trueSPV :
{
    Text: 'entityB with true value',
    SelectionVariant: {
          SelectOptions:
          [
              {
                  $Type : 'UI.SelectOptionType',
                  PropertyName : propertyBoolean,
                   Ranges:
                   [
                       {
                           $Type: 'UI.SelectionRangeType',
                           Option: #EQ,
                           Low: 'true'
                      }
                   ]
              }
          ]
      },
    PresentationVariant: {
            MaxItems       : 3,
            SortOrder      : [{Property : 'ID'}]
    }
},
```

**STEP**: 7 — OData V4: Manifest configuration for multiple views (sap.fe targets)

**DESCRIPTION**: Configure the List Report target to include multiple views. Set contextPath to the leading entity and supply views.paths entries for each tab. For tabs that use a different entity set, add "entitySet" alongside "annotationPath".

**LANGUAGE**: JSON

**CODE**:
```json
"targets": {
    "DraftList": {
        "type": "Component",
            "id": "DraftList",
            "name": "sap.fe.templates.ListReport",
            "options": {
                "settings": {
                    "contextPath": "/entityA",
                    "views": {
                        "paths": [
                            {
                                "key": "tab1",
                                "annotationPath": "com.sap.vocabularies.UI.v1.SelectionPresentationVariant#trueSPV"
                            },
                            {
                                "key": "tab2",
                                "entitySet": "entityB",
                                "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant#One"
                            }
                        ]
                    }
                }
            }
        },
...
}
```

**STEP**: 8 — OData V4: Define per-entity-set table personalization using controlConfiguration

**DESCRIPTION**: To set different personalization or tableSettings per entity set, prefix the annotation key with the entity set name in controlConfiguration. Use the path "/EntityB/@<AnnotationKey>" to scope settings to EntityB. Place controlConfiguration under the target component settings.

**LANGUAGE**: JSON

**CODE**:
```json
"targets": {
    "DraftList": {
        "type": "Component",
        "id": "DraftList",
        "name": "sap.fe.templates.ListReport",
        "options": {
            "settings": {
                "contextPath": "/EntityA",
                "views": {
                    "paths": [
                        {
                            "key": "tab1",
                            "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant"
                        },
                        {
                            "key": "tab2",
                            "entitySet": "EntityB",
                            "annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant"
                        }
                    ]
                },
                "controlConfiguration": {
                    "@com.sap.vocabularies.UI.v1.LineItem": {
                        "tableSettings": {
                            "personalization": false
                        }
                    },
                    "/EntityB/@com.sap.vocabularies.UI.v1.LineItem": {
                        "tableSettings": {
                            "personalization": {
                                "column": true,
                                "sort": false,
                                "filter": true,
                                "group": false
                            }
                        }
                    }
                }
            }
        }
    },
    ...
}
```

**STEP**: 9 — Checklist before deployment

**DESCRIPTION**: Verify these before releasing:
- Leading entitySet configured correctly (smart filter bar fields exist).
- Each variant or view has correct annotationPath and entitySet (if different).
- Table types per-variant comply with responsive/non-responsive constraints.
- Do not mix draft/non-draft entity sets.
- Chart services/entities are read-only or non-draft as required.
- Test filter behavior: apply filters that are not present in secondary entity sets and confirm informational messages and counts.

**LANGUAGE**: PlainText

**CODE**:
```PlainText
Pre-deployment checklist:
- Leading entitySet defined.
- Each variant/view: annotationPath + optional entitySet set.
- Table types validated (no responsive/non-responsive mix).
- No draft/non-draft mixing.
- Chart services non-draft or read-only.
- Filter/Count behavior verified per tab.
```

fiori-elements-framework list-report multiple-views entity-set manifest.json odata-v2 odata-v4 selectionvariant selectionpresentationvariant controlConfiguration quickVariantSelectionX


**TITLE**: Defining the Loading Behavior of Object Page (OData V4)

**INTRODUCTION**:
Instructions for controlling request grouping and understanding lazy loading for SAP Fiori elements Object Page (OData V4). Use these steps to configure header DataPoint/MicroChart request grouping via manifest.json, follow best practices for performance, and understand how the framework performs lazy loading of sections and header content.

**TAGS**: fiori-elements-framework, object-page, odata-v4, request-groups, lazy-loading, manifest.json, DataPoint, MicroChart

**STEP**: 1 — Request groups available (names and purposes)

**DESCRIPTION**:
Use these request group names in manifest.controlConfiguration entries to bundle requests into batch groups. Set the requestGroupId for header DataPoints and MicroCharts using the annotation path as the key in manifest.json.

Request group names and intended use:
- Heroes
  - Requests for fields coming directly from the main entity set
  - All 1:1 (multiplicity) fields from header forms and visible section forms
- Workers
  - All table requests
- Decoration
  - All 1-n multiplicity micro charts in the header
- LongRunners
  - Slow KPIs (complex analytical service responses). Not used by Fiori elements by default, but available to send as a separate batch group so UI performance from standard groups is not impacted.

Recommendation:
- Place LongRunners KPIs at the far-right of the header so faster groups (Heroes/Workers/Decoration) deliver visible information first.

**LANGUAGE**: text

**CODE**:
```text
Use one of the requestGroupId values: "Heroes", "Workers", "Decoration", "LongRunners"
Set in manifest.json under the ObjectPage component options.settings.controlConfiguration
Key: annotation path of the header element (DataPoint or MicroChart)
Value: { "requestGroupId": "<GroupName>" }
```

**STEP**: 2 — Configure request grouping in manifest.json (example)

**DESCRIPTION**:
Add controlConfiguration entries for header DataPoints/MicroCharts in the object page component configuration. Use the annotation path (e.g. "@com.sap.vocabularies.UI.v1.DataPoint#NetValue" or "<NavigationProperty>/<AnnotationPath>") as the object key, and set "requestGroupId" to one of the group names. Batch groups are fired in parallel by Fiori elements (with a slight delay) but the underlying model may affect exact bundling and ordering. Expect that the framework cannot fully enforce batching timing when the model is preparing requests.

Preserve example keys exactly as annotation paths when configuring.

File: manifest.json (inside the object page component entry)

**LANGUAGE**: JSON

**CODE**:
```json
"SalesOrderManageObjectPage": {
    "type": "Component",
    "id": "SalesOrderManageObjectPage",
    "name": "sap.fe.templates.ObjectPage",
    "options": {
       "settings": {
            "contextPath": "/SalesOrderManage",
            …
            "controlConfiguration": {
                …
                "@com.sap.vocabularies.UI.v1.DataPoint#NetValue": {
                    "requestGroupId": "Workers"
               },
                "_CreditLimitDetails/@com.sap.vocabularies.UI.v1.Chart#CreditLimitChart": {
                    "requestGroupId": "LongRunners"
               }
                …
```

**STEP**: 3 — Request-group behavior notes and best practices

**DESCRIPTION**:
Operational notes to apply while configuring requestGroupId:
- SAP Fiori elements fires batch groups in parallel but cannot fully control the OData model; requests may still be sent at slightly different times.
- The framework recommends bundling requests of a given requestGroupId into one batch, but a request from that group may fire before another request in the same group if the model prepares it earlier.
  - Example: A DataPoint configured with "Workers" can be fired before a table request also configured "Workers".
- Best practice: Put LongRunners KPIs to the far right of the header so the initial visible header area loads via standard, faster groups.
- Use requestGroupId only for header DataPoints and MicroCharts (set via controlConfiguration annotation path keys).

**LANGUAGE**: text

**CODE**:
```text
Notes:
- Fiori elements fires groups in parallel (small delays may occur).
- The model can change batching behavior; grouping is advisory to the model.
- Put LongRunners KPIs to the right-most header positions to avoid delaying visible header content.
```

**STEP**: 4 — Lazy loading behavior (default, cannot be disabled)

**DESCRIPTION**:
Lazy loading delays data calls for Object Page sections that are not yet visible. This is enabled by default in SAP Fiori elements for OData V4 and cannot be turned off by applications. Behavior details below describe how many batch requests are created and when.

Simple scenario (header has no micro charts AND no form section contains a table):
- Two batch requests on initial load:
  1. Header request (header fields)
  2. Section data request — includes:
     - The first three subsections on desktop
     - Only currently visible subsections on touch devices (tablet/mobile)

Complex scenario (header has micro charts OR any form section contains a table):
- Two additional parallel calls on initial load:
  - Table request(s) in a separate batch (parallel)
  - All micro charts in the header in a separate batch (parallel)
- Header and visible section requests still occur as above.

On scrolling:
- When a user scrolls and a section enters the viewport, a separate batch request is sent for that scrolled-to subsection.

Error handling and subsequent loads:
- If the backend returns messages (errors) for fields not currently visible, lazy loading is temporarily switched off and additional sections are loaded so the user can navigate directly to the field referenced in the message.
- On subsequent navigations to the object page instance (for example back to list report then opening another object), the header and visible subsection requests are combined into a single GET batch request.

**LANGUAGE**: text

**CODE**:
```text
Lazy loading:
- Enabled by default (OData V4 Object Page). Cannot be disabled.
- Simple scenario: initial batches = Header + SectionData (first 3 subsections on desktop).
- Complex scenario: additional parallel batches = TableRequests + HeaderMicroCharts.
- On scroll: separate batch per newly visible subsection.
- On backend messages for invisible fields: lazy loading switched off to load relevant sections for navigation.
- On subsequent loads: header + visible subsections may be sent in a single GET batch.
```

fiori-elements-framework object-page odata-v4 request-groups lazy-loading manifest.json DataPoint MicroChart


**TITLE**: Defining loadingBehavior for Object Page subsections (SAP Fiori elements OData V2)

**INTRODUCTION**: Configure when a subsection in an Object Page activates its binding (loads data) via the manifest. Use loadingBehavior to control waiting for header data and/or waiting until the subsection enters the viewport. Applicable only to SAP Fiori elements for OData V2.

**TAGS**: fiori-elements-framework, OData V2, object-page, manifest, loadingBehavior, subsection, waitForHeaderData, waitForViewportEnter

STEP: 1 - Identify subsection id

DESCRIPTION: Locate the subsection id under the Object Page (or subobject page) configuration in the manifest. The property path is:
pages -> ObjectPage|<ObjectPageId> -> component -> settings -> sections -> <SubsectionId>

LANGUAGE: JSON

CODE:
```json
// Example path (context): pages -> "ObjectPage|C_STTA_SalesOrder_WD_20" -> component.settings.sections -> "SalesOrderItemsID"
```

STEP: 2 - Add loadingBehavior properties

DESCRIPTION: Add the loadingBehavior object under the subsection entry. Set one or both of:
- waitForHeaderData: true/false — if true, the subsection waits until header data is loaded before activating its binding (useful when subsection table/chart needs additional filters from header).
- waitForViewportEnter: true/false — if true, the subsection waits to enter the viewport before activating its binding. If false, binding activation is independent of viewport and can load together with header data.

LANGUAGE: JSON

CODE:
```json
"loadingBehavior":{
	"waitForHeaderData":true/false,
	"waitForViewportEnter":true/false
}
```

STEP: 3 - Default behavior and property rules

DESCRIPTION:
- Default if loadingBehavior is not defined:
  - waitForHeaderData: false
  - waitForViewportEnter: true
- If you define one property and omit the other, the omitted property is considered false. Example: if you set waitForHeaderData: true and omit waitForViewportEnter, waitForViewportEnter is treated as false.

LANGUAGE: JSON

CODE:
```json
"loadingBehavior":{
	"waitForHeaderData":false,
	"waitForViewportEnter":true
}
```

STEP: 4 - Full manifest example (Object Page subsections)

DESCRIPTION: Insert loadingBehavior per subsection in the Object Page pages configuration. The following shows two subsections with different loadingBehavior settings.

LANGUAGE: JSON

CODE:
```json
"pages": {
                    "ObjectPage|C_STTA_SalesOrder_WD_20": {
                        "entitySet": "C_STTA_SalesOrder_WD_20",
                        "component": {
                            "name": "sap.suite.ui.generic.template.ObjectPage",
                            "settings": {
                                "sections": {
                                    "SalesOrderItemsID": {
                                        "navigationProperty": "to_Item",
                                        "entitySet": "C_STTA_SalesOrderItem_WD_20",
                                        "createMode": "inline",
                                        "tableSettings": {
                                            "inlineDelete": true
                                        },
                                        "loadingBehavior":{
                                            "waitForHeaderData":true,
                                            "waitForViewportEnter":false
                                        }
                                    },
                                    "ContactsID": {
                                        "loadingBehavior":{
                                            "waitForHeaderData":false,
                                            "waitForViewportEnter":false
                                        }
                                    }
                                }
```

STEP: 5 - Implementation guidance for code/extensions

DESCRIPTION: When using waitForHeaderData:true, implement any rebind or filter adjustments (for example, onBeforeRebindTableExtension) after header data is available. When waitForViewportEnter:false, subsection binding may run together with header data—ensure your handlers tolerate simultaneous loading.

LANGUAGE: Text

CODE:
```
// Implementation note (example):
// If you use waitForHeaderData: true, perform table/chart rebind logic in onBeforeRebindTableExtension
// after header data has been loaded to apply header-based filters before binding.
```

fiori-elements-framework
OData V2
object-page
manifest
loadingBehavior
subsection
waitForHeaderData
waitForViewportEnter


**TITLE**: Deploy an SAP Fiori Application (Business Application Studio & Visual Studio Code)

**INTRODUCTION**: This guide gives minimal, action-oriented steps to deploy SAP Fiori applications using SAP Fiori tools from Business Application Studio (BAS) and Visual Studio Code (VS Code). It covers prerequisites, UI-driven deployment via the Fiori tools command, and common CLI-based deployment for Cloud Foundry (MTA) targets. For full vendor documentation, see: https://help.sap.com/docs/SAP_FIORI_tools/17d50220bcd848aa854c9c182d65b699/1b7a3be8d99c45aead90528ef472af37.html

**TAGS**: fiori-elements-framework, sap-fiori-tools, deployment, business-application-studio, visual-studio-code, cloud-foundry, mbt

STEP: 1 — Prerequisites and project preparation

DESCRIPTION: Ensure your environment and project are ready for deployment. Install required extensions/tools, build the app, and prepare any required artifacts (MTA archive) before running the deploy flow.

LANGUAGE: Bash / Checklist

CODE:
```bash
# 1. Install project dependencies and build the production bundle
npm install
npm run build

# 2. (Optional, if using Multi-Target Application (MTA) packaging)
# Install the mbt tool (if not already installed)
npm install -g @sap/mbt

# Build the MTA archive (produces mtar under mta_archives/)
mbt build

# 3. (Optional, Cloud Foundry CLI deployment)
# Install and login to CF CLI and target your org/space
cf login -a https://api.<region>.cf.<domain> -u <user> -p <password> -o <org> -s <space>

# Deploy the built MTA archive (replace <archive>.mtar)
cf deploy mta_archives/<project>.mtar -f
```

STEP: 2 — Deploy using SAP Fiori tools (Business Application Studio or VS Code UI)

DESCRIPTION: Use the SAP Fiori tools extension to run a wizard/command-driven deployment from the IDE. This is the recommended quick path to push an app to supported targets (BTP Cloud Foundry, ABAP, or other configured servers).

LANGUAGE: UI / Command Palette

CODE:
```text
# Typical UI-driven steps (use in BAS or VS Code with SAP Fiori tools installed):
1. Open your Fiori project in BAS or VS Code.
2. Open Command Palette:
   - Windows/Linux: Ctrl+Shift+P
   - macOS: Cmd+Shift+P
3. Run the Fiori tools deploy command:
   - Type: "Fiori: Deploy Application"  (or "SAP Fiori Tools: Deploy Application")
4. Follow the wizard:
   - Select the target type (Cloud Foundry / ABAP / Other)
   - Select destination / system (choose configured BTP/ABAP connection)
   - Provide credentials or choose a saved destination
   - Confirm transport/space/org settings if prompted
5. Monitor the Output/Terminal view for deployment logs and success messages.
```

STEP: 3 — CLI deployment to Cloud Foundry (MTA archive)

DESCRIPTION: Build an MTA archive and deploy it directly via the Cloud Foundry CLI. Use this when you need repeatable scripted deployments or CI/CD integration.

LANGUAGE: Bash

CODE:
```bash
# Build MTA archive
mbt build

# Login with CF CLI (one-time)
cf login -a https://api.<region>.cf.<domain> -u <user> -p <password> -o <org> -s <space>

# Deploy the MTA archive
cf deploy mta_archives/<project>.mtar -f

# Watch logs for the application or service instances as needed:
cf logs <app-name> --recent
```

STEP: 4 — ABAP deployment notes (using Fiori tools)

DESCRIPTION: SAP Fiori tools provide a UI path to deploy to ABAP systems (BSP/Flp). Use the IDE deploy command, choose ABAP as target, and supply the ABAP system connection or destination. For ABAP-specific requirements (transports, package, BSP name), respond to prompts in the wizard. See official docs for ABAP system setup.

LANGUAGE: Text / UI

CODE:
```text
# Typical ABAP deployment flow in IDE:
1. Open Command Palette -> "Fiori: Deploy Application"
2. Choose target -> ABAP
3. Enter/select ABAP destination (system alias, client, user)
4. Provide package name or local object (if required)
5. Confirm transport request or choose local change
6. Watch Output/Terminal for upload and activation messages
# For detailed ABAP prerequisites and steps, consult:
# https://help.sap.com/docs/SAP_FIORI_tools/17d50220bcd848aa854c9c182d65b699/1b7a3be8d99c45aead90528ef472af37.html
```

STEP: 5 — Troubleshooting common issues

DESCRIPTION: Quick checks when deployment fails: verify connectivity, credentials, built artifacts, target capacity, and review logs shown in IDE Output or CF logs.

LANGUAGE: Checklist

CODE:
```text
# Troubleshooting checklist:
- Confirm npm run build completed without errors.
- Verify mbt build produced an .mtar in mta_archives/.
- Ensure CF CLI is logged in to the correct org/space.
- For ABAP: Verify destination settings and transport availability.
- Check IDE Output and Terminal for detailed error messages.
- Retry with increased verbosity or check BTP cockpit / ABAP logs for server-side errors.
```

fiori-elements-framework sap-fiori-tools deployment business-application-studio visual-studio-code cloud-foundry mbt


**TITLE**: Extension Functions Reference — Adaptation Extensions for SAP Fiori elements (OData V2)

**INTRODUCTION**: Concise, action-oriented reference for implementing controller extension functions in adaptation extensions for SAP Fiori elements (OData V2). Each step shows what to implement, expected inputs/outputs, and minimal code examples demonstrating how to call the platform-provided helper functions (fnSetAppStateData, fnGetAppStateData, fnEnsureSelectionProperty, fnAddFilter, fnSetExtensionStateData, fnGetExtensionStateData, etc.).

**TAGS**: fiori-elements, adaptation, extension, odata-v2, list-report, object-page, overview-page, analytical-list-page

**STEP**: onInitSmartFilterBar

**DESCRIPTION**: Implement this method to react when the SmartFilterBar is initialized. Use it for any custom initialization of filter controls, registering events, or reading initial filter values.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
// Controller extension: called when SmartFilterBar is initialized
onInitSmartFilterBar: function (oEvent) {
  // oEvent.getSource() is the SmartFilterBar control
  var oSmartFilterBar = oEvent.getSource();

  // Example: attach a liveChange handler to a custom filter field
  var oCustomField = oSmartFilterBar.getControlByKey && oSmartFilterBar.getControlByKey("MyCustomFilter");
  if (oCustomField) {
    oCustomField.attachLiveChange(function () {
      // custom logic
      console.log("Custom filter changed");
    });
  }
}
```

**STEP**: provideExtensionAppStateData

**DESCRIPTION**: Store extension-specific app state into the framework-managed app state. Must call fnSetAppStateData(oControllerExtension, oAppState). The core ignores calls if oAppState is faulty.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
// Example implementation inside controller extension
provideExtensionAppStateData: function (fnSetAppStateData, oControllerExtension) {
  // Prepare a plain JSON object representing your extension state
  var oAppState = {
    myCustomFlag: true,
    selectedIds: ["A", "B", "C"]
  };

  // Call the provided helper to store state for this controller extension
  // Follow the documented call signature
  fnSetAppStateData(oControllerExtension, oAppState);
}
```

**STEP**: restoreExtensionAppStateData

**DESCRIPTION**: Restore extension state previously stored in the app state. Use fnGetAppStateData(oControllerExtension) to retrieve it. The function returns undefined if no state or a faulty state was stored.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
// Example implementation inside controller extension
restoreExtensionAppStateData: function (fnGetAppStateData, oControllerExtension) {
  // Retrieve stored state for this controller extension
  var oStoredState = fnGetAppStateData(oControllerExtension);

  if (oStoredState) {
    // Apply stored values back to controls or internal variables
    if (oStoredState.myCustomFlag) {
      // apply behavior
    }
    if (Array.isArray(oStoredState.selectedIds)) {
      this._applySelectedIds(oStoredState.selectedIds);
    }
  } else {
    // No state to restore
  }
}
```

**STEP**: ensureFieldsForSelect

**DESCRIPTION**: Ensure that specific fields are present in the $select clause of the table binding used by the control with id sControlId. For each field call fnEnsureSelectionProperty(oControllerExtension, sFieldname). sFieldname must be an entity field or a relative path via a 1:1 navigation property.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
// Example implementation inside controller extension
ensureFieldsForSelect: function (fnEnsureSelectionProperty, oControllerExtension, sControlId) {
  // Ensure direct entity property
  fnEnsureSelectionProperty(oControllerExtension, "CustomerName");

  // Ensure a property accessible via a 1:1 navigation: NavProp/Field
  fnEnsureSelectionProperty(oControllerExtension, "Address/City");

  // Repeat for all fields your custom code depends on
}
```

**STEP**: addFilters

**DESCRIPTION**: Add additional filters (combined with AND with other filters). For each filter call fnAddFilter(oControllerExtension, oFilter). oFilter must be an instance of sap.ui.model.Filter.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
// Example implementation inside controller extension
addFilters: function (fnAddFilter, oControllerExtension) {
  // Create sap.ui.model.Filter instances (import or global sap.ui.model.Filter)
  var Filter = sap.ui.model.Filter;

  // Example: Status EQ 'A'
  var oStatusFilter = new Filter("Status", sap.ui.model.FilterOperator.EQ, "A");
  fnAddFilter(oControllerExtension, oStatusFilter);

  // Example: Date >= 2020-01-01
  var oDateFilter = new Filter("CreatedDate", sap.ui.model.FilterOperator.GE, "2020-01-01");
  fnAddFilter(oControllerExtension, oDateFilter);
}
```

**STEP**: provideExtensionStateData (Object Page)

**DESCRIPTION**: Store extension-specific state for Object Page lifecycle. Call fnSetExtensionStateData(oControllerExtension, oExtensionState). The call is ignored if oExtensionState is faulty. Lifecycle object parameters (Page, Permanent, etc.) should be provided in oExtensionState.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
// Example implementation inside Object Page controller extension
provideExtensionStateData: function (fnSetExtensionStateData, oControllerExtension) {
  // oExtensionState should provide lifecycle info and your data
  var oExtensionState = {
    lifecycle: {
      page: "Transient",
      permanent: false
    },
    myExtensionData: {
      lastFocusedSection: "General",
      customSelections: ["X", "Y"]
    }
  };

  fnSetExtensionStateData(oControllerExtension, oExtensionState);
}
```

**STEP**: restoreExtensionStateData (Object Page)

**DESCRIPTION**: Restore previously stored extension state for Object Page. Use fnGetExtensionStateData(oControllerExtension) to retrieve it. The helper returns undefined for missing/faulty state. bIsSameAsLast indicates whether the current view equals the last stored view (true: no adaptation needed).

**LANGUAGE**: JavaScript

**CODE**:
```javascript
// Example implementation inside Object Page controller extension
restoreExtensionStateData: function (fnGetExtensionStateData, oControllerExtension, bIsSameAsLast) {
  var oExtensionState = fnGetExtensionStateData(oControllerExtension);

  if (!oExtensionState) {
    return;
  }

  if (bIsSameAsLast) {
    // No view adaptation required
    return;
  }

  // Apply stored extension state
  if (oExtensionState.myExtensionData) {
    this._applyLastFocusedSection(oExtensionState.myExtensionData.lastFocusedSection);
    this._applyCustomSelections(oExtensionState.myExtensionData.customSelections);
  }
}
```

**STEP**: provideStartupExtension (Overview Page)

**DESCRIPTION**: Modify the selection variant object that will be set on the Overview Page filter bar. The parameter is a reference to the selection variant expected by the Overview Page; modify it in-place.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
// Example implementation inside overview controller extension
provideStartupExtension: function (oSelectionVariant) {
  // oSelectionVariant structure varies. Modify select options or parameters as required.
  // Example: add selection for Customer = 'CUST01'
  if (!oSelectionVariant.SelectOptions) {
    oSelectionVariant.SelectOptions = {};
  }
  oSelectionVariant.SelectOptions.Customer = [
    { Sign: "I", Option: "EQ", Low: "CUST01", High: null }
  ];

  // No return required if modifying by reference
}
```

**STEP**: provideExtensionNavigation (Overview Page)

**DESCRIPTION**: Return a new or modified navigation entry (custom navigation) for the core. This method receives the standard navigation entry details for a card and context; return the modified/alternative navigation entry object the core should use.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
// Example implementation inside overview controller extension
provideExtensionNavigation: function (oNavigationEntry) {
  // Modify target route or parameters
  var oCustomNav = Object.assign({}, oNavigationEntry);

  // Example: change semantic object/action or add a custom parameter
  oCustomNav.semanticObject = "MyObject";
  oCustomNav.action = "display";
  oCustomNav.parameters = oCustomNav.parameters || {};
  oCustomNav.parameters.customParam = "value";

  // Return the custom navigation entry for the core to execute
  return oCustomNav;
}
```

**STEP**: provideCustomActionPress (Overview Page)

**DESCRIPTION**: Capture a custom action's press event and return an event object or perform custom logic. The method is defined in the controller extension and the core forwards the event.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
// Example implementation inside overview controller extension
provideCustomActionPress: function (oEvent) {
  // oEvent is the press event from the card/action
  var oPressedEvent = oEvent;

  // Custom behavior: show a message, modify event, etc.
  console.log("Custom action pressed", oPressedEvent);

  // Optionally return the event or a promise resolving to event details
  return oPressedEvent;
}
```

**STEP**: provideCustomParameter (Overview Page)

**DESCRIPTION**: Map a name/key to a function that provides custom parameters. The core calls this method with the key; return a function that resolves/returns the custom parameters (can be sync or return a Promise).

**LANGUAGE**: JavaScript

**CODE**:
```javascript
// Example implementation inside overview controller extension
provideCustomParameter: function (sName) {
  if (sName === "getCardParams") {
    // Return a function that provides parameters (can be async)
    return function () {
      return {
        param1: "value1",
        param2: 123
      };
    };
  }

  // For unknown names return undefined
  return undefined;
}
```

**STEP**: Related Information (file reference)

**DESCRIPTION**: Reference to the adaptation extensions how-to file for creating adaptation projects.

**LANGUAGE**: text

**CODE**:
```
Extending Delivered Apps Using Adaptation Extensions:
extending-delivered-apps-using-adaptation-extensions-52fc48b.md
```

fiori-elements adaptation extension odata-v2 list-report object-page overview-page analytical-list-page