Skip to Content
Product Information

Annotating annotations in SAP Cloud Application Programming (CAP) with code completion

I’ve heard from several developers that specifying annotations is the most challenging part when developing applications based on the SAP Fiori elements framework. This is especially true if you have no tools support, as many of us felt trying to add annotations in .cds files of CAP (SAP Cloud Application Programming) projects. We recently introduced code completion for OData annotations in CAP, so even the trickiest things, such as applying annotations to an existing annotation or its part can be achieved with a few clicks.

In this blog post, I will show you how it works with a couple of examples.

Example 1: Annotating UI.DataField records to control table responsiveness

 

In this example, I have a table of safety incidents represented by the annotation “UI.LineItem”.

annotate service.SafetyIncidents with @UI.LineItem : [
{
    $Type : 'UI.DataField',
    Value : title,
},
{
    $Type : 'UI.DataField',
    Value : priority_code,
},
{
    $Type : 'UI.DataField',
    Value : category_code,
},
{
    $Type : 'UI.DataField',
    Value : incidentStatus_code,
},
];

On small screens, such as a typical smartphone, the first three columns keep their places by default, and all the other columns move to the second line. But, sometimes you want to show the important information in the right part of the table on large screens and still keep them distinctly visible on the small screens too. In this case, the columns in the middle should slide down to the second line: note the Priority column in the right screenshot below.

 

To implement this, I applied the annotation “UI.Importance” to UI.DataField records in my LineItem. So, I annotate the data fields for incident title, category and status with High importance, to keep them always distinctly visible. The only non-high value now moves to the second line, giving its space to the VIPs.

annotate service.SafetyIncidents with @UI.LineItem : [
{
    $Type : 'UI.DataField',
    Value : title,
    ![@UI.Importance] : #High,
},
{
    $Type : 'UI.DataField',
    Value : priority_code,
},
{
    $Type : 'UI.DataField',
    Value : category_code,
    ![@UI.Importance] : #High,
},
{
    $Type : 'UI.DataField',
    Value : incidentStatus_code,
    ![@UI.Importance] : #High,
},
];

Even if you forget the correct syntax for this annotation/value or do not have this example in front of you, use the code completion (CTRL+Space) next to the Value and select a suggestion from the list – it could be even faster than copying!

In this video, you can see it yourself:

Note: Alternatively, I could have annotated the priority_code record with the low importance rather than the 3 records with high, but with the real-life tables having much more than 4 columns it makes more sense to mark those that are more important and ignore the remaining ones.

Example 2: Annotating UI.LineItem to highlight table rows based on criticality

In this example, I would like to highlight the rows in my table based on the incident priority. Thus, priority would still be easily visible, even when the value appears in the second row.

According to the SAP UI5 documentation, I need to apply the annotation “UI.Criticality” to the whole Ui.LineItem annotation.

This is really tricky in cds syntax, even for experienced users: the LineItem annotation should be wrapped in curly brackets { } with $value and then annotated with UI.Criticality in ![ ] syntax. Finally, the value pointing to the entity element containing criticality information should be added:

annotate service.SafetyIncidents with @UI.LineItem : {
    ![@UI.Criticality] : priority.criticality,
    $value:  [
        {
            $Type             : 'UI.DataField',
            Value             : title,
            ![@UI.Importance] : #High,
        },
        {
            $Type : 'UI.DataField',
            Value : priority_code,
        },
        {
            $Type             : 'UI.DataField',
            Value             : category_code,
            ![@UI.Importance] : #High,
        },
        {
            $Type             : 'UI.DataField',
            Value             : incidentStatus_code,
            ![@UI.Importance] : #High,
        },
        ]
};

Thankfully, with code completion all this is achieved with just a few clicks: use CTRL+Space right before the collection brackets [] of the LineItem and choose UI.Criticality – all the wrapping and formatting will be done automatically. Now use the code completion again to select the value and you are done:

Try it out and provide feedback

You can try this out yourself in Visual Studio Code with  SAP Cloud Platform core data services plug-in for Visual Studio Code (v 3.0.0 or higher) any time, as it is already enhanced with the @sap/ux-cds-odata-language-server-extension.

If you use SAP Business Application Studio, you can find it in the SAP Cloud Business Application dev space.

Once you try it, share your experience with OData annotation support in the comments: what works well, what requires improvement and what else you like to know about LSP features for OData annotations (code completion, diagnostics, etc).

More information on OData annotation support in CAP CDS

28 Comments
You must be Logged on to comment or reply to a post.
  • Hi,

    wrt open sourcing CAP: yes, we would like to do it and ponder about it every now and then.  Still no concrete plans yet, mainly due to the high load on the dev teams here.

    For PostgreSQL, see the community works on it: https://blogs.sap.com/2020/08/20/postgresql-persistence-adapter-for-cap-node.js/

     

    Regards, Christian

  • Dear Mariana,

     

    I have a self developed bookshop Odata Service Fiori Elements App in my Business Application Staudio, code can be seen here --> miyasuta/central-launchpad-cap (github.com)

    Now I am trying to extend it via Fiori tools with an additional button (action). I also have been following your video : https://www.youtube.com/watch?v=p1f0Albi7eE

    and documentation. Code is added to manifest and the extension controller file but the extensions won't show up in the app. Do you have any idea why this is not working? Do the extensions for instance only work for fiori standard apps with an OData Service from Backend etc.?

     

    I would highly appreciate your answer:)

    Best Regards

    Max

    • Hello Max,

      Could you please share more information on how you use Fiori tools to add an custom action? Where exactly are you adding this button?
      In the attached github repo, I couldn't find your extension coding.

      Best Regards,

      Hitesh

  • Hi Hitesh Parmar

     

    thanks for your response:)

    this was the template that i used to implement the extension. All I added was the extension in my manifest file plus the extension controller ( both in the app/fiori/webapp folder)

    I uploaded my extension project here:

    SnarkWay/bookshopapp (github.com)

    Do you find an issue?

    Do the annotations from the service file overwrite my extension?

     

    Best Regards

    Max

    • Hi Max Schnürle ,

      Yes, you are correct, currently the Guided Development only supports OData V2. To see the guides only applicable to OData V4 you can group guides by OData Version.

      We will take this up to improve the UX.

      Group%20guides%20by%20OData%20version

      Group guides by OData version

      Your coding looks correct to me. Let me take a deeper look into this.

       

      Best Regards,

      Hitesh

      /
      Group%20guides%20by%20OData%20version
    • Hi Max Schnürle ,

       

      I tried with your application and I can see that the button is rendered properly. I have a feeling that you overlooked the button in the UI. With your current coding in manfiest.json, global action will be added.

      See here: https://sapui5.hana.ondemand.com/#/topic/7619517a92414e27b71f02094bd08d06

      Custom%20Global%20Action

      Custom Global Action

      Additionally make sure to make use of the following controller code (as mentioned in the documentation).

       extendFunctionBooks: function(oContext, aSelectedContexts) {
              // oContext :  is the binding context of the current entity 
              // aSelectedContexts : contains an array of binding contexts corresponding to 
              // 						selected items in case of table action (or) 
              // 						current entity in case of header / footer action. 
          }

       

      Best Regards,

      Hitesh

      /
      Custom%20Global%20Action
  • /
    customActions.js
  • Hitesh Parmar

    now the question is how I can start a workflow instance from that customEvent?

    I am using Archana's blog post for that:

    https://blogs.sap.com/2020/08/27/starting-workflow-from-custom-fiori-application-in-cloud-foundry/

    but the $ajax call throws an error because it doesnt find the XSRF Token(502-BadGatewayError)

    i thought its because Im calling from SAP Fiori Elements App but it should work the same as in UI5.

    Do you have any idea?

     

    Best Regards

    Max

    /
  • Hi @Hitesh Parmar,in OData V2 was an annotation loadDataOnAppLaunch to eliminate Go button,
    I can not find the way to do it in V4, could you please help?

    "dataLoadSettings": {
    "loadDataOnAppLaunch": "always"
    }

     

    thx in advance,
    Pavel

  • Hi Mariana Naboka,

    we are struggling with the UI.Hidden annotation. We can set it to a property of our entity, but our requirement is to control actions that mark a Product as Favourite if it is not marked as favourite and to remove it from the Favourites if it is marked as a Favourite.

    In one case it's easy, the annotation is "![@UI.Hidden]: isFavourite", but in the second case we would like to use an expression to negate the isFavourite property of the entity. Is this possbile with the CAP Annotation Syntax?

    As a workaround we have introduced a second property "isNotFavourite", but this is a rather ugly workaround.

    We were not able to find any examples of documentation regarding expressions for CAP CDS Annotations.

    Kind regards,

    Sebastian

    • Hi Sebastian Esch,

      SAP Fiori elements floorplans for OData v4 support OData annotation expressions. Not at all places yet but at least all the usages of hidden are enabled for expressions.

      But: unfortunately CAP CDS does not yet support annotation expressions.

      Until then you can help you with local annotations, like:

      <Record Type="UI.DataFieldForAction">
         <PropertyValue Property="Label" String="Your Action Label" />
         <PropertyValue Property="Action" String="yourNameSpace.YourAction" />
         <Annotation Term="UI.Hidden">
            <Not>
               <Path>isFavorite</Path>
            </Not>
         </Annotation>
      </Record>

      The issue with having local annotations in this case means you would need to override on a term level, so for example if this is an action in a table the whole UI.LineItem. So this is actually not a very good example of having local annotations if you have all the annotations in your CDS.

      Can you tell me if you use CAP JAVA or CAP Node? I will try to reach the product owner to see if when this can be expected.

      Best regards,
      Marcel

        • you can also use the same logical operator in cap cds, if you work with the latest cds compiler. CDS compiler then converts it to the code suggested by Marcel Waechter above.
          Here is how it looks in cap cds:
          {
                  $Type         : 'UI.DataFieldForAction',
                  Label         : 'Your Action Label',
                  Action        : 'yourService.YourAction',
                  ![@UI.Hidden] : {$edmJson : {$Not : [{$Path : 'isFavorite' } ] } },
              }
          • Steffen Weinstock

            Sorry, my fault. Got lost in compiler versions 🙁

            Sebastian Esch

            So you can either use the xml, or wait for the compiler version containing this feature.

            BTW, Fiori tools already provide the code completion for logical operators in xml annotation files - by default they are sorted out to the end of the code completion list.

            Once it is released, we will do our best to provide the code completion to simplify it for the end users also in CAP cds.

            /
          • Hi Mariana Naboka,

            we will patiently wait for the July release of CAP and then remove our workaround. 🙂

            I haven't used the Fiori Tools XML Editor yet - the last time I did Fiori Elements with local annotations, Web IDE was the tool of choice and BAS / Fiori Tools was not around yet.

            Cheers,

            Sebastian