How to make an association map containing white spaces - javascript

I am building an association map that matched a company with its loogo.
The purpose would be to show this logo on google-map.
I am completing the association map company <--> logo but I realized that the name of some vessels have a white space as shown below and I don't know how to correct that problem:
the problem I have is how do I make an association map with a white space? In this way I get a compilation error and don't know how to solve the problem:
Below a snippet of code:
import React from 'react';
import { Table } from 'reactstrap';
const shipCompanyMap = {
VesselA: 'COMPANY-A', //<-- No white space in
Vessel B: 'COMPANY-B', // <-- white space
Vessel C: 'COMPANY-C', // <-- white space
// Other companies...
};
const companyImageMap = {
COMPANY-A: '../src/logos/company_A.jpg',
COMPANY-B: '../src/logos/company_B.png',
COMPANY-C: '../src/logos/company_C.png',
// Other logos...
};
const associationMap = Object.values(shipCompanyMap).reduce(
(acc, curr) => ({
...acc,
[curr]: companyImageMap[curr]
}),
{}
);
const Ship = ({ ship }) => {
const shipName = ship.NAME;
const company = shipCompanyMap[shipName];
const shipImage = companyImageMap[company] || defaultImg;
return (
<div>
{/* Render shipImage image */}
<img src={shipImage} alt="Logo" />
</div>
);
};
export { Ship };
What I have done so far:
I suspected that I had to treat it as an array and started working in that direction. But since I am not passing a "real" object but am trying to make an association map, working to pass the object was not a good way and I have some issues understanding how to treat white spaces.
I am not sure I have to replace the white space. But I don't think so as the name of some vessels have a white space as shown above.
I came across the trimming function that seems to be doing something close, but I am not sure how to use it.
I have the impression that the white space should be sort of neglected (or trimmed) but I am not sure if this is the right approach.

You may quote your keys:
const shipCompanyMap = {
"VesselA": 'COMPANY-A', //<-- No white space in
"Vessel B": 'COMPANY-B', // <-- white space
"Vessel C": 'COMPANY-C', // <-- white space
// Other companies...
};
However in a real world scenario this may not be relevant any longer as you will probably load the data from a service via JSON anyhow.
I like to use sanitised/normalised keys, so i will replace any [^a-zA-Z0-9] characters with a "_", and i may be stripping out whitespaces altogether and also lowercasing all the characters. In most situations you can care less about the actual value for the purpose of a quick lookup. You may even be just using a hash of such a normalised value as key.

Related

React TreeSelect inject custom filtering logic

I have been trying to alter logic in TreeSelect React component.
So, what I am trying to do is to search by value, but with trimmed spaces, for example if we have entries:
dog
cat
fish
when entering dog it should return me dog entry, simply - ignore spaces at the beginning, while still keeping them in UI.
I tried
const [filterValue, setFilterValue] = useState('')
...
<TreeSelect
...otherProps,
filter
filterValue={filterValue}
onFilterValueChange={(e) => setFilterValue(e?.value?.trimStart())}
/>
but unfortunately this affects how component work and while typing spaces at the beginning, it also trims it in displayed value, giving wrong user experience.
QUESTION
Is there simple way I can somehow override this filtering?
Maybe somehow by changing equality comparison?
Yes, you can change the equality comparison logic by passing a custom function to the filterOption.
so first create the compare function and pass it in filterOption.
if that not work for you try filterTreeNode={trimStartAndCompare}
const trimStartAndCompare = (searchValue, optionValue) => {
return optionValue.trimStart() === searchValue.trimStart();
};
const [filterValue, setFilterValue] = useState('');
...
<TreeSelect
...otherProps,
filter
filterValue={filterValue}
filterOption={trimStartAndCompare} // add this part
onFilterValueChange={(e) => setFilterValue(e.value)}
/>
I finally found a way to work around it. Simply make the TreeSelect controlled component and supply your own input in panelHeaderTemplate property of TreeSelect.
This way you can inject bit of extra logic in filtering:
import { useCallback, useState, ChangeEvent } from 'react'
...
const [filterValueProxyState, setFilterValueProxyState] = useState('')
const handleFilterValueChange = useCallback(
(event: ChangeEvent<HTMLTextAreaElement>) => {
// here we trim filter proxy value, to filter by trimmed string in TreeSelect list
setFilterValueProxyState(event.target.value.trimStart())
},
[props.onProxyFilterValueChange]
)
<TreeSelect
panelHeaderTemplate={<textarea value={filterValue} onChange={handleFilterValueChange}/>}
filterValue={filterValueProxyState}
{...restProps}/>
This is merely pseudo code, as most probably textarea is not best choice here, but I just wanted to describe how it could be achieved.

Restrictring user To Enter some Prohibited words in the Address input field, if he enters we have to throw an Error, here i am using react.JS

I have tried this approach to solve this problem,
in this approach, I can validate with the strings present in the Constant object,
if the user entered text will consists those words, the function will return true, with which I can update the error state in react
const constants = {
ADDRESS_PROHIBITED_WORDS:'POBOX|POSTBOX|POSTBUS|P.O.B.O.X|PO BOX|POST BOX'
}
//here we are assuming that user entered below text
const userInput = 'pobox 27 gujarat inida'
const checkForProhibitedWords = userInput => {
const addProhibitedWords = constants.ADDRESS_PROHIBITED_WORDS.split('|')
const prohibitedWordsCheck = userInput.split(' ').some(eachWord => !addProhibitedWords.every(prohibWord => eachWord.toLowerCase() !== prohibWord.toLowerCase()))
console.log('---->> checking',prohibitedWordsCheck );
if (prohibitedWordsCheck) {
console.log('Eror triggered' );
}else{
console.log('Eror removed' );
}
return prohibitedWordsCheck
}
checkForProhibitedWords(userInput);
But the actual problem is
I want to validate with space words also like PO BOX, POST BOX, POST BUS,
but while using split(' ') method on the userInput, it's extracting that word as a seperate one(i.e, for example POBOX it will become two strings as PO and BOX)..
note :
you may tell that, simply add those also in the Constants object as
const constants = {
ADDRESS_PROHIBITED_WORDS:'POBOX|POSTBOX|POSTBUS|P.O.B.O.X|PO BOX|POST BOX|**PO**|**BOX**'
}
but here according to my requirement, I can't use those strings(it's client requirement)
here I can only able to deal with user Input, not the Strings given by client,
did anyone have any idea ??
So when user enters POST BOX or similar words with space, I wanted them to be extracted as same (not only POST BOX, I have a ~100 similar words in my requirement),
What if after you split it, merge it without spaces?
userInput.split(' ').join('').... // logic goes

Pass array of strings to React component with string coming from json file and allow inline span tags

I'm trying to get an array of strings to display as paragraphs and allow an inline span tag inside of these strings.
My issue comes is when the value is added inside the paragraph the decodes the "<" and ">" tag start and ends to their decoded values "<" and ">"
Is there an easy way to get this working without making a specific component for this case?
My React component is as follows
const Paragraphs = ({ data, languageText }) => {
if (data) {
const texts = languageText[data.languageKey];
return (
<section>
{texts && texts.map(text => <p>{text}</p>)}
</section>
);
} else {
console.warn(`webpage::element: 'PARAGRAPHS' lack content`);
}
}
export default Paragraphs;
this is the array that is passed to texts
[
"When a Relic is found or assembled from Relic Fragments, a payout is rewarded, based on its rarity. <span style=\"font-weight: bold\">The rarer the item, the higher the payout!</span>",
"In addition to Relics, Gold Coins can also be found."
],
By default, React escapes HTML to prevent XSS just use dangerouslySetInnerHTML, take a look at oficial docs

CSS transition lost when array changes

I have a simple react app that shifts and unshifts an array of letters. The transition animation occurs when a user hits next and back button. Functionally, the array is properly changed, but the transition only works for next. I have a hunch that this may be an issue more basic than React, but I did make sure that the key is unique to prevent redraw.
// this is the issue.
clickLeftRightHandler = () => {
const { list } = this.state;
// Does using slice or shifting the array cause a new redraw? Is it
the CSS?
const newList = [list[list.length-1], ...list.slice(0, -1)];
this.setState({list : newList});
}
Code Link:
https://stackblitz.com/edit/react-7nsrjg
Any help is appreciated!
Just use the unshift method:
clickLeftRightHandler = () => {
const { list } = this.state;
const newList = list.slice(0, -1);
newList.unshift(list[list.length-1]); // <-- right here
this.setState({list : newList});
}
working example
edit
I honsetly don't know why it works, but it seems like if the string is a bit longer, the animation works as you want it to, so this works:
newList.unshift(list[list.length-1]+' ');
example. I don't know why's that happening, truly.
It turns out that the reason the animation wasn't working properly was due to the key being supplied to the Alphabet Component. The solution adds an index state that makes sure the shifted key receives a new key that's different from the cycled key.
It should also be noted that, #yuvi's updated example also implicitly fixes the issue with a new string that'll be passed to the key causing it to be uniquely set.
See updated example

Draft-js: auto line break

I'm trying to implement an editor using facebook's Draft-JS framework which will be limited to a 50 characters line.
I don't want the lines to break using css, I want them to really break into separate blocks when reaching this 50 characters limit.
The line break should happen at the last space before the word exceeding the 50th character (similar to word-wrap: break-word in css).
Surely, I need the selection to stay at the end of the new line.
I'm not sure where to start with this. Any ideas?
I've created a draft-js codepen with a preview of the current editorState for easy start, just not sure where to start: https://codepen.io/adamtal/pen/pbqVrL?editors=0010
Update:
As a response to Jiang YD's answer, I don't think it's a good idea to take the text from the end of the block and create a new block with it.. Not sure how well the formatting state will be kept. I think the solution should use Modifier.splitBlock with some selection manipulation maybe.
I fought with this same issue where I had a split a block and had to give the new split block some metadata.
Getting the key of the next block that's been created after the split was the tricky part. Here's how I got it done.
const selection = editorState.getSelection();
let contentState = editorState.getCurrentContent();
contentState = Modifier.splitBlock(contentState, selection);
const currentBlock = contentState.getBlockForKey(selection.getEndKey());
const nextBlock = contentState
.getBlockMap()
.toSeq()
.skipUntil(function(v) {
return v === currentBlock;
})
.rest()
.first();
const nextBlockKey = nextBlock.getKey();
const nextBlockEmptySelection = new SelectionState({
anchorKey: nextBlockKey,
anchorOffset: 0,
focusKey: nextBlockKey,
focusOffset: 0
});
contentState = Modifier.setBlockData(
contentState,
nextBlockEmptySelection,
Map()
.set("data1", "Hello this is block data")
.set("data2", 3)
);

Categories