ReactiveSearch only autocomplete - reactjs

I want to use ReactiveSearch library only for autocomplete with submit.
const Search = () => (
<div className="search-field">
<ReactiveBase
app="good-books-ds"
credentials="nY6NNTZZ6:27b76b9f-18ea-456c-bc5e-3a5263ebc63d"
>
<div className="row">
<div className="col">
<DataSearch
dataField={['original_title', 'original_title.search']}
categoryField="authors.raw"
componentId="BookSensor"
/>
</div>
</div>
</ReactiveBase>
</div>
)
export default Search
I tried making the input as above with <DataSearch ... /> and it works, but it doesn't have submit option. I tried to wrap it with form, but after enter or select value it doesn't fire.
Any suggestions?

https://opensource.appbase.io/reactive-manual/search-components/datasearch.html
you need to read the doc carefully there is onValueChange handler so when you type in something you can set the state first set the initial state state = {searchText: ""} at the top after that in Data search prop you can do the following
<DataSearch onValueChange = {(e) => this.setState({searchText: value})} />
now make you own button and submit the value in the state for example this.state.searchText

ReactiveSearch now supports an onValueSelected prop which is perfect for usecases where you are only interested in utilizing the selected value (either selecting a suggestion or hitting Enter key). Docs and example usage:
<DataSearch
...
onValueSelected={(value) => console.log('The selected value is', value)}
/>

Related

How to get the ref.current dom element when using react-select and react refs?

I have a group of react selects using the react-select package – https://react-select.com/home.
I have a component that wraps three react-selects – something basically like this:
import Select from "react-select"
function SelectGroup(){
const ref1 = useRef(null);
const ref2 = useRef(null);
const ref3 = useRef(null);
return (
<div>
<Select ref={ref1} />
<Select ref={ref2} />
<Select ref={ref3} />
</div>
)
}
I need to perform some checks to see what's in focus. The reason I am doing this is because the group of selects is a single component that needs to be able to allow the user to navigate in multiple ways through the keyboard. Spacebar, and enter keys should allow the user to shift the focus to the next select element. Arrow keys should allow the user to go to the next or previous select. So, focus needs to be managed somehow, and this means knowing what's currently in focus.
Normally, I would do that like this:
function isActiveElement(ref){
return ref?.current === document.activeElement
}
However, for ref.current react-select returns an object called StateManager – https://react-select.com/props#statemanager-props
So, ref.current === document.activeElement always returns false.
How, can I check to see which react-select is in focus? I was unable to find anything about this in the react-select docs. Maybe, I'm missing it? I have solved this problem others ways, but I was curious if there is a way to do it this "simpler way" I describe above, which may be the more common approach.
You can listen to the focus and the blur event to keep track of the currently focused Select:
export default function App() {
const [focus, setFocus] = useState(-1);
const onBlur = () => setFocus(-1);
return (
<div>
<div>Current focus: {focus}</div>
<Select
onFocus={() => setFocus(0)}
onBlur={onBlur}
options={colourOptions}
/>
<Select
onFocus={() => setFocus(1)}
onBlur={onBlur}
options={colourOptions}
/>
<Select
onFocus={() => setFocus(2)}
onBlur={onBlur}
options={colourOptions}
/>
</div>
);
};
Live Demo

Reactjs - toggle switches not working when using local array

I have an update for anyone that is reading this....
I think I've found the issue - when you set a toggle switch to checked it's also set to READONLY. So I can't toggle the toggle switch now.
I have a toggle component of type checkbox in React.
products is a locally set array for testing purposes as this.props.products is empty for now.
Through testing, I've noticed that if I use:
selected={(products.indexOf(p) > -1)} the toggles stop working. They display correctly but I'm not able to toggle them. They do not appear disabled or are set to disabled in HTML element.
products=['ProdA', 'ProdB', 'ProdC];
customerProducts.forEach(p => {
content(): string[] {
const toggles = [];
if(isEnabled){
toggles.push(
<ToggleComponent
value={p}
selected={(products.indexOf(p) > -1)}
onChange={this.props.onChange}
disabled={false}
/>
);
}
render() {
{this.content()}
}
//TOGGLE COMPONENT
render() {
const {id, title, disabled, name, value, selected} = this.props;
return (
<div>
<fieldset>
<div className="form-structure">
<label className={!this.props.disabled ? 'checkbox-switch-label' : 'checkbox-switch-label checkbox-switch-label-disabled'}>
<input id={id} type="checkbox" checked={selected} className="checkbox-switch" role="Switch" disabled={disabled} name={name} value={value} onChange={this.validate} />
<span/>{title}
</label>
</div>
</fieldset>
</div>
)}
I can see there is an invalid Event Listener in my dev Tools: dispatchDiscreteEvent
The toggles are appearing, are not visibly disabled, (there is no disabled attribute in the html element), but clicking them does not toggle them on/off.
Am I supposed to be setting 'disabled' against a state value instead?
I already have an onChange function elsewhere for getting the values.

How to use hooks in multiple rendered inputs?

I'm creating the form to my app. Problem i'm facing is whenever i click add and generate another row of inputs i got an "Rendered more hooks than during the previous render" error.
I have a "benefit" input with checkbox. When user checks it i want to render another 2 inputs (in the same row) with KPI. Hook works perfectly fine if there is only one row. When i add another row the error occurs.
const renderBenefitFields = (benefit, index, fields) => {
const [hidden, setHidden] = useState(false);
return (
<div key={index}>
<InputGroup>
<Input
name={`${benefit}.projectBenefitData`}
type="text"
component={renderField}
label="Benefit of the project"
/>
<InputGroupAddon addonType="append">
<InputGroupText>
<Input
addon
type="checkbox"
aria-label="Mesurable benefit?"
onChange={() => setHidden(!hidden)}
/>
</InputGroupText>
<InputGroupText>Benefit mesurable </InputGroupText>
</InputGroupAddon>
<Trash
className="align-middle"
size={25}
onClick={() => fields.remove(index)}
/>
Show KPI inputs? {hidden === false ? "false" : "true"}
</InputGroup>
</div>
);
};
const renderBenefits = ({ fields }) => (
<div>
{fields.map(renderBenefitFields)}
<PlusCircle
className="align-baseline"
size={24}
onClick={() => fields.push({})}
/>
</div>
);
Perfect solution would be: when user checks the box react will show another two inputs.
As Ross Hunter mentioned,
1. You should capitalize your component, i.e. RenderBenefitFields
2. No mutation on state/props, in onClick={() => fields.push({})}
In addition, you should call your RenderBenefitFields in renderBenefits as following:
{fields.map((props, index) => <RenderBenefitFields key={index} {...props} />)}
P.S. You can use a unique key instead of index, depending on your situation.
The name of user-defined components needs to be capitalized.
The onClick callback in PlusCircle looks like it's directly mutating state. That's a big problem for React, and almost certainly the root of your issue. I can explain further if you need sometime I'm not on mobile 😊

React - Setting state to target with onClick method

I am trying to recreate a tabs component in React that someone gave me and I am getting stuck while getting the onClick method to identify the target.
These are the snippets of my code that I believe are relevant to the problem.
If I hardcode setState within the method, it sets it appropriately, so the onClick method is running, I am just unsure of how to set the tab I am clicking to be the thing I set the state to.
On my App page:
changeSelected = (event) => {
// event.preventDefault();
this.setState({
selected: event.target.value
})
console.log(event.target.value)
};
<Tabs tabs={this.state.tabs} selectedTab={this.state.selected}
selectTabHandler={() => this.changeSelected}/>
On my Tabs page:
{props.tabs.map(tab => {
return <Tab selectTabHandler={() => props.selectTabHandler()} selectedTab={props.selectedTab} tab={tab} />
})}
On my Tab page:
return (
<div
className={'tab active-tab'}
onClick={props.selectTabHandler(props.tab)}
>
{props.tab}
</div>
When I console.log(props.tab) or console.log(event.target.value) I am receiving "undefined"
There are a few issues causing this to happen. The first issue is that you wouldn't use event.target.value in the Content component because you aren't reacting to DOM click event directly from an onClick handler as you are in Tab, instead you are handling an event from child component. Also keep in mind that event.target.value would only be applicable to input or similar HTML elements that have a value property. An element such as <div> or a <span> would not have a value property.
The next issues are that you aren't passing the tab value from Tabs to Content and then from within Content to it's changeSelected() handler for selectTabHandler events.
In addition the onClick syntax in Tab, onClick={props.selectTabHandler(props.tab)} is not valid, you will not be able to execute the handler coming from props and pass the props.tab value. You could instead try something like onClick={() => props.selectTabHandler(props.tab)}.
Content - need to pass tab value coming from child to changeSelected():
render() {
return (
<div className="content-container">
<Tabs
tabs={this.state.tabs}
selectedTab={this.state.selected}
selectTabHandler={tab => this.changeSelected(tab)}
/>
<Cards cards={this.filterCards()} />
</div>
);
}
Tabs - need to pass tab coming from child to selectTabHandler():
const Tabs = props => {
return (
<div className="tabs">
<div className="topics">
<span className="title">TRENDING TOPICS:</span>
{props.tabs.map(tab => {
return (
<Tab
selectTabHandler={tab => props.selectTabHandler(tab)}
selectedTab={props.selectedTab}
tab={tab}
/>
);
})}
</div>
</div>
);
};
export default Tabs;
Also don't forget the unique key property when rendering an array/list of items:
<Tab
key={tab}
selectTabHandler={tab => props.selectTabHandler(tab)}
selectedTab={props.selectedTab}
tab={tab}
/>
Here is a forked CodeSandbox demonstrating the functionality.

What is the difference betwen value and defaultValue in react.js [duplicate]

I'm trying to create a simple form with react, but facing difficulty having the data properly bind to the defaultValue of the form.
The behavior I'm looking for is this:
When I open my page, the Text input field should be filled in with the text of my AwayMessage in my database. That is "Sample Text"
Ideally I want to have a placeholder in the Text input field if the AwayMessage in my database has no text.
However, right now, I'm finding that the Text input field is blank every time I refresh the page. (Though what I type into the input does save properly and persist.) I think this is because the input text field's html loads when the AwayMessage is an empty object, but doesn't refresh when the awayMessage loads. Also, I'm unable to specify a default value for the field.
I removed some of the code for clarity (i.e. onToggleChange)
window.Pages ||= {}
Pages.AwayMessages = React.createClass
getInitialState: ->
App.API.fetchAwayMessage (data) =>
#setState awayMessage:data.away_message
{awayMessage: {}}
onTextChange: (event) ->
console.log "VALUE", event.target.value
onSubmit: (e) ->
window.a = #
e.preventDefault()
awayMessage = {}
awayMessage["master_toggle"]=#refs["master_toggle"].getDOMNode().checked
console.log "value of text", #refs["text"].getDOMNode().value
awayMessage["text"]=#refs["text"].getDOMNode().value
#awayMessage(awayMessage)
awayMessage: (awayMessage)->
console.log "I'm saving", awayMessage
App.API.saveAwayMessage awayMessage, (data) =>
if data.status == 'ok'
App.modal.closeModal()
notificationActions.notify("Away Message saved.")
#setState awayMessage:awayMessage
render: ->
console.log "AWAY_MESSAGE", this.state.awayMessage
awayMessageText = if this.state.awayMessage then this.state.awayMessage.text else "Placeholder Text"
`<div className="away-messages">
<div className="header">
<h4>Away Messages</h4>
</div>
<div className="content">
<div className="input-group">
<label for="master_toggle">On?</label>
<input ref="master_toggle" type="checkbox" onChange={this.onToggleChange} defaultChecked={this.state.awayMessage.master_toggle} />
</div>
<div className="input-group">
<label for="text">Text</label>
<input ref="text" onChange={this.onTextChange} defaultValue={awayMessageText} />
</div>
</div>
<div className="footer">
<button className="button2" onClick={this.close}>Close</button>
<button className="button1" onClick={this.onSubmit}>Save</button>
</div>
</div>
my console.log for AwayMessage shows the following:
AWAY_MESSAGE Object {}
AWAY_MESSAGE Object {id: 1, company_id: 1, text: "Sample Text", master_toggle: false}
Another way of fixing this is by changing the key of the input.
<input ref="text" key={this.state.awayMessage ? 'notLoadedYet' : 'loaded'} onChange={this.onTextChange} defaultValue={awayMessageText} />
Update:
Since this get upvotes, I will have to say that you should properly have a disabled or readonly prop while the content is loading, so you don't decrease the ux experience.
And yea, it is most likely a hack, but it gets the job done.. ;-)
defaultValue is only for the initial load
If you want to initialize the input then you should use defaultValue, but if you want to use state to change the value then you need to use value. Personally I like to just use defaultValue if I'm just initializing it and then just use refs to get the value when I submit. There's more info on refs and inputs on the react docs, https://facebook.github.io/react/docs/forms.html and https://facebook.github.io/react/docs/working-with-the-browser.html.
Here's how I would rewrite your input:
awayMessageText = if this.state.awayMessage then this.state.awayMessage.text else ''
<input ref="text" onChange={this.onTextChange} placeholder="Placeholder Text" value={#state.awayMessageText} />
Also you don't want to pass placeholder text like you did because that will actually set the value to 'placeholder text'. You do still need to pass a blank value into the input because undefined and nil turns value into defaultValue essentially. https://facebook.github.io/react/tips/controlled-input-null-value.html.
getInitialState can't make api calls
You need to make api calls after getInitialState is run. For your case I would do it in componentDidMount. Follow this example, https://facebook.github.io/react/tips/initial-ajax.html.
I'd also recommend reading up on the component lifecycle with react. https://facebook.github.io/react/docs/component-specs.html.
Rewrite with modifications and loading state
Personally I don't like to do the whole if else then logic in the render and prefer to use 'loading' in my state and render a font awesome spinner before the form loads, http://fortawesome.github.io/Font-Awesome/examples/. Here's a rewrite to show you what I mean. If I messed up the ticks for cjsx, it's because I normally just use coffeescript like this, .
window.Pages ||= {}
Pages.AwayMessages = React.createClass
getInitialState: ->
{ loading: true, awayMessage: {} }
componentDidMount: ->
App.API.fetchAwayMessage (data) =>
#setState awayMessage:data.away_message, loading: false
onToggleCheckbox: (event)->
#state.awayMessage.master_toggle = event.target.checked
#setState(awayMessage: #state.awayMessage)
onTextChange: (event) ->
#state.awayMessage.text = event.target.value
#setState(awayMessage: #state.awayMessage)
onSubmit: (e) ->
# Not sure what this is for. I'd be careful using globals like this
window.a = #
#submitAwayMessage(#state.awayMessage)
submitAwayMessage: (awayMessage)->
console.log "I'm saving", awayMessage
App.API.saveAwayMessage awayMessage, (data) =>
if data.status == 'ok'
App.modal.closeModal()
notificationActions.notify("Away Message saved.")
#setState awayMessage:awayMessage
render: ->
if this.state.loading
`<i className="fa fa-spinner fa-spin"></i>`
else
`<div className="away-messages">
<div className="header">
<h4>Away Messages</h4>
</div>
<div className="content">
<div className="input-group">
<label for="master_toggle">On?</label>
<input type="checkbox" onChange={this.onToggleCheckbox} checked={this.state.awayMessage.master_toggle} />
</div>
<div className="input-group">
<label for="text">Text</label>
<input ref="text" onChange={this.onTextChange} value={this.state.awayMessage.text} />
</div>
</div>
<div className="footer">
<button className="button2" onClick={this.close}>Close</button>
<button className="button1" onClick={this.onSubmit}>Save</button>
</div>
</div>
That should about cover it. Now that is one way to go about forms which uses state and value. You can also just use defaultValue instead of value and then use refs to get the values when you submit. If you go that route I would recommend you have an outer shell component (usually referred to as high order components) to fetch the data and then pass it to the form as props.
Overall I'd recommend reading the react docs all the way through and do some tutorials. There's lots of blogs out there and http://www.egghead.io had some good tutorials. I have some stuff on my site as well, http://www.openmindedinnovations.com.
it's extremely simple, make defaultValue and key the same:
<input defaultValue={myVal} key={myVal}/>
This is one of the recommended approaches at https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key
To force the defaultValue to re-render all you need to do is change the key value of the input itself. here is how you do it.
<input
type="text"
key={myDynamicKey}
defaultValue={myDynamicDefaultValue}
placeholder="It works"/>
Maybe not the best solution, but I'd make a component like below so I can reuse it everywhere in my code. I wish it was already in react by default.
<MagicInput type="text" binding={[this, 'awayMessage.text']} />
The component may look like:
window.MagicInput = React.createClass
onChange: (e) ->
state = #props.binding[0].state
changeByArray state, #path(), e.target.value
#props.binding[0].setState state
path: ->
#props.binding[1].split('.')
getValue: ->
value = #props.binding[0].state
path = #path()
i = 0
while i < path.length
value = value[path[i]]
i++
value
render: ->
type = if #props.type then #props.type else 'input'
parent_state = #props.binding[0]
`<input
type={type}
onChange={this.onChange}
value={this.getValue()}
/>`
Where change by array is a function accessing hash by a path expressed by an array
changeByArray = (hash, array, newValue, idx) ->
idx = if _.isUndefined(idx) then 0 else idx
if idx == array.length - 1
hash[array[idx]] = newValue
else
changeByArray hash[array[idx]], array, newValue, ++idx
Related issue
Setting defaulValue on control din't not update the state.
Doing reverse works perfectly:
Set state to default value, and the control UI gets updated correctly as if defaulValue was given.
Code:
let defaultRole = "Owner";
const [role, setRole] = useState(defaultRole);
useEffect(() => {
setMsg(role);
});
const handleChange = (event) => {
setRole(event.target.value );
};
// ----
<TextField
label="Enter Role"
onChange={handleChange}
autoFocus
value={role}
/>
Define a state for your default value
Surround your input with a div and a key prop
Set the key value to the same value as the defaultValue of the input.
Call your setDefaultValue defined at the step 1 somewhere to re-render your component
Example:
const [defaultValue, setDefaultValue] = useState(initialValue);
useEffect(() => {
setDefaultValue(initialValue);
}, false)
return (
<div key={defaultValue}>
<input defaultValue={defaultValue} />
</div>
)
Give value to parameter "placeHolder".
For example :-
<input
type="text"
placeHolder="Search product name."
style={{border:'1px solid #c5c5c5', padding:font*0.005,cursor:'text'}}
value={this.state.productSearchText}
onChange={this.handleChangeProductSearchText}
/>
Use value instead of defaultValue and change the value of the input with the onChange method.

Resources