I'm trying to use tagify in a React app. I want it to build the whitelist as the user types. This is what I've got:
const HandleChange = event => {
event.persist()
console.log("CHANGED:", event.target.value)
}
const ProjectAdmin = () => {
const tagifyRef = useRef()
const [tagifySettings, setTagifySettings] = useState([])
const [tagifyProps, setTagifyProps] = useState({})
const tagifyCallbacks = {
input: onInput,
}
const baseTagifySettings = {
placeholder: "Type to search",
dropdown: {
enabled: 0,
position: "text",
},
}
const settings = {
...baseTagifySettings,
...tagifySettings,
callbacks: tagifyCallbacks,
}
var controller
function onInput(e) {
var value = e.detail.value
setTagifySettings(lastState => ({
...lastState,
whitelist: [],
}))
if (value !== "") {
// https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort
controller && controller.abort()
controller = new AbortController()
// show loading animation and hide the suggestions dropdown
setTagifyProps({ loading: true, showDropdown: false })
fetch(`${apiOrigin}/users?query=${value}`, {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${tokens.accessToken}`,
},
signal: controller.signal,
})
.then(result => result.json())
.then(whitelist => {
console.log(whitelist)
let tempList = []
whitelist.forEach(s => {
tempList.push(s["username"])
})
console.log("Whitelist: ", tempList)
setTagifySettings(lastState => ({
...lastState,
whitelist: tempList,
}))
setTagifyProps({ loading: false, showDropdown: true })
})
.catch(error => {
console.log(error)
setTagifySettings({ loading: false })
})
}
}
return (
<Layout pageTitle="Project Control">
<Header contentPage={true} className="contentPage">
<h1 className="display-4 font-weight-bold">Project Control</h1>
</Header>
<Content>
<Row>
<Col xs={{ size: 12 }}>
<Tags
tagifyRef={tagifyRef}
settings={settings}
value="a,b,c"
{...tagifyProps}
onChange={HandleChange}
/>
</Col>
</Row>
</Content>
</Layout>
)
}
As far as I can tell, the whitelist is being built and set correctly as shown by this capture from the React dev tools:
{
"tagifyRef": {
"current": "{CSSVars: {鈥, DOM: {鈥, isFirefox: false, isIE: un鈥"
},
"settings": {
"placeholder": "Type to search",
"dropdown": "{enabled: 0, position: \"text\"}",
"loading": false,
"whitelist": "[\"pjc-test3\", \"pjc-test2\", \"pjc-test1\"]",
"callbacks": "{input: 茠 onInput() {}}"
},
"value": "a,b,c",
"loading": false,
"showDropdown": true,
"onChange": "茠 HandleChange() {}"
}
However, the dropdown never appears. If I enable enforcement of the whitelist and continue typing, say, _pjc-test3_ and press Return, it gets added but then removed, even though the value is in the whitelist.
It is probably something obvious but I'm struggling to see what I've got wrong.
Thanks.
I will investigate asap, thanks for reporting. I suspect showDropdown prop was forgotten to be implemented in my large code-refactor last month, when I completely re-wrote the React wrapper file. will be fixed tomorrow.
sorry about that
Hi @yairEO
I've done some more testing. You will obviously know your code better than I do but I'm not entirely sure it is down to showDropdown.
I've replaced the code with the following:
const tagifyRef = useRef()
const [tagifySettings, setTagifySettings] = useState({
whitelist: [
{ id: 100, value: "kenny", title: "Kenny McCormick" },
{ id: 101, value: "cartman", title: "Eric Cartman" },
{ id: 102, value: "kyle", title: "Kyle Broflovski" },
{ id: 103, value: "token", title: "Token Black" },
],
})
const [tagifyProps, setTagifyProps] = useState({})
const tagifyCallbacks = {
input: onInput,
}
const baseTagifySettings = {
placeholder: "Type to search",
enforceWhitelist: true,
dropdown: {
enabled: 0,
position: "text",
},
}
const settings = {
...baseTagifySettings,
...tagifySettings,
callbacks: tagifyCallbacks,
}
function onInput(e) {
var value = e.detail.value
if (value !== "") {
setTagifyProps({ loading: true }) // , showDropdown: false
let tempList = [
{ id: 107, value: "randy", title: "Randy Marsh" },
{ id: 108, value: "Mr. Garrison", title: "POTUS" },
{ id: 109, value: "Mr. Mackey", title: "M'Kay" },
]
setTagifySettings(lastState => ({
...lastState,
whitelist: tempList,
}))
setTagifyProps({ loading: false }) // , showDropdown: true
}
}
When the page loads and I click in the tag component, the dropdown immediately displays the four South Park names and clicking on one adds it to the tag field.
If I type a single letter, no dropdown is displayed. If I then delete that letter, the dropdown is displayed but with the three remaining names!
So:
showDropdown prop change doesn't make any difference.I thought I'd share this simpler code in case it helps.
Thanks for looking at this so quickly - much appreciated.
I am working hard on this problem, it's a very interesting one.
it will be solved promptly.
Ok, just released a new version 3.17.0 which incorporates the fix in the React wrapper file, but it also requires a different thinking when modifying the whitelist after the component has been initialized.
Instead of this part:
setTagifySettings(lastState => ({
...lastState,
whitelist: tempList,
}))
setTagifyProps({ loading: false }) // , showDropdown: true
Do:
setTagifyProps(lastProps => ({
...lastProps,
whitelist: tempList,
loading: false,
showDropdown: value // your user-input value which was last-typed
}))
It is impossible to modify the whitelist via the settings after the component was initialized, but it is possible via a dedicated whitelist React prop, therefore I use setTagifyProps and not setTagifySettings
Hope this helps!