Can't solve a problem. Could someone help me?
I'm building a form and have an autocomplete box. The problem is that if I click somewhere on a page (except for the suggestion item) it doesn't hide. Where should I add setIsAutoCompelte(false) so that it hides?
State
// if true then show the box
const [isAutoComplete, setIsAutoCompelte] = useState(false);
onHandleChangeInput (if input.length > 3)
// show the box
setIsAutoCompelte(true);
onSuggestionClick (if I click on item in autocoplete box)
// hide the box
setIsAutoCompelte(false);
I do not provide full code because it's too big and I'm sure nobody would take a look at it.
You could have an onClick on App that changes the state if the clicked target didn't have the className of the input. You'd need to apply a className such as "autoCompleteBox" to every element/component where you want isAutoComplete to be true.
const clickAnyWhereBut = (e, className) => {
if (!e.current.target.classList.contains(className)) {
setIsAutoCompelte(false); /* you have a typo for "complete/compelte" */
}
}
<div className="App" onClick={() => clickAnyWhereBut("autoCompleteBox")}></div>
This is a lot easier if you're using redux because you wouldn't need to pass down the setIsAutoCompelte[sic] state.
Related
I'm trying to implement highlighter to my blog project using React however I couldn't find any useful library to implement it. Basically I want to implement replica of Medium's Highlighter to my article pages.
After the text selection done, if the user activated the highlighter tool, should be able to highlight the text. Since it requires DOM manipulation I haven't come across the full implementation of the Highlighter the way I wanted to.
What I want to do
User should activate the highlighter.
When the user selects text on the specified area of the articles page, Popover should come up and the user be able select color.
If highlighted text mouseovered, user should see Popover to change the color remove the color.
I found some similar tools;
Link Closest one however it's not getting the which area to highlight and popover modification is not easy.
Link
Link Can't
manipulate the selected text.
I also tried similar JavaScript example however i got error on this methods.link
Currently, I'm trying to write my own component if I can finish it, I will share the source code.
This is the component I wrote, after the text selection done how can i wrap the selected text area with span and can track multiple highlighted texts to remove without breaking the React. I haven't implemented popover yet.
I call this component on article page. Ref comes from the article div.
//articleRef is the id of article area where i want to Highlighter to work.
const Highlighter = ({articleRef}) => {
const { isActive } = useSelector((state) => state.highlighter)
const [selectedText, setSelection] = useState("")
const [selectedNode, setNodeSelection] = useState("")
const [selectedNodes, setNodesSelection] = useState()
useEffect(() => {
document.onselectionchange = function() {
console.log(isActive)
console.log(articleRef.current.id)
// check if the selection done on the article area and check highlighter tool is active
if(articleRef.current.id === 'article-area' && isActive === true ){
console.log("Highlighter is active")
if(document.getSelection() !== (undefined || null ) ){
setNodeSelection(document.getSelection())
}
for(let i = 0; i < selectedNode.rangeCount; i++) {
if( selectedNode.getRangeAt(i) !== (undefined || null )){
console.log(selectedNode.getRangeAt(i))
setSelection(selectedNode.getRangeAt(i).cloneContents())
}
};
console.log(selectedNode)
console.log(selectedText)
}
}
}, [selectedText, selectedNode, isActive, articleRef])
return null;
}
You can use the getSelection API to get the highlighted text. You can make it so that when the user clicks, you get the mouse's position (1), create a element (2) there (which is the tooltip/popup in this case) and use the getSelection API to get the selected text. I recommend using some react hook instead of getSelection as its easier.
(1) - The mouse's position is reported on the event object received by a handler in onmousemove event
(2) - You could also have a hidden element which will be moved to the cursor's position using CSS and make it visible
Well, this question came after this question of mine.
How to disable button if multiple form inputs do not change in Vue.js
There is Switch at every form. When a form inputs are changed, the switch needs to be ON from the OFF state. I have done it by putting this line into the watch method on each form
this.items.forEach( (_, index) => {
this.$watch(['items', index].join('.'), {deep: true, handler: (newVal, oldVal) => {
this.changed.push(newVal.id)
this.items[index].switch = true
}});
});
After adding this line, this.items[index].switch = true, the Switch is getting ON from OFF; but if a user then OFF the Switch again by clicking on the Switch; the text is not changing anymore. It's always remaining ON. how to fix that?
CodePen Demo
If you add this line to watch every time you change this model the switch is set to true. You need a conditional, try this.
this.items[index].switch = this.changed.includes(newOld.id)
My aim is to delete the button, I have just clicked. I understand there may be numerous ways such as creating a deleteButton component, and setting the state appropriately.
However, my return function in the main App component will also render another button (this I can do), but I think this may add to the complexity.
I'm currently struggling to pin-point the ideal solution, so please help.
Okay, so I've managed to solve my question, although I'm sure there's other ways too.
To further clarify...
I had a form which I wished to render, when clicking on a 'Create' Button.
At the same time, I wished to remove the 'Create' button, once clicked.
The end result is to only display the form and nest a new button in the return function.
1) Set the initial state of the form to false:
this.state = {
displayForm: false,
}
2) Then use setState within the displayForm function to allow for the change in state, once the button is clicked:
displayForm(){
this.setState({
displayForm: !this.state.displayForm {/* true */}
})
}
3) set a style object within the render function, such as:
render() {
const btnStyle = {
display: 'block',
} ...
4) Use an IF statement to change the display style of the button if the form has been rendered
if(this.state.displayForm){
btnStyle.display = 'none'
}
5) Now, within the return function, use your JSX tags appropriately and call the function onClick, as well as the style to be applied.
<Button
style={btnStyle}
onClick={() => {
this.displayForm()
}}>Create</button>
{this.state.displayForm && ([
<Form />,
<br />,
<Button>Add Schema</Button>,
])}
NOTE: the < Form /> and < Button /> components have been imported and added here.
So, once the 'Create' button has been clicked, the form displays (true), and thereby the 'Create' button disappears from the Virtual DOM. I've also nested another (new) button as intended, underneath the form.
Please take a look at my code for Dropdown,
I'm using the semantic ui react dropdown on an EditProfile component. I have pasted a sample code here, https://codesandbox.io/s/m4288nx4z8, but I could not get it to work because I'm not very familiar with functional components in React, I've always used Class component. But you can check the full code for the whole component below in the github gist.
https://gist.github.com/mayordwells/b0cbb7b63af85269091f1f98296fd9bb
Please, I need help on inserting values from multiple select options of a Dropdown into the Database and also a way to display that back upon viewing the profile edit page again.
I'm using semantic-ui-react in react + rails app.
Also when I insert a value using a normal drop down without multiple select, the value gets persisted into the database.
<Dropdown
placeholder='Select Country'
fluid
search
selection
options={countryOptions}
name='country'
defaultValue={this.state.extraInfo.country}
onChange={(e) => this.handleExtraInfoChange('country', e)}
/>
This code handles change for the dropdown elements.
handleExtraInfoChange = (name, event) => {
let value;
if (event.target.value !== undefined) {
value = event.target.value;
} else {
value = event.target.textContent;
}
let newExtraInfo = Object.assign(this.state.extraInfo, { [name]: value })
this.setState({ extraInfo: newExtraInfo});
}
But when I visit the page again, I get a white blank in the input box. Here's a screen pic for that. When I comment out the defaultValue or value property(i have tried with defaultValue and value), the white blank disappears, but the value picked by a user is also not seen.
Please advice what is a possible solution to this misbehavior? And what is the best way to insert multiple values into the Database?
Thanks in advance for your time.
A functional component does not have state, it's used for composition; you want to store state, so you either have to create a Component class or you need an external state container like redux.
I have a react project, a recipe box, which includes the ability to open a recipe and add/delete ingredients. Here is a fiddle. You can click the recipe name to open the recipe. There is an edit button which reveals the delete button and gives the option to change the name of the ingredients. When the 'delete ingredient' button is pressed, the last ingredient appears to always be deleted, regardless of which ingredient is selected, but when the 'done' button is clicked and the editable input boxes change back to text, the correct change is shown, the proper ingredient deleted and the last ingredient remains. Though this works functionally, it's obviously not very UI friendly, and I wondered why this was happening. Any help would be great.
jsFiddle
class Input extends React.Component {
render() {
const array = this.props.update;
let booleanButton = null;
if (this.props.ingr) {
////////////////////////////
// here is the button's JSX
booleanButton = <button onClick=
{this.props.handleDeleteIngredient.bind(this, array)}>delete
ingredient</button>;
///////////////////////////
}
return (<div><form><input type="text" defaultValue={this.props.text}
onChange={this.props.onChange.bind(this, array)} /></form>{booleanButton}
</div>)
}
}
And the handler:
handleDeleteIngredient(data, e ) {
var key = data[2];
var ingrs = this.state.ingrs;
ingrs.splice(key, 1);
this.setState({ingrs:ingrs});
}
Your description is quiet confusing, and according the your fiddle code I think your problem is caused by not setting a good key for your list Item.
from what it looks in this line, you don't have a key={ingrs[i]} props, try set it to id see it will work, but making ingrediant name as key is probably not a good idea, try to give an actual id.
ingrList.push(<Input key={ingrs[i]} handleDeleteIngredient={this.handleDeleteIngredient.bind(this)} id={id} update={[this.props.objectIndex, "ingrs", i]} onChange={this.onInputChangeIng.bind(this)} text={ingrs[i]} />);