New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comparison Filter GUI #64
Conversation
This adds several components, which can be used to aggregate to a Comparison Filter UI. For demonstration purposes a basic Demo UI is also implemented. (Addresses #58)
This adds several components, which can be used to aggregate to a Comparison Filter UI. For demonstration purposes a basic Demo UI is also implemented. (Addresses #58)
Adds an UploadButton component which let the user select a geodata file as base for the filter UI.
… into 58-filter-gui
This enables the ComparisonFilterUi to hold a GeoStyler ComparisonFilter object derived from its GUI elements.
This adds a text area to output the serialized GeoStyler filter in the FilterDemoUi.
Disable button to add more ComparisonFilterUis since we cannot handle multiple filters at the moment.
*/ | ||
class AttributeCombo extends React.Component<any, any> { | ||
|
||
// PROPS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
React usually defines its props with PropTypes.
As we make use of TypeScript another approach with interfaces should be the way to go.
The props should not be declared as member variables. The declared member variables will not be associated with the props. So you will have this.internalDataDef
and this.props.internalDataDef
and so on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I have this on my list. This is the next thing I will tackle.
|
||
</div> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might want to profit from object destructuring / spread operator for the props. You can then use "passThorughProps".
Compare
@@ -0,0 +1,4 @@ | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use less instead of css
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created a separate issue for this (#65), so we can tackle this later (since this seems a bit more complicated that one might think at first sight).
* - A combo to select the operator | ||
* - An input field for the value | ||
*/ | ||
class ComparisonFilterUi extends React.Component<any, any> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove "Ui" from the classname
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK...
*/ | ||
class ComparisonFilterUi extends React.Component<any, any> { | ||
|
||
// PROPS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment above regarding props.
* | ||
* Changes the input field for the filter value and stores the appropriate attribute name as member. | ||
*/ | ||
onAttributeChange = (newAttrName: string) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please transform methods to following syntax and use .bind(this)
at the call if needed:
onAttributeChange(newAttrName: string) {
Otherwise styleguidist doesn't recognize this methods as methods but as properties.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will check that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the moment binds are forbidden in JSX attributes due to their rendering performance impact (tslint).
So what do you prefer? Making styleguidist happy or relying on the tslint recommendation not to use bind?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't aware that TypeScript recommends this way of declaring class methods. So
we should stick to the TypeScript recommendation for know.
@@ -0,0 +1,77 @@ | |||
import * as React from 'react'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if it makes a difference but i'd prefer import React from 'react';
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does not work for me. The module doesn't seem to have a standard export. And using import { React } from 'react';
also does not work because there is no exported member React
in the module.
I also just discovered import * as React from 'react';
in all documentations / tutorials I read so far.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should work if you leave the curly-brackets. Never mind. It's just Schmuck at the Nachthemd...
/** Handler function bound to the 'onChange' of the underlying Select */ | ||
onAttributeChange: Function; | ||
|
||
constructor(props: any) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you don't perform any actrions with props or the state you can omit the constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree...
Looks very promising. 😍 I added some notes to structural things. |
Thanks for your review @KaiVolland! Good points, I agree with most of them. I will go on and address your remarks / hints. |
This reworks the filter UI components so the react properties are modelled corretly for TypeScript. Concept taken from: https://charleslbryant.gitbooks.io/hello-react-and-typescript/content/TypeScriptAndReact.html
Detects the min and max value from the attribute schema for numeric attributes.
Adds a BoolFilterField component offering a checkbox to set the filter value for attributes of type boolean .
I addressed or at least commented your remarks, @KaiVolland. I think this is now ready for another (and hopefully final) review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice. Feel free to merge.
Could you explain in one or two sentences (or maybe a source) why you decide to split the props interface in "default props" and "non default props"?
@@ -0,0 +1,77 @@ | |||
import * as React from 'react'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should work if you leave the curly-brackets. Never mind. It's just Schmuck at the Nachthemd...
operator: ComparisonOperator; | ||
|
||
/** The currently entered filter value */ | ||
value: string | number | boolean | null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the 4 props above should go to the state, too. But we can adjust this later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so. Since setting the state is an asynchronous action (by triggering the rendering not immediately) this can lead to divergence in the values for attribute
, operator
and value
, when serializing them. Holding them as "normal" members ensures the correct values at every time.
For my understanding the state should be used for information, which is directly connected to a component.
Thanks again for your review @KaiVolland!
The "default props" are these props, which are optional and have a default value. The other have to be passed in by the father component. By modeling the "default props" in an own interface we can define a static
I found several sources describing this, e.g.: |
This introduces a GUI visualizing a ComparisonFilter. The GUI consists of a bunch of react components.
For demonstration purpose a little demo app has also been developed, where the following can be done:
UI for boolean attributes: