How to Access Elements from XML Fragment by ID

Nilesh Puranik picture Nilesh Puranik · Sep 23, 2016 · Viewed 38.1k times · Source

I am working on a SAPUI5 application. I have an XML view which contains an XML Fragment and a Button to save.

The fragment contains a few controls like drop-down, text field and a table. When I press on the save button, I need to get all the rows in the table and call an OData update service.

The problem is in the onSave method in view controller. I get an error while accessing the table using its ID. Can anyone help me and advice how can I access controls used in fragments by their ID in the controller?

Here is the code snippet:

View:

<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns:core="sap.ui.core" xmlns:form="sap.ui.layout.form" xmlns="sap.m">
    <Page>
        ...
        <form:SimpleForm>
            <core:Fragment id ="fr1" fragmentName="first" type="XML" />
            <Button id="id1" press="onSave" />
        </form:SimpleForm>
    </Page>
</mvc:View>

Fragment definition:

<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core">
    <Table id="tab1" mode="MultiSelect">
        ...
    </Table>
</core:FragmentDefinition>

Controller:

sap.ui.controller("view", {
    onSave: function() {
        //var tab = this.getView().byId("tab1"); // Not working
        var tab  = sap.ui.getCore().byId("tab1"); // Not working
    },
    // ...
});

Answer

Boghyon Hoffmann picture Boghyon Hoffmann · Dec 18, 2017

Accessing controls inside a fragment depends on how your fragment was created in the first place. Here is a list of cases with respective API to use to get the control reference:

API to Use

this.byId("controlId");

  • When the fragment was created with a view ID:

    sap.ui.xmlfragment(this.getView().getId(), "my.Fragment", this); // deprecated *
    <core:Fragment fragmentName="my.Fragment" type="XML" />
    <!-- Here, the view ID will be automatically passed to the fragment -->
  • Global ID: "componentId---viewId--controlId"**


this.byId(Fragment.createId("fragmentId", "controlId"));

  • When the view ID and a fragment ID were given:

    sap.ui.xmlfragment(this.createId("fragmentId"), "my.Fragment", this); // deprecated *
    <core:Fragment id="fragmentId" fragmentName="my.Fragment" type="XML"/>
  • Global ID: "componentId---viewId--fragmentId--controlId"**


Fragment.byId("fragmentId", "controlId");

  • When fragment ID only:

    sap.ui.xmlfragment("fragmentId", "my.Fragment", this); // deprecated *
  • Global ID: "fragmentId--controlId"


sap.ui.getCore().byId("controlId");

  • When no IDs were given:

    sap.ui.xmlfragment("my.Fragment", this); // deprecated *
    // All control IDs within the fragment gets registered globally without any prefixes!!
    
  • Global ID: "controlId"


document.getElementById(a) // Only for native <html:...> elements within the fragment

  • Whereas a corresponds to this.createId("elementId"), Fragment.createId("fragmentId", "elementId"), or just "elementId" depending on how the fragment was created as described above.


*: The API sap.ui.*fragment is deprecated. Use Fragment.load instead (available since 1.58).

**: The component ID won't be a part of the global ID if no stable ID was given for the view. In that case, the global ID starts with the generated view ID: "__xmlview0--...".


Given

  • this: Reference to the controller instance
  • Fragment: Parameter name for the resolved module given by the dependency definition

    sap.ui.define([ // or .require
      "sap/ui/core/Fragment",
      // ...
    ], function(Fragment, /*...*/) { /*...*/});
    

Note

  • Avoid concatenating ID parts or relying on the syntax of the global ID, as mentioned in the comment as well as in the documentation:

    Do not rely on the specific prefixing syntax because it may change at some point. Always use methods like byId() and createId().

  • Consider to avoid using the above APIs when the intention is actually to alter some data that are being used in the fragment controls (e.g. myManuallyAccessedInput.setValue("...")). Make use of data binding instead ⇒ Changes in model will be reflected in UI automatically.