1- import React , { useState , useEffect , useRef } from 'react' ;
1+ import React from 'react' ;
22import ReactDOM from 'react-dom/client' ;
33import './index.css' ;
44
@@ -39,39 +39,27 @@ interface Entity {
3939 fields : Field [ ] ;
4040}
4141
42- const QueryBuilderOverview : React . FC = ( ) => {
43- const queryBuilderRef = useRef < IgcQueryBuilderComponent > ( null ) ;
44- const gridRef = useRef < IgcGridComponent > ( null ) ;
45- const [ expressionTree , setExpressionTree ] = useState < IgcExpressionTree | null > ( null ) ;
46-
47- // Define field structures
48- const customersFields : Field [ ] = [
49- { field : 'customerId' , dataType : 'string' } ,
50- { field : 'companyName' , dataType : 'string' } ,
51- { field : 'contactName' , dataType : 'string' } ,
52- { field : 'contactTitle' , dataType : 'string' }
53- ] ;
54-
55- const ordersFields : Field [ ] = [
56- { field : 'orderId' , dataType : 'number' } ,
57- { field : 'customerId' , dataType : 'string' } ,
58- { field : 'employeeId' , dataType : 'number' } ,
59- { field : 'shipperId' , dataType : 'number' } ,
60- { field : 'orderDate' , dataType : 'date' } ,
61- { field : 'requiredDate' , dataType : 'date' } ,
62- { field : 'shipVia' , dataType : 'string' } ,
63- { field : 'freight' , dataType : 'number' } ,
64- { field : 'shipName' , dataType : 'string' } ,
65- { field : 'completed' , dataType : 'boolean' }
66- ] ;
67-
68- const entities : Entity [ ] = [
69- { name : 'Customers' , fields : customersFields } ,
70- { name : 'Orders' , fields : ordersFields }
71- ] ;
72-
73- // Initialize expression tree
74- useEffect ( ( ) => {
42+ interface SampleState {
43+ expressionTree : IgcExpressionTree | null ;
44+ }
45+
46+ export default class Sample extends React . Component < any , SampleState > {
47+ private queryBuilderRef : React . RefObject < IgcQueryBuilderComponent > ;
48+ private gridRef : React . RefObject < IgcGridComponent > ;
49+
50+ constructor ( props : any ) {
51+ super ( props ) ;
52+
53+ this . queryBuilderRef = React . createRef ( ) ;
54+ this . gridRef = React . createRef ( ) ;
55+
56+ this . state = {
57+ expressionTree : null
58+ } ;
59+ }
60+
61+ componentDidMount ( ) {
62+ // Initialize expression tree
7563 const tree = new IgcFilteringExpressionsTree ( ) ;
7664 tree . operator = FilteringLogic . And ;
7765 tree . entity = 'Orders' ;
@@ -88,46 +76,89 @@ const QueryBuilderOverview: React.FC = () => {
8876 'completed'
8977 ] ;
9078
91- setExpressionTree ( tree ) ;
92- } , [ ] ) ;
79+ this . setState ( { expressionTree : tree } ) ;
9380
94- // Set up query builder
95- useEffect ( ( ) => {
96- if ( ! queryBuilderRef . current || ! expressionTree ) return undefined ;
81+ // Set up query builder
82+ if ( this . queryBuilderRef . current && tree ) {
83+ const queryBuilder = this . queryBuilderRef . current ;
84+ queryBuilder . entities = this . entities as any ;
85+ queryBuilder . expressionTree = tree ;
9786
98- const queryBuilder = queryBuilderRef . current ;
99- queryBuilder . entities = entities as any ;
100- queryBuilder . expressionTree = expressionTree ;
87+ queryBuilder . addEventListener ( 'expressionTreeChange' , this . handleExpressionTreeChange ) ;
88+ }
10189
102- const handleExpressionTreeChange = ( event : CustomEvent < IgcExpressionTree > ) => {
103- setExpressionTree ( event . detail ) ;
104- } ;
90+ // Set up grid
91+ if ( this . gridRef . current ) {
92+ const grid = this . gridRef . current ;
93+ grid . height = '420px' ;
94+ grid . autoGenerate = true ;
95+ }
96+ }
10597
106- queryBuilder . addEventListener ( 'expressionTreeChange' , handleExpressionTreeChange as EventListener ) ;
98+ componentDidUpdate ( prevProps : any , prevState : any ) {
99+ // Fetch data when expression tree changes
100+ if ( prevState . expressionTree !== this . state . expressionTree && this . state . expressionTree ) {
101+ this . fetchData ( ) ;
102+ }
107103
108- return ( ) => {
109- queryBuilder . removeEventListener ( 'expressionTreeChange' , handleExpressionTreeChange as EventListener ) ;
110- } ;
111- } , [ expressionTree ?. entity ] ) ; // Only re-run if entity changes
112-
113- // Set up grid
114- useEffect ( ( ) => {
115- if ( ! gridRef . current ) return undefined ;
116-
117- const grid = gridRef . current ;
118- grid . height = '420px' ;
119- grid . autoGenerate = true ;
120- } , [ ] ) ;
121-
122- // Calculate which columns should be visible based on returnFields
123- const calculateColumnsInView = ( ) => {
124- if ( ! gridRef . current || ! expressionTree ) return ;
125-
126- const grid = gridRef . current ;
104+ // Update query builder if expression tree changed
105+ if ( this . queryBuilderRef . current && this . state . expressionTree &&
106+ prevState . expressionTree !== this . state . expressionTree ) {
107+ const queryBuilder = this . queryBuilderRef . current ;
108+ queryBuilder . expressionTree = this . state . expressionTree ;
109+ }
110+ }
111+
112+ componentWillUnmount ( ) {
113+ if ( this . queryBuilderRef . current ) {
114+ this . queryBuilderRef . current . removeEventListener ( 'expressionTreeChange' , this . handleExpressionTreeChange ) ;
115+ }
116+ }
117+
118+ private handleExpressionTreeChange = ( event : CustomEvent < IgcExpressionTree > ) => {
119+ this . setState ( { expressionTree : event . detail } ) ;
120+ } ;
121+
122+ private get customersFields ( ) : Field [ ] {
123+ return [
124+ { field : 'customerId' , dataType : 'string' } ,
125+ { field : 'companyName' , dataType : 'string' } ,
126+ { field : 'contactName' , dataType : 'string' } ,
127+ { field : 'contactTitle' , dataType : 'string' }
128+ ] ;
129+ }
130+
131+ private get ordersFields ( ) : Field [ ] {
132+ return [
133+ { field : 'orderId' , dataType : 'number' } ,
134+ { field : 'customerId' , dataType : 'string' } ,
135+ { field : 'employeeId' , dataType : 'number' } ,
136+ { field : 'shipperId' , dataType : 'number' } ,
137+ { field : 'orderDate' , dataType : 'date' } ,
138+ { field : 'requiredDate' , dataType : 'date' } ,
139+ { field : 'shipVia' , dataType : 'string' } ,
140+ { field : 'freight' , dataType : 'number' } ,
141+ { field : 'shipName' , dataType : 'string' } ,
142+ { field : 'completed' , dataType : 'boolean' }
143+ ] ;
144+ }
145+
146+ private get entities ( ) : Entity [ ] {
147+ return [
148+ { name : 'Customers' , fields : this . customersFields } ,
149+ { name : 'Orders' , fields : this . ordersFields }
150+ ] ;
151+ }
152+
153+ private calculateColumnsInView = ( ) => {
154+ if ( ! this . gridRef . current || ! this . state . expressionTree ) return ;
155+
156+ const grid = this . gridRef . current ;
157+ const expressionTree = this . state . expressionTree ;
127158 const returnFields = expressionTree . returnFields ?? [ ] ;
128159
129160 if ( returnFields . length === 0 || returnFields [ 0 ] === '*' ) {
130- const selectedEntity = entities . find ( e => e . name === expressionTree . entity ) ;
161+ const selectedEntity = this . entities . find ( e => e . name === expressionTree . entity ) ;
131162 const selectedEntityFields = ( selectedEntity ?. fields ?? [ ] ) . map ( f => f . field ) ;
132163
133164 grid . columns . forEach ( column => {
@@ -140,58 +171,55 @@ const QueryBuilderOverview: React.FC = () => {
140171 }
141172 } ;
142173
143- // Fetch data when expression tree changes
144- useEffect ( ( ) => {
145- if ( ! expressionTree || ! gridRef . current ) return ;
146-
147- const fetchData = async ( ) => {
148- const grid = gridRef . current ;
149- if ( ! grid ) return ;
150-
151- grid . isLoading = true ;
152-
153- try {
154- const response = await fetch ( `${ API_ENDPOINT } /QueryBuilder/ExecuteQuery` , {
155- method : 'POST' ,
156- headers : { 'Content-Type' : 'application/json' } ,
157- body : JSON . stringify ( expressionTree )
158- } ) ;
159-
160- if ( ! response . ok ) {
161- throw new Error ( `ExecuteQuery failed: ${ response . status } ${ response . statusText } ` ) ;
162- }
163-
164- const json = await response . json ( ) ;
165- const data = ( Object . values ( json ) [ 0 ] as any [ ] ) ?? [ ] ;
166- grid . data = data ;
167-
168- // Calculate column visibility after data loads
169- await new Promise ( resolve => requestAnimationFrame ( ( ) => resolve ( null ) ) ) ;
170- calculateColumnsInView ( ) ;
171- } catch ( err ) {
172- console . error ( err ) ;
173- grid . data = [ ] ;
174- } finally {
175- grid . isLoading = false ;
174+ private async fetchData ( ) {
175+ const grid = this . gridRef . current ;
176+ const expressionTree = this . state . expressionTree ;
177+
178+ if ( ! grid || ! expressionTree ) return ;
179+
180+ grid . isLoading = true ;
181+
182+ try {
183+ const response = await fetch ( `${ API_ENDPOINT } /QueryBuilder/ExecuteQuery` , {
184+ method : 'POST' ,
185+ headers : { 'Content-Type' : 'application/json' } ,
186+ body : JSON . stringify ( expressionTree )
187+ } ) ;
188+
189+ if ( ! response . ok ) {
190+ throw new Error ( `ExecuteQuery failed: ${ response . status } ${ response . statusText } ` ) ;
176191 }
177- } ;
178192
179- fetchData ( ) ;
180- } , [ expressionTree ] ) ;
193+ const json = await response . json ( ) ;
194+ const data = ( Object . values ( json ) [ 0 ] as any [ ] ) ?? [ ] ;
195+ grid . data = data ;
196+
197+ // Calculate column visibility after data loads
198+ await new Promise ( resolve => requestAnimationFrame ( ( ) => resolve ( null ) ) ) ;
199+ this . calculateColumnsInView ( ) ;
200+ } catch ( err ) {
201+ console . error ( err ) ;
202+ grid . data = [ ] ;
203+ } finally {
204+ grid . isLoading = false ;
205+ }
206+ }
181207
182- return (
183- < div className = "container sample ig-typography" >
184- < div className = "wrapper" >
185- < igc-query-builder ref = { queryBuilderRef } id = "queryBuilder" > </ igc-query-builder >
186-
187- < div className = "output-area" >
188- < igc-grid ref = { gridRef } id = "grid" > </ igc-grid >
208+ public render ( ) : JSX . Element {
209+ return (
210+ < div className = "container sample ig-typography" >
211+ < div className = "wrapper" >
212+ < igc-query-builder ref = { this . queryBuilderRef } id = "queryBuilder" > </ igc-query-builder >
213+
214+ < div className = "output-area" >
215+ < igc-grid ref = { this . gridRef } id = "grid" > </ igc-grid >
216+ </ div >
189217 </ div >
190218 </ div >
191- </ div >
192- ) ;
193- } ;
219+ ) ;
220+ }
221+ }
194222
195- // Rendering component in the React DOM
196- const root = ReactDOM . createRoot ( document . getElementById ( 'root' ) ! ) ;
197- root . render ( < QueryBuilderOverview /> ) ;
223+ // rendering above component in the React DOM
224+ const root = ReactDOM . createRoot ( document . getElementById ( 'root' ) ) ;
225+ root . render ( < Sample /> ) ;
0 commit comments