2024 Dec 31 4:09 AM - edited 2024 Dec 31 4:16 AM
Hi everyone, I am facing issues with my SAPUI5 application; the data is duplicated in the binding. I am using OData v4 created from my CDS. I've created CDS in Eclipse to get Journal Entry Items based on G/l Line Items. I'm using I_GLAccountLineItem and I_JournalEntryItem to get the data, below is my CDS code:
### CDS in Eclipse
@AbapCatalog.sqlViewName: 'ZGLITEMS'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'General Ledger Line Items'
@Metadata.ignorePropagatedAnnotations: true
define root view ZGL_LINE_ITEMS
as select distinct from I_GLAccountLineItem as GlLineItem
association [0..1] to I_JournalEntryItem as _toJournalEntryItem
on GlLineItem.AccountingDocument = _toJournalEntryItem.AccountingDocument
and GlLineItem.FiscalYear = _toJournalEntryItem.FiscalYear
and GlLineItem.Ledger = _toJournalEntryItem.Ledger
and GlLineItem.GLAccount <> _toJournalEntryItem.GLAccount
and GlLineItem.DebitCreditCode <> _toJournalEntryItem.DebitCreditCode
association [0..1] to I_User as _toUser
on GlLineItem.AccountingDocCreatedByUser = _toUser.UserID
{
key GlLineItem.CompanyCode as CompanyCode,
key GlLineItem.AccountingDocument as AccDoc,
GlLineItem.PostingDate as PostingDate,
GlLineItem.FiscalPeriod as Period,
GlLineItem.FiscalYear as FisYear,
GlLineItem.Ledger as Ledger,
GlLineItem.GLAccount as GlAccount,
GlLineItem.DocumentItemText as Description,
_toJournalEntryItem.GLAccount as OpposingGLAccount,
GlLineItem.DebitCreditCode as DebitCreditCode,
GlLineItem.CompanyCodeCurrency as Currency,
@Semantics.amount.currencyCode: 'Currency'
GlLineItem.AmountInCompanyCodeCurrency as AmountInGlLineItem,
// Summing amounts for the GL account
@Semantics.amount.currencyCode: 'Currency'
sum(_toJournalEntryItem.AmountInCompanyCodeCurrency) as AmountInJournalEntry,
GlLineItem.AccountingDocCreatedByUser as CreatedBy,
_toUser.UserDescription as CreatedByDesc,
// Associations
_toJournalEntryItem,
_toUser
}
where
GlLineItem.Ledger = '0L'
group by
GlLineItem.CompanyCode,
GlLineItem.AccountingDocument,
GlLineItem.PostingDate,
GlLineItem.FiscalPeriod,
GlLineItem.FiscalYear,
GlLineItem.Ledger,
GlLineItem.GLAccount,
GlLineItem.DocumentItemText,
_toJournalEntryItem.GLAccount,
GlLineItem.DebitCreditCode,
GlLineItem.CompanyCodeCurrency,
GlLineItem.AmountInCompanyCodeCurrency,
GlLineItem.AccountingDocCreatedByUser,
_toUser.UserDescription;### Main.view.xml
<mvc:View controllerName="laporankas.laporankas.controller.Main"
xmlns="sap.m"
xmlns:uxap="sap.uxap"
xmlns:mvc="sap.ui.core.mvc"
xmlns:core="sap.ui.core"
height="100%">
<uxap:ObjectPageLayout
id="idObjectPageLayout"
showHeaderContent="true"
toggleHeaderOnTitleClick="true"
upperCaseAnchorBar="false"
showFooter="true">
<uxap:headerTitle>
<uxap:ObjectPageDynamicHeaderTitle id="idObjectPageDynamicHeaderTitle">
<uxap:expandedHeading>
<Title text="Laporan Kas" wrapping="true" />
</uxap:expandedHeading>
<uxap:snappedHeading>
<Title text="Laporan Kas" wrapping="true" />
</uxap:snappedHeading>
<uxap:expandedContent>
<Text text="{glRange>/glAccountFrom} - {glRange>/glAccountTo}" />
</uxap:expandedContent>
<uxap:snappedContent>
<Text text="{glRange>/glAccountFrom} - {glRange>/glAccountTo}" />
</uxap:snappedContent>
</uxap:ObjectPageDynamicHeaderTitle>
</uxap:headerTitle>
<uxap:headerContent>
<HBox alignItems="End">
<VBox>
<Label text="G/L Account" />
<ComboBox
id="idGlDataSetComboBox"
items="{glModel>/glDataSet}"
selectionChange="onGlDataSetComboBoxSelectionChange"
placeholder="Select GL Account">
<core:Item key="{glModel>gl}" text="{glModel>gl}" />
</ComboBox>
</VBox>
<VBox class="sapUiSmallMarginBegin">
<Label text="Posting Date" />
<DateRangeSelection change="onDateRangeSelectionChange" />
</VBox>
<VBox class="sapUiSmallMarginBegin">
<Label text="Created By" />
<ComboBox
id="idUserDataSetComboBox"
items="{userModel>/userDataSet}"
selectionChange="onUserDataSetComboBoxSelectionChange"
placeholder="Select Created By">
<core:Item key="{userModel>user}" text="{userModel>user}" />
</ComboBox>
</VBox>
<VBox class="sapUiSmallMarginBegin">
<Button type="Emphasized" text="Go" press="onGoButtonPress" />
</VBox>
</HBox>
</uxap:headerContent>
<uxap:sections>
<uxap:ObjectPageSection
showTitle="false"
class="sapUiLargeMarginTopBottom">
<uxap:subSections>
<uxap:ObjectPageSubSection>
<VBox>
<Table
sticky="ColumnHeaders"
id="idZglLineItemsTable"
items="{
path: '/ZGL_LINE_ITEMS',
filters: [
{
path: 'CreatedBy',
operator: 'NE',
value1: 'SAP_SYSTEM'
},
{
path: 'GlAccount',
operator: 'EQ',
value1: '10010000'
}
],
sorter: {
path: 'PostingDate',
descending: true
}
}"
growing="true"
growingThreshold="200"
alternateRowColors="true"
growingTriggerText="Load More"
noDataText="No data found"
mode="SingleSelectMaster"
updateFinished="onTableUpdateFinished">
<columns>
<Column>
<Text text="Date" />
</Column>
<Column>
<Text text="Journal Entry" />
</Column>
<Column>
<Text text="G/L Acc." />
</Column>
<Column>
<Text text="Description" />
</Column>
<Column>
<Text text="Opp. G/L Acc." />
</Column>
<Column>
<Text text="Amount" />
</Column>
<Column>
<Text text="CreatedBy" />
</Column>
</columns>
<items>
<ColumnListItem>
<cells>
<Text text="{PostingDate}" />
<Text text="{AccDoc}" />
<Text text="{GlAccount}" />
<Text text="{Description}" />
<Text text="{OpposingGLAccount}" />
<Text text="{AmountInJournalEntry}" />
<Text text="{CreatedByDesc}" />
</cells>
</ColumnListItem>
</items>
</Table>
</VBox>
</uxap:ObjectPageSubSection>
</uxap:subSections>
</uxap:ObjectPageSection>
</uxap:sections>
<uxap:footer>
<OverflowToolbar>
<ToolbarSpacer />
<Button
type="Emphasized"
text="Export PDF"
press="onExportPDFButtonPress" />
</OverflowToolbar>
</uxap:footer>
</uxap:ObjectPageLayout>
</mvc:View>### Main.controller.js
sap.ui.define(
[
'sap/ui/core/mvc/Controller',
'sap/ui/model/json/JSONModel',
'sap/ui/model/Filter',
'sap/ui/model/FilterOperator',
],
function (Controller, JSONModel, Filter, FilterOperator, PdfmakeMin, vfs_fonts) {
'use strict';
return Controller.extend('laporankas.laporankas.controller.Main', {
onInit: function () {
const oModel = this.getOwnerComponent().getModel(); // Get the OData V4 model
if (!oModel) {
console.error('OData V4 Model is not available.');
return;
}
// Define filters
const client = this._getClientFromURL();
const glAccount = client === '080' ? '0010010000' : '0011010020';
const aFilters = [
new Filter('GlAccount', FilterOperator.EQ, glAccount),
new Filter('CreatedBy', FilterOperator.NE, 'SAP_SYSTEM'), // Example filter for CompanyCode
];
// Bind the entity set with filters
const oListBinding = oModel.bindList('/ZGL_LINE_ITEMS', undefined, undefined, aFilters);
// Fetch filtered data
oListBinding
.requestContexts()
.then((aContexts) => {
const aData = aContexts.map((oContext) => oContext.getObject());
console.log('Filtered Data:', aData); // Log the filtered data to the console
})
.catch((oError) => {
console.error('Error Fetching Data:', oError); // Log any errors
});
},
_getClientFromURL: function () {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get('sap-client') || '080'; // Default client
}
});
},
);
### Example CDS result when I run in Eclipse
| AccDoc | PostingDate | GlAccount | Opposing GlAccount | Amount In Journal Item |
| 100000145 | 2024-12-30 | 10010000 | 65301000 | 700000 |
| 100000145 | 2024-12-30 | 10010000 | 63009000 | 400000 |
| 100000145 | 2024-12-30 | 10010000 | 61012100 | 500000 |
### The Issue (Result when the data bound in SAPUI5 App)
##### Here is the first result:
| AccDoc | PostingDate | GlAccount | Opposing GlAccount | Amount In Journal Item |
| 100000145 | 2024-12-30 | 10010000 | 65301000 | 700000 |
| 100000145 | 2024-12-30 | 10010000 | 65301000 | 700000 |
| 100000145 | 2024-12-30 | 10010000 | 65301000 | 700000 |
##### Here is the second result when I refresh:
| AccDoc | PostingDate | GlAccount | Opposing GlAccount | Amount In Journal Item |
| 100000145 | 2024-12-30 | 10010000 | 63009000 | 400000 |
| 100000145 | 2024-12-30 | 10010000 | 63009000 | 400000 |
| 100000145 | 2024-12-30 | 10010000 | 63009000 | 400000 |
### What I've done to solve the issue
- I tried to hit the entity endpoint in the browser/Postman, and I got the correct result as in Eclipse, which makes me a little bit confused.
- I tried to console.log it from the controller, but the result is not correct (duplicated).
Please let me know if there's something wrong with the CDS I created or my configuration in my SAPUI5 App or let me know if there's anything I need to do to solve this issue. Thank you in advance!
Request clarification before answering.
Even if the key value is duplicated, it is displayed normally when calling the CDS Entity from Postman.
but When table binding is performed, data is expressed repeatedly due to the same key value.
This is
It's not a Binding error, it's a CDS key field configuration issue.
You need to change the key field configuration so that the key value is unique.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I recently resolved the issue by manually fetching the entity endpoint from the controller in the `onInit` method and binding the data to the table. However, I will consider your suggestion to change the key field configuration in the CDS for a more optimal solution. Thank you! @hjshin
Hi @WG23
You need to check the CDS key field configuration information.
Can one Line Item be extracted with the two (CompanyCode, AccountingDocument) key fields specified in CDS?
If more than one is extracted, the data may be displayed as duplicate when binding.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
* Try this:
1. Main.controller.js - Comment out onInit Method.
2. Main.view.xml
Set Table Binding property(item) information the same as Postman
3.Testing
* Questions
The binding information for Controller and View is the same. Is there a reason to set both?
* Note
To check OData service response data
Check the response of WebBrowser's Developer Tools -> Network Tab -> Batch request.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @hjshin thanks for your comment.
What I do in the onInit function is just to console the data, to make sure if it is duplicated as it is in the main.view.xml or not.
In the postman, I just run a GET protocol with just filter parameters like I did in the table items. But still, I got different results in Postman and in my SAPUI5 Application
| User | Count |
|---|---|
| 8 | |
| 6 | |
| 6 | |
| 3 | |
| 3 | |
| 3 | |
| 2 | |
| 2 | |
| 2 | |
| 2 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.