GoodData.UI: Custom Filter with GoodData.CN Backend

  • 28 June 2021
  • 0 replies
  • 76 views

This article will guide you through implementation of a custom dropdown filter that supports thousands of values via pagination. To achieve this, we will integrate GoodData’s Accelerator Toolkit with the react-select-async-paginate (RSAP) library.

 

As a Prerequisite, you will need an instance of GoodData.CN and a workspace with some data. If you do not have this, you can follow this article which explains how to install GoodData.CN and create a workspace with the included demo data.

 


 

Once we have GoodData.CN setup, we can spin up a React application using the Accelerator Toolkit. Run the following command in terminal:

npx @gooddata/create-gooddata-react-app --backend tiger

 

You will be prompted with some questions, be sure to set up your hostname correctly. Since we will be using GoodData.CN, the hostname will be: http://localhost:3000

? What is your application name? my-app

? What is your hostname? I have a custom hostname

? Insert your hostname: http://localhost:3000

? What is your application desired flavor? JavaScript

 

Next we will cd into the application directory and add the RSAP libraries:

cd my-app

yarn add react-select@3.1.0 react-select-async-paginate@0.3.14

 

After adding the necessary libraries, we can start the application:

yarn start

 

You will be met by a Welcome page from the Accelerator Toolkit:

7vLvuQirafH1C4mxXcADlgGLpFW7OD7Ny3HZrWd-2hMKAk9GdSNaLq8_wEMNHU3l5-Y2iKng_QXkBSPu_Sp-uktLwBmKz0_ru5ljWsBpga57m9vQIRyo3qJB3J4uuk6RrKsgQD62

 

If a browser does not automatically pop up after starting the application, you can go to the application URL in the browser manually

https://localhost:3000/
 


 

This example will use GoodData.UI at a very low level. We will only be using the backend / API and not any of the visual components. The RSAP library will actually render the dropdown filter. You will need a workspace with data. Any attribute with values loaded to it will work.

 

Let’s make a few changes to the application before we get to the dropdown filter:

In /src/constants.js

Double check that backend is set to the domain that you will be working with and set workspace to the workspace you will be working with.

 

In /src/routes/AppRouter.js

Find the line that says DELETE THIS LINE, and delete it.

This removes the redirect to the welcome page and sets up Home as the default landing page. We will be doing our work on the Home page.

 

Find the two sections that have the comment:

Uncomment the next line if you want to redirect unauthorized users to login form

Uncomment those sections to redirect the user to the login page if the user is not already logged in.

 

Copy and paste the code below to /src/routes/Home.js 

import React, { useState } from "react";
import { useWorkspace } from "../contexts/Workspace";
import AsyncPaginate from 'react-select-async-paginate';

import Page from "../components/Page";

// The number of values that will be fetched per page
const PAGE_SIZE = 10;

// The label ID of the attribute
const ATTRIBUTE_LABEL = "products.product_name";

// helper method to parse the paging metadata from the api response
const getPagingInformation = (response) => {
const paging = response.paging;
const { count, total, offset: prevOffset } = paging;

return {
count,
total,
prevOffset,
};
};

const Home = (props) => {
const [value, onChange] = useState([]);
const { workspace } = useWorkspace();

const loadOptions = async (search, prevOptions, { offset }) => {

const response = await fetch(`http://localhost:3000/api/actions/workspaces/${workspace}/execution/collectLabelElements?label=${ATTRIBUTE_LABEL}&offset=${offset}&limit=${PAGE_SIZE}`, {
method: 'GET',
mode: 'cors',
credentials: 'include',
headers: {
"accept": "application/json, text/plain, */*",
}
});
const data = await response.json();

// get the options / values returned
const elements = data.elements.map((element) => ({
label: element.title,
value: element.primaryTitle
}));

// get the paging metadata from elements API call
const { count, prevOffset, total } = getPagingInformation(data);

const hasMore = prevOffset + count < total;
const newOffset = prevOffset + count;

return {
options: elements,
hasMore,
additional: {
offset: newOffset
}
};
};

return (
<Page>
Paging Filter
<AsyncPaginate
value={value}
loadOptions={loadOptions}
isMulti
closeMenuOnSelect={false}
onChange={onChange}
additional={{ offset: 0 }}
/>
</Page>
);
};

export default Home;

There are two variables that need to be set:

PAGE_SIZE

This sets the page size. Set this to something small at first to see the paging work.

 

ATTRIBUTE_LABEL

As previously mentioned, you will need a workspace with data. This string is set to the attribute label identifier of the attribute you want to use as a filter.

 

Once setup, save /src/routes/Home.js and go to the application. You should see a dropdown filter that loads new pages of data once the scroll bar hits the bottom. Remember to set PAGE_SIZE to something small so you can easily see the paging in action!

 

 

Let’s look closer at my example. PAGE_SIZE is set to 10 and I have 18 total values. This results in 2 pages of data.

 

Response (Page) 1:

 

The paging metadata contains 3 values.

count

The number of values returned in the response.

 

total

The total number of values for the attribute label.

 

offset

The offset from the starting value. We see here that it is 0 since this is the first page.

 

The elements array contains the first 10 values, from index 0 to 9.

 

Response (Page) 2:

 

Here we see that the offset has changed. The items array contains the next 10 values. Since we only have a total of 18 values, count is 8 and the elements array contains the last set of values from index 10 - 17. We know this is the last page because: offset + count = total. A similar check occurs with variable hasMore in the code. This tells the code that we no longer need to load any new values, since we have them all.

 

NOTE: You can leverage the next parameter in the paging metadata to control the paging logic for simple use cases. By not using the next parameter we allow for complete customization of the paging logic. For example if we wanted dynamic page sizes. Read more about the API that we are using here.

 

This example is a great starting point for implementing custom filters into your GoodData.UI application. Thanks for reading / coding!

 

If you are interested in GoodData.CN, please contact us.

Alternatively, test a trial version of GoodData Cloud:

Start Your GoodData Analytics Trial — Commitment-Free


This topic has been closed for comments