Hello guys :partying_face: I am having an issue w...
# gooddata-ui
n
Hello guys 🥳 I am having an issue with filters. I want to apply filters to my Insights without using the AttributeFilter component. I am not able to apply more than one filter on an insight. For now i have just been trying with arrays and single variables so for example, in this code below i am applying two filters, the surveryIdFilter filter is supposed to be constant, and its supposed to always be on all my insights and testFilterState is a state that changes depending on what the user picks. this works but i need to be able to have more filters than that, where surveryIdFilter is supposed to always be there no matter what the user choses.
const surveryIdFilter = newPositiveAttributeFilter(filter.attribute, [filter.value]);
const [testFilterState, setTestFilterState] = useState<any>(surveryIdFilter);
<InsightView
insight={idRef(widget.widgetId)}
filters={[surveryIdFilter, testFilterState]}
/>
I have tried to make the state an array but once i do that my insights only display “NO DATA”. I also tried to do something like this for testing purposes:
const testFilter = newPositiveAttributeFilter(Md.Gender.Default, ["Female"]);
const testFilter2 = newPositiveAttributeFilter(Md.Gender.Default, ["Male"]);
const listOfFilters = [
testFilter2,
testFilter
];
<InsightView
insight={idRef(widget.widgetId)}
filters={listOfFilters}
/>
This dosent work for me either, what i get displayed on my insight is “NO DATA” there is data in our gooddata plattform with these filters. I cant seem to grasp how i am supposed to usethese filters with user interaction. I am not using the AttributeFilter component because our customer wants a custom css. Thank you in advance
j
Hello @Nicole Lopez! I can see why both of your examples (surveryId, and gender) are giving you NO DATA: There is AND relationship between each filter in the array. In other words, your filters translate ROUGHLY to SELECT * FROM table WHERE gender = male AND gender = female. (This is not exactly what is happening under the hood, but close enough to understand the problem.) In your case, you need to add multiple attribute values/elements, and not multiple attributes 🙂 Go ahead and try something like this:
Copy code
const testFilter = newPositiveAttributeFilter(Md.Gender.Default, ["Male", "Female"]);

<InsightView
     insight={idRef(widget.widgetId)}
     filters={[testFilter]}
/>
Let me know if it works! 😉
n
@Jiri Zajic Thank you so much for your answer 🥳 This worked for me 🌟
@Jiri Zajic My only other issue is that i need to fetch the ‘Male’ and the ‘Female’ value dynamically, so for example
Copy code
const testFilter = newPositiveAttributeFilter(Md.Gender.Default, ["Male", "Female"]);
This line works fine but where it says
["Male", "Female"]
Those values needs to be fetched dynamically, how do i access them?
j
Hello @Nicole Lopez, there are several ways how to load attribute elements dynamically/programatically. You could use the
<AttributeElements />
component like in this example, or you could simply GET the attribute's displayForm URL like this:
<https://your.gooddata.domain.com/gdc/md/><workspace-id>/obj/123/elements
. Let me know if you managed to get it to work!
n
Hello @Jiri Zajic This didint work for me 😕 I tried to do the following:
const test = newPositiveAttributeFilter(uriRef('/gdc/md/i57o7ciy7dqqu3ecynq8fjkz3bxd0bsb/obj/287/'), []);
console.log('TESTINGGG: ', test);
The picture is what i get in my log. My values are empty 😕 ¢
@Jiri Zajic I want to retrieve the values, i get the filters but i dont want to hard code in the values, the solution you provided works if i use the
<AttributeFilter />
Component but i am building a custom filter component and i need to be able to retrieve the values not the filters 😊
Hello @Jiri Zajic I have been able to retrieve the values now, thank you the only issue is that i cant apply the filters on a insight, so for example this:
const TEST = [newPositiveAttributeFilter(uriRef('/gdc/md/i57o7ciy7dqqu3ecynq8fjkz3bxd0bsb/obj/287/elements?id=5'), ["Less than 18 years old"])]
or this:
const TEST = [newPositiveAttributeFilter(uriRef('/gdc/md/i57o7ciy7dqqu3ecynq8fjkz3bxd0bsb/obj/287/elements?id=5'), [])]
or this:
const TEST = [newPositiveAttributeFilter(uriRef('<https://brandranalytics.on.gooddata.com/gdc/md/i57o7ciy7dqqu3ecynq8fjkz3bxd0bsb/obj/287/elements?id=5>'), [])]
None of the above work for me, my insights display “SORRY, WE CANT DISPLAY THIS INSIGHT”, thank you in advance 🌟
j
Hello Nicole! It seems you are mixing terms and metadata objects here 🙂 There are basically 3 objects you are working with: • the attribute ◦ e.g., Gender • the attribute labels ◦ one or many ◦ e.g. Long ("Male"), Short ("M") • the attribute elements ◦ Male, Female, Nonbinary (label "Long") ◦ M, F, N (label "Short") You want to go back to this previously working example:
Copy code
const testFilter = newPositiveAttributeFilter(Md.Gender.Default, ["Male", "Female"]);

<InsightView
     insight={idRef(widget.widgetId)}
     filters={[testFilter]}
/>
Function
newPositiveAttributeFilter()
accepts attribute_label as the first param, and an array of attribute_values as the second param. So the values you load dynamically belong inside those square brackets.
You can use either values:
Copy code
newPositiveAttributeFilter(Md.LocationCity, [
    'Dallas'
])
Or you can use URIs:
Copy code
newPositiveAttributeFilter(Md.LocationCity, {
    uris: [
        "/gdc/md/xms7ga4tf3g3nzucd8380o2bev8oeknp/obj/2208/elements?id=6340103"
    ]
})
They both work the same, but if you want to use URIs you always have to get them dynamically, otherwise your application won't work across multiple workspaces. (This should be obvious as the workspace ID is part of the URI.)
n
Hello @Jiri Zajic This worked for me thank you 🥳 My only issue is that when i apply filters not all widgets show. I apply the filters in a state and when the state changes the entire page reloads, this causes some widgets to not reload and to not show at all although they have values in the GoodData dashboard with the same filters. Down below is my entire code file that i have built. Every time i drill down or when i filter on my inisghts they dont show and i have to reload the page to get them to display data.
👀 1
import { useEffect, useState, FC } from "react";
import Page from "../Page";
import { InsightView } from "@gooddata/sdk-ui-ext";
import { useSelector } from "react-redux";
import { useQuery } from "graphql-hooks";
import { idRef, IPositiveAttributeFilter, newPositiveAttributeFilter } from "@gooddata/sdk-model";
import { HeaderPredicates } from "@gooddata/sdk-ui";
import { RootState } from "../../redux/store";
import { OVERVIEW_QUERY } from "../querys/OverviewQuery";
import { FilterListItems } from "./SurveyForm";
import { getCustomerCms } from "./query-validator";
import styles from "./Form.module.scss";
import { ICmsData } from "../../routes/Overview";
import * as Md from "../../md/full";
interface IHasNameUri {
name: string;
uri: string;
}
const OverviewForm: FC = () => {
const query = OVERVIEW_QUERY("allOverviews");
const filter = FilterListItems[0];
const idFilter = newPositiveAttributeFilter(filter.attribute, [filter.value]);
const userWorkspace = useSelector(
(state: RootState) => state.testData.currentUserSettings?.workspaces[0],
);
const filtersFromRedux = useSelector((state: RootState) => state.testData.insightFiltersToApply);
const [cmsData, setCmsData] = useState<ICmsData | undefined>(undefined);
const [filters, setFilters] = useState<IPositiveAttributeFilter>(idFilter);
const [isExpanded, setIsExpanded] = useState(false);
const [state, setState] = useState<IHasNameUri | null>(null);
const [awareness, setAwarenss] = useState<IHasNameUri | null>(null);
//const TESTFILTER = newPositiveAttributeFilter(Md.ValueText, { uris: ['/gdc/md/i57o7ciy7dqqu3ecynq8fjkz3bxd0bsb/obj/287/elements?id=7'] });
const topTenAwarenessDrillableItems = [HeaderPredicates.identifierMatch("label.vanswers.valuetext")];
const { loading, error, data } = useQuery(query, {
variables: {
limit: 100,
},
});
const getDrillFilters = (
state: IHasNameUri | null,
awareness: IHasNameUri | null,
): IPositiveAttributeFilter => {
let filter1 = newPositiveAttributeFilter(Md.ValueText, []);
if (state) {
filter1 = newPositiveAttributeFilter(Md.ValueText, { uris: [state.uri] });
};
if (awareness) {
filter1 =  newPositiveAttributeFilter(Md.ValueText, { uris: [awareness.uri] });
};
return filter1;
};
const tableFIlters = getDrillFilters(state, awareness);
const fetchCustomerCms = async () => {
const customerOverview = await getCustomerCms(data.allOverviews, userWorkspace || "No-data");
setCmsData(customerOverview);
};
const handleComparisonToggle = () => {
setIsExpanded(!isExpanded);
};
function onAwarenesslDrill(drillTarget: any) {
const { name, uri } =
drillTarget.drillContext.element === "bar"
? drillTarget.drillContext.intersection[1].header.attributeHeaderItem
: drillTarget.drillContext[0].intersection[1].header.attributeHeaderItem;
const newAwareness: IHasNameUri = {
name,
uri,
};
setAwarenss(newAwareness);
setState(null);
}
useEffect(() => {
if (data && userWorkspace) {
fetchCustomerCms();
}
}, [data, userWorkspace]);
useEffect(() => {
if (filtersFromRedux) {
const newFilter = newPositiveAttributeFilter(filtersFromRedux.atrb, {
uris: <http://filtersFromRedux.ar|filtersFromRedux.ar>,
});
setFilters(newFilter);
}
}, [filtersFromRedux]);
return (
<Page>
<p>{cmsData?.introText || "...Loading"}</p>
{cmsData ? (
<div className={styles.CardContainer}>
<div className={styles.WidgetCardRow}>
<div className={styles.WidgetContainer}>
<p>{cmsData.totalScore[0].heading}</p>
<InsightView
insight={idRef(cmsData.totalScore[0].widgetId)}
filters={[idFilter, filters, tableFIlters]}
/>
</div>
<div style={{ display: "flex", flexDirection: "column" }}>
<h1>{cmsData.totalScore[0].heading}</h1>
<p>{cmsData.totalScore[0].description}</p>
</div>
</div>
<div className={styles.WidgetCardColumn}>
<h1>{cmsData.totalScoreComparison[0].heading}</h1>
<p>{cmsData.totalScoreComparison[0].description}</p>
<div style={{ display: "flex", flexDirection: "row" }}>
{cmsData.totalScoreComparison[0].widgets.map((widget, index) => (
<div key={index} className={styles.WidgetContainer}>
{widget.heading === 'Brandr score' ?
<>
<p>{widget.heading}</p>
<InsightView
insight={widget.widgetId}
filters={[idFilter, filters, tableFIlters]}
/>
</> : <></>}
<p>{widget.heading}</p>
<InsightView
insight={widget.widgetId}
filters={[idFilter, filters]}
/>
</div>
))}
</div>
</div>
<div className={styles.WidgetCardRow}>
<div style={{ display: "flex", flexDirection: "column", maxWidth: '30%' }}>
<h1>{cmsData.dimensionWeight[0].heading}</h1>
<p>{cmsData.dimensionWeight[0].description}</p>
</div>
{cmsData.dimensionWeight[0].widgets.map((widget, index) => (
<div
key={index}
style={{ display: "flex", flexDirection: "column", alignItems: "center", minHeight: 300, width: '100%'}}
>
<p style={{ height: "auto" }}>{widget.heading}</p>
<div style={{ display: "flex", width: 600, height: 300 }}>
<InsightView
insight={widget.widgetId}
filters={[idFilter, filters, tableFIlters]}
/>
</div>
</div>
))}
</div>
<div className={styles.WidgetCardColumn}>
<h1>{cmsData.dimensionScore[0].heading}</h1>
<p>{cmsData.dimensionScore[0].description}</p>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
}}
>
{cmsData.dimensionScore[0].widgets.map((widget, index) => (
<div key={index}>
<div className={styles.WidgetContainer}>
<p>{widget.heading}</p>
<InsightView
insight={widget.widgetId}
filters={[idFilter, filters, tableFIlters]}
/>
</div>
<button className={styles.ComparisonBtn} onClick={handleComparisonToggle}>
View comparison
</button>
</div>
))}
</div>
{isExpanded && <div className={styles.ComparisonContainer}></div>}
</div>
{isExpanded && <div className={styles.ComparisonContainer}></div>}
<div className={styles.WidgetCardColumn}>
<h1>{cmsData.trustAndLoyalty[0].heading}</h1>
<p>{cmsData.trustAndLoyalty[0].description}</p>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: 'center',
gap: 16,
minHeight: 300,
minWidth: 300
}}
>
{cmsData.trustAndLoyalty[0].widgets.map((widget, index) => (
<>
<div
key={index}
className={styles.WidgetContainer}
style={{ height: 400, width: 400 }}
>
<InsightView
insight={widget.widgetId}
filters={[idFilter, filters, tableFIlters]}
/>
</div>
</>
))}
</div>
</div>
<div className={styles.WidgetCardColumn}>
<h1>{cmsData.topTenAwareness[0].heading}</h1>
<p>{cmsData.topTenAwareness[0].description}</p>
<div style={{ display: "flex", flexDirection: "row" }}>
{cmsData.topTenAwareness[0].widgets.map((widget, index) => (
<div
key={index}
style={{
display: "flex",
width: "100%",
height: 400,
flexDirection: "column",
}}
>
<h4>{widget.heading}</h4>
<InsightView
insight={widget.widgetId}
filters={[idFilter, filters]}
drillableItems={topTenAwarenessDrillableItems}
onDrill={onAwarenesslDrill}
/>
<InsightView
insight={widget.widgetId}
filters={[idFilter, filters, tableFIlters]}
drillableItems={topTenAwarenessDrillableItems}
onDrill={onAwarenesslDrill}
/>
</div>
))}
</div>
</div>
</div>
) : error ? (
<p>Error in loading data</p>
) : loading ? (
<p>...Loading</p>
) : error ? (
<p>Oopsie an error occured</p>
) : (
<p>Oopsie</p>
)}
<div className={styles.HomeScreen}>
{/* <h1>Insight - with drilldown</h1> */}
{/* <div style={{ height: 500 }}>
<InsightView
insight={Md.Insights.QuestionList}
drillableItems={[HeaderPredicates.identifierMatch("aag4sK7sLQkT")]}
onDrill={onDrillHandler}
/>
</div> */}
{/* <div style={{ height: 500 }}>
<InsightView
insight={Md.Insights.CustomWidget}
drillableItems={[HeaderPredicates.identifierMatch("label.scoreformulation.score_id")]}
onDrill={onDrillHandler}
/>
</div> */}
</div>
</Page>
);
};
export default OverviewForm;
j
Hello Nicole! This is most likely a design flaw in your React code that has nothing to do with GoodData. This code snippet below caught my attention:
Copy code
<div style={{ display: "flex", flexDirection: "row" }}>
    {cmsData.topTenAwareness[0].widgets.map((widget, index) => (
        <div
            key={index}
            style={{
                display: "flex",
                width: "100%",
                height: 400,
                flexDirection: "column",
            }}
        >
            <h4>{widget.heading}</h4>
            <InsightView
                insight={widget.widgetId}
                filters={[idFilter, filters]}
                drillableItems={topTenAwarenessDrillableItems}
                onDrill={onAwarenesslDrill}
            />
            <InsightView
                insight={widget.widgetId}
                filters={[idFilter, filters, tableFIlters]}
                drillableItems={topTenAwarenessDrillableItems}
                onDrill={onAwarenesslDrill}
            />
        </div>
    ))}
</div>
Firstly, for each widget in
cmsData.topTenAwareness[0].widgets
you are rendering a heading and two insights — is that intended? If yes, then try wrapping each
<InsightView />
in a
<div></div>
with specified non-zero height. Like this:
Copy code
<div style={{ display: "flex", flexDirection: "row" }}>
    {cmsData.topTenAwareness[0].widgets.map((widget, index) => (
        <div
            key={index}
            style={{
                display: "flex",
                width: "100%",
                // height: 400,
                flexDirection: "column",
            }}
        >
            <h4>{widget.heading}</h4>
            <div style={{ height: 200}}>
                <InsightView
                    insight={widget.widgetId}
                    filters={[idFilter, filters]}
                    drillableItems={topTenAwarenessDrillableItems}
                    onDrill={onAwarenesslDrill}
                />
            </div>
            <div style={{ height: 200}}>
                <InsightView
                    insight={widget.widgetId}
                    filters={[idFilter, filters, tableFIlters]}
                    drillableItems={topTenAwarenessDrillableItems}
                    onDrill={onAwarenesslDrill}
                />
            </div>
        </div>
    ))}
</div>
Remember, each GoodData.UI chart component must be wrapped in a non-zero height container. I see that at the bottom of your file you did this correctly:
Copy code
<div className={styles.HomeScreen}>
    {/* <h1>Insight - with drilldown</h1> */}
    {/* <div style={{ height: 500 }}>
        <InsightView
            insight={Md.Insights.QuestionList}
            drillableItems={[HeaderPredicates.identifierMatch("aag4sK7sLQkT")]}
            onDrill={onDrillHandler}
        />
    </div> */}
    {/* <div style={{ height: 500 }}>
        <InsightView
            insight={Md.Insights.CustomWidget}
            drillableItems={[HeaderPredicates.identifierMatch("label.scoreformulation.score_id")]}
            onDrill={onDrillHandler}
        />
    </div> */}
</div>
It is possible that your page will still re-render when you apply filters. You will then need to carefully revise all your state variables and make sure React does not perform any unnecessary re-renders. But that would be a React matter, not GoodData's.
Let me know if wrapping `<InsightView />`s in non-zero height divs helped!