How to render objects in hyperHTML - javascript-objects

I've been asked to create a dropdown menu using hyperHTML for an exercise. I'm new to this framework and admittedly haven't found a great deal of material on hyperHTML online, but I've drafted a basic template based on what I've read. The problem is when I attempt to run my script using JSFiddle, it returns nothing from the entire div contents. Is anybody able to explain why this might be?
// HTML
<div id="drop"></div>
// JS
const modes = [{label: 'Driving', value: 'driving'},{label: 'Walking', value: 'walking'},{label: 'Cycling', value: 'cycling'}];
const render = hyperHTML.bind(document.getElementById('drop'));
render`
<h1>Hello, world</h1>
<select>
${modes.map(obj => wire(obj)`<option value="${obj.value}">${obj.label}</option>`)};
</select>
`;
Note: It is only when I add the code within the select parameters that JSFiddle refuses to render the div contents.

From what I can see from your code, you should have an error about the undefined wire, as you don't reference it anywhere.
This is the code I've used in this code pen, and everything works just fine.
const modes = [
{label: 'Driving', value: 'driving'},
{label: 'Walking', value: 'walking'},
{label: 'Cycling', value: 'cycling'}
];
const {bind, wire} = hyperHTML;
const render = bind(document.getElementById('drop'));
render`
<h1>Hello, world</h1>
<select>
${modes.map(obj => wire(obj)`<option value=${obj.value}>${obj.label}</option>`)};
</select>
`;

Related

How to get value from React Select Form

Sorry for just a basic question, But I'm a little stuck here to find any way to get values from React Select after making a selection.
This is a Simple Selection setup.
const selectOptions = [
{ value: 'YES', label: 'Set to Active' },
{ value: 'NO', label: 'Set to Mute' }
]
<Label className='form-label'>Select</Label>
<Select
isClearable={false}
className='react-select'
classNamePrefix='select'
options={selectOptions}
theme={selectThemeColors}
/>
I want to get the value against user-selected choice and put it into userChoice content using useState.
const [userChoice, setUserChoice] = useState("")
value can be YES or NO as defined in selectOptions. But how to pass this into userChoice.
I tried using onChange={(e) => setUserChoice(e.target.value)} But this thing is not working.
Also tried onInputChange={handleInputChange} as suggested in previously asked threads on StackOverflow but not working here.
The onChange callback handler gets called with the whole choice object instead of the event object. Therefore it should be like this.
<Select
...
...
onChange={(choice) => setUserChoice(choice)}
/>
If you only intested in YES / NO value, then use,
onChange={(choice) => setUserChoice(choice.value)}

React - get DOM element TEXT value with Ref

This should be a simple operation, but everything I keep finding online is how to get an 'input value' with a react ref.
I need to know how to get a TEXT value from a DOM element like
<p>hello world</p>
and get 'hello world'
I have the ref set properly and I can log the full html tag with refName.current.
To get the text I have tried refName.value, refName.current.value refName.text, refName.current.text(), refName.innerText.. etc.
Can anyone point me in the right direction?
Thanks.
You can access the text via ref.current.innerText
For example (sandbox):
const ref = useRef();
useEffect(() => {
console.log(ref.current?.innerText || "ref not set!");
}, []);
return <p ref={ref}>Hello world</p>;
Keep in mind that the ref.current is not set for the first render - so it is undefined to start with.

"TypeError: Object(...) is not a function" error when trying to use Semantic UI React Dropdown

I'm getting an error of "TypeError: Object(...) is not a function" on "ClientApp/node_modules/semantic-ui-react/dist/es/modules/Dropdown/Dropdown.js line 81" when I try to create a new instance of the Semantic UI React dropdown in my react application. I have even copied the code over, only changing variable names, from a project that a colleague worked on, and neither of us can seem to determine the source of the error.
I have tried following the guides on semantics website to no avail. I have copied the code with the includes from a working and existing project.
handleSelectClub = (e, data) => {
const club = this.state.clubList[data.value];
this.setState({
clubId: club.id,
name: club.name
});
}
render() {
var clubs;
let selectClub = null;
if (this.state.clubList.length > 0)
{
clubs = this.state.clubList.map((opt, i) => ({
key: opt.id,
text: opt.name,
value: i
}));
selectClub =
<div>
<div className="form-group">
<Dropdown placeholder='Search Clubs' search selection options={clubs} onChange={this.handleSelectClub} />
</div>
</div>
}
return (
<form className="club-add-form" onSubmit={this.handleSubmit}>
<h1>Add a New Club</h1>
{selectClub}
</form>
);
}
I just want the dropdown to be part of a pretty basic form for adding an entry to a database.
I managed to reproduce this error in 0.87.1 of Semantic UI, I downgraded to 0.84 and the issue is not there.
Hope it helps.

React State - Unable to update the state

Update: Fixed it. It was a schoolboy error. I had actually declared a const BaseObject = () => in the render function, and then I was using return in render function. Sorry for wasting your time guys. I moved the const outside as function, and everything is fine.
I have a very simple state:
this.state = {
filters: [{ key: '', value: '' }, { key: '', value: '' }]
}
And part of render method is:
<div>
{
this.state.filters.map((filter, index) => {
return <div key={'filter_parent_div_'+index} style={{ display: 'flex', alignItems: 'center' }}>
<AutoComplete key={'filter_auto'+index} className='width30 sane-margin-from-right' data={keys} onItemSelected={this.onKeySelected(index)} label='Filter'/>
<div key={'filter_div_'+index} className='sane-margin-from-right width30'>
<FormattedTextbox
id={'filterValue_'+index}
key={'filter_text_'+index}
type='text'
label='Filter Value'
defaultValue={filter.value}
onChange={this.filterTextChanged(index)}>
</FormattedTextbox>
</div>
{ index > 0 ? <div className='show-hand' onClick={this.deleteFilter(index)}><i style={{ color: 'lightgray' }} className='sane-margin-from-top material-icons'>clear</i></div> : '' }
</div>
})
}
</div>
It produces a result something like this:
Now my problem is that when I am trying to add a text in the textfield, it is somehow refreshing the state and it is moving my cursor away every time. For example, in my first row, if I am trying to enter 'Vikas' in Filter Value textfield, As soon as I enter 'V', it refreshes the component and my focus goes away. It looks like I am doing something silly here and somehow messing up the state. My text change method is:
filterTextChanged = index => event => {
const filters = this.state.filters; // or JSON.parse(JSON.stringify(this.state.filters))
filters[index].value = event.target.value;
this.setState({ filters });
};
So I can see that this approach is totally wrong, but I am unable to find the best approach in such case. If I have a single object in my state, I can easily use that state and update the state only for that object, but how to do it with the Array? Any help? I can find workarounds like using onBlur instead but I really need to find the best approach to use arrays in the state. Any help?
The problem is with your key, you are using the index as the key, but it isn't identifiable, i.e it will change when you change your filters, try using a uniquer key for each filter that is persisted with state changes and it should fix your problem.
As far as I can tell you're not keeping your component up to date with the state as you're not setting the value of the component. I might be reading the code wrong, but try adding value={filter.value} instead of defaultValue={filter.value}.
If that doesn't work, a fiddle would be very helpful.

Setting a checkbox "check" property in React

I am having a very annoying issue with React and checkboxes. The application I am working with requires a list of checkboxes that represent settings that are persisted in the back-end. There is an option to restore the settings to their original state.
At first, I created a component that has an object like a map of settings. Each setting has a key and a boolean value. Hence:
{
bubbles: true,
gregory: false
}
Is to be represented as:
<input type="checkbox" value="bubbles" checked="checked" />
<input type="checkbox" value="gregory" />
Now, it seems React is ignorant about how a checkbox is supposed to work. I don't want to set the checkboxes' values, I want the "checked" property.
Yet, if I try something like this:
<input
type="checkbox"
value={setting}
checked={this.settings[setting]}
onChange={this.onChangeAction.bind(this)}
/>
I get this warning:
Warning: AwesomeComponent is changing an uncontrolled input of type checkbox to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: [some useless docs page I read several times to no avail]
So I decided to create another component to wrap each individual checkbox and I got this:
<input
type="checkbox"
checked={this.state.checked}
onChange={this.onChangeAction.bind(this)}
/>
Now the checked is a property present directly in my state.
This yields the same warning, so I tried using defaultChecked:
<input
type="checkbox"
defaultChecked={this.state.checked}
onChange={this.onChangeAction.bind(this)}
/>
Which makes the warning disappear, but now it is unable to reset the checked value to the default one. So I tried playing with the method componentWillReceiveProps, this way I am quite sure my state is correct, this.state.checked is correct and the component renders again.
And it does. But the checkbox remains as it was originally.
For now I left that ugly warning and I am using checked.
How do I fix this thing so the warning goes away?
I was thinking that perhaps there is a way to force-re-render the component, so it captures the new defaultChecked value and uses it. But I don't know how to do that. Perhaps suppress the warning only for this component? Is that possible? Perhaps there is something else that can be done?
The problem arises if you set the checked property of your checkbox to null or undefined.
Those are "falsy" values in JS. However, React treats a value of null as if the property was not set at all. Since the default state of a checkbox is unchecked, everything will work fine though. If you then set checked to true, React thinks the property suddenly comes into existence! This is when React figures you switched from uncontrolled to controlled, since now the prop checked exists.
In your example, you can get rid of this warning by changing checked={this.settings[setting]} to checked={!!this.settings[setting]}. Notice the double bang (!!). They will convert null or undefined to false (and leave true alone), so React will register your checked property with a value of false and start off with a controlled form component.
I had this problem too and I, too, read the docs about controlled-components several times to no avail, but I finally figured it out, so I thought I'd share. Also, since version 15.2.0, normal inputs are triggered to be controlled by setting value, while checkboxes are initialized as controlled by setting checked, regardless of their value property, which added a bit to the confusion.
Amoebe's answer is correct, but I think there's a cleaner solution than the double bank (!!). Simply add a defaultProps property with value false for checked prop of your Checkbox component:
import React from 'react';
const Checkbox = ({checked}) => (
<div>
<input type="checkbox" checked={checked} />
</div>
);
Checkbox.defaultProps = {
checked: false
};
export default Checkbox;
Basically, the defaultChecked means you don't want to control the input – it just renders with this value and then there is no way to control it. Also, value shouldn't be used, but checked instead, so your second code should be correct. And you shouldn't use them both simultaneously.
<input
type="checkbox"
checked={this.state.checked}
onChange={this.onChangeAction.bind(this)}
/>
Can you create a small fiddle with this behaviour?
Here is an answer using hooks should you choose to convert the class component to a functional one...
export default Checklist = () => {
const [listOfItems, setListOfItems] = useState([
{name: 'bubbles', isChecked: true},
{name: 'gregory', isChecked: false}
]);
const updateListOfItems = (itemIndex, isChecked) => {
const updatedListOfItems = [...listOfItems];
updatedListOfItems[itemIndex].isChecked = isChecked;
setListOfItems(updatedListOfItems);
}
return (
{listOfitems.map((item, index) =>
<index key={index} type="checkbox" checked={item.isChecked} onChange={() => updateListOfItems(index, !item.isChecked)} />
)}
)
}
You can assign your data to the state and then make use of the checked property associated with the individual checkbox to set the state as
{ this.state.data.map(function(item, index) {
return (
<input type="checkbox" checked={item.value} onChange={this.handleChange.bind(this, index)}/>
);
}.bind(this))
}
Sample Data in state is as
data: [{name:'bubbles', value: true}, {name:'gregory', value: false}]
JSFIDDLE
What finally worked, combining other answers:
const [categories, setCategories] = useState(
[
{
field: 'Label 1',
checked: true
},
{
field: 'Label 2',
checked: false
},
{
field: 'Label 3',
checked: false
}
]
)
const updateList = (item, isChecked) => {
const updatedList = [...categories];
updatedList[item].checked = isChecked;
setCategories(updatedList);
}
... in your markup:
{
categories.map((item, index) =>
<div key = {item.field}>
<label>
<span>{item.field}</span>
<input key={index}
type="checkbox"
checked={item.checked}
onChange={() => updateList(index, !item.checked)}
/>
</label>
</div>
)
}

Resources