Replace string with react component with .replace - reactjs

I have a long text (string), I want the user to be able to highlight any word he wants, and make this word a Tag component.
function highlightingString() {
document.onmouseup = () => {
const myHighlightedString = window.getSelection().toString(); // Gives me the word I highglight
const startHighlightedString = docText.indexOf(myHighlightedString) // Give me the start index of my word in the document
const endHighlightedString = startHighlightedString + myHighlightedString.length // Give me the end index of my word in the document
newDocText = docText.replace(myHighlightedString, <Tag name={"Highlighted"}/>)
setOpenedFile(newDocText)
};
}
Tag component
function Tag({name}){
const color = colors[name];
return <div style={{backgroundColor: color, ...tagStyle}}>{name}<span style={{cursor: "pointer", paddingLeft: '10px'}}</span></div>
}
Example:
Initial document text: "Hello, I would like to order a pizza with peperoni"
If the user selects "pizza with", I would like to happen:
"Hello, I would like to order a Tag name={highlighted} /> peperoni" # Where Tag is simply adding a to the selected word
Instead, I get:
"Hello, I would like to order a [object Object] peperoni"
It seems that I am replacing correctly the string I highlight with the <Tag /> component, however I do not get why is not rendering the text within <span> but [object Object]

Well, replacing part of the string with an object will not magically insert that object into that string :) What it does is converting your object to its string representation (which is [object Object]) and then inserting that representation into the string.
What you want to do is to create a proper React component.
Something like this:
<>
{openFile.textBeforeHighlighted}
<Tag name={openFile.highlighted}/>
{openFile.textAfterHighlighted}
</>
while your handler function sets openFile to something like this:
setOpenFile({
textBeforeHighlighted:textBeforeHighlighted,
highlighted:highlighted,
textAfterHighlighted:textAfterHighlighted
});

Related

Reading JSON elements from a field value using REACT

I'm using REACT to read the value from an input field containing a JSON object.
I'm able to get the JSON string value into a const containing the following:
{"name": "This is the name element"}
But when I try to extract the value of the "name" element from the JSON, I get an "undefined" response.
When I get the same JSON text from a js file like this:
export default
{"name": "This is the name field"}
and import it using:
import JSONObject from './JSONObjectFile'
Then it works fine.
What do I need to do to achieve the same thing when retrieving the JSON object from the text field on the HTML page?
Here's the whole code:
import './App.css';
import JSONObject from './aa_DDFFormConfigJSON'
function App() {
var myJSON;
function ConfigJSONReady(event) {
myJSON = document.getElementsByName("myJSONField")[0].value;
//This returns "undefined" instead of the actual "name" element value
console.log("myJSON.name using input field: " + myJSON.name);
// This is the same JSON object from a file, but it works fine
myJSON = JSONObject;
console.log("myJSON.name using file import: " + myJSON.name);
}
return (
<div>
<header>
Everything here is in a REACT App
<p>Success!!</p>
</header>
<form>
<textarea rows="10"
cols="200"
maxlength="5000"
id='myJSONField'
defaultValue='{"name": "This is the name field"}'>
</textarea>
<input
name="DDFConfigJSONReady"
id="DDFConfigJSONReady"
type="checkbox"
onChange={ConfigJSONReady}
/>
</form>
</div>
);
}
export default App;
You are using the wrong API to get the textarea value, you didn't give the name attribute value to the element.
<textarea rows="10"
cols="200" // you are missing `name="myJSONField"`
maxlength="5000"
id='myJSONField'
defaultValue='{"name": "This is the name field"}'>
</textarea>
Instead, you can use document.getElementById() as you already have give an id to the element.
And the value you got from the element is a text, you should parse it to JSON using JSON.parse().
So the code will look like this:
myJSON = document.getElementById("myJSONField").value;
//This returns "undefined" instead of the actual "name" element value
console.log("`myJSON.name` using input field: " + JSON.parse(myJSON).name);
// This is the same JSON object from a file, but it works fine
myJSON = JSONObject;
console.log("myJSON.name using file import: " + myJSON.name);
Live demo here: https://codesandbox.io/s/funny-raman-ktvdzi?file=/src/App.js:141-513
Values read from input fields are of string type, which means, your JSON object is a string as well. In order to convert your JSON string to a JSON object, you need to use JSON.parse() method.
const myObj = "{"key": "value"}";
const parsedObj = JSON.parse(myObj);
And, if you want to convert your JSON object to a string, you can use JSON.stringify() in the similar manner.
const stringifiedObj = JSON.stringify(parsedObj);
Hope that helps!

console log dangerouslySetInnerHTML={{ __html: article.description }}

I built a wyziwig following the instructions here: https://blog.learningdollars.com/2020/04/01/how-to-add-a-rich-text-editor-in-your-react-app-using-draft-js-and-react-draft-wysiwyg/
Now I want to add a show/hide container based on 3 lines of text in the output.
I'm just trying to console.log(dangerouslySetInnerHTML={{ __html: output }}), so I can test the show/hide as well as add an ellipsis. Anyone have any idea how to do this?
Edit:
If you don't want to follow the link, I have setup a sandbox here: https://codesandbox.io/s/react-draft-wysiwyg-fjfh9
More Details:
<div class="modal-body" dangerouslySetInnerHTML={{ __html: output }} /> comes from a library draftjs-to-html. It takes a string such as the following <p>This text is <strong><em>BOLD AND ITALIC</em></strong> with this wyziwyg.</p>, and outputs a string display to the html page such as the following...
"This text is BOLD AND ITALIC from a wyziwyg."
What I want to be able to is determine the .length() of the html displayed output string(above). To do this, I need to see if there is a way to console.log(dangerouslySetInnerHTML={{ __html: output }});
When you want to get the length to the text from a html string, you could do the following, since you assume the contents to be safe (coming from the user's editor):
const getTextLength = (html) => {
// This will never get added to the DOM.
const element = document.createElement("div")
element.innerHTML = html
return element.textContent.length
}
// Some test cases.
const outputs = [
"Some text",
"<p>Some text</p>",
"<p><strong>Some</strong> text</p>"
]
// Should ouput `9` for all test inputs.
console.log(outputs.map(getTextLength))

React JSX - dynamic html attribute

In JSX, we can indicate attribute value dynamically like:
<div className={this.state.className}>This is a div.</div>
Is it possible to indicate attribute (including attribute name and attribute value) dynamically? Like:
const value = emptyValue ? "" : "value='test'";
<input {value} />
That means, once emptyValue is true, "input" tag should not include "value" attribute (value="" is different from no value attribute, as one is show empty in input field, another is show existing text in input field).
ES6 object expansion only works for objects. Therefore to generate a dynamic attribute, try something like this:
const value = emptyValue ? {} : { value: 'test' }
<a {...value} ></a>
Note value will always be an object.
you can insert whole element in if statement in render function, but before return like this:
render() {
var input = (<input />);
if (!emptyValue) {
input = (<input value='test'/>)
}
return (
<div>
{input}
</div>
)
}

Render an Element with React

Honestly I don't think that this is the best Title, but I've no idea how explain it.
So sorry for it.
I'm trying to write a Component that parse all links(thar are not into a anchor tag) and emoji and render it like links or image.
For emoji I'm using this amazing component: https://github.com/banyan/react-emoji
It works well, but the problem is with the simple links...I don't have found a way for render it like links, instead of text of the link tag.
This is my code:
# #cjsx React.DOM
#Linkify = React.createClass
displayName: 'Linkify'
mixins: [ReactEmoji]
componentDidMount: ->
componentWillUnmount: ->
render: ->
<div>
{#parseLinks(#props.text)}
</div>
parseLinks: (text) ->
pattern = /(ht|f)tps?:\/\/[^\"<]*?(?=\s|$|<\/[^a]>)/gi
results = text.match(pattern)
new_text = text
if results and results.length > 0
for result in results
link_html = React.createElement('a', {href: result}, result)
new_text = new_text.replace(result, link_html)
return #emojify(new_text)
and if I wrote:
Hello search here google.com :)
I get:
Hello search here [object Object] :) (instead of :) I've the correct emoji image)
The problem is: why it don't show correctly the Object Link ? where I done wrong ?
Thanks for any help.
link_html = React.createElement('a', {href: result}, result)
new_text = new_text.replace(result, link_html)
You can't use String#replace to put an object (returned by React.createElement) into a string. It's like saying
var text = "one two three";
var el = {testing: true};
alert(text.replace("two", el));
Instead, you should return a ReactElement (created with JSX or React.createElement) that contains the associated text, but with the link in the correct place in the children.
Consider the output of
<span>Test google.com link</span>
which is
React.createElement("span", null,
"Test ",
React.createElement("a", {href: "google.com"},
"google.com"
),
" link"
)

Reactjs How to insert react component into string and then render

How to create a reactjs component that will render the props data with another component.
for example I have a sentence say "Hello guys this is {{name}}. How are you.". Now I want to replace the name with the reactjs component.
when I try to replace the name with the component it shows as [object object].
First Edit:
var sentence = "Hello guys this is {{name}}. How are you.";
var tag_values = {'name': 'any Name'}
TagBox will take sentence and tag_value as props and replace the tags with the Tag component. and render it
var TagBox = React.createClass({
render: function(){
// replacing the tags with Tag component
this.props.sentence = this.props.sentence.replace(tags_values['name'], <Tag \>)
return(
<div>
{this.props.sentence} //Issue: This will Print as "Hello guys this is [Object Object]. How are you."
// But this should print as "This will Print as Hello guys this is any Name. How are you."
// After clicking on "any Name" it should be replaced with input.
</div>
);
}
})
Tag Component will replace the tag with input box on double click. and again replace input box with data on enter.
This can be done using state.
var Tag = React.createClass({})
Okay, so assuming that's a string you have as input, you need to create an array.
var parts = str.split(/\{\{|\}\}/g);
// => ["Hello guys this is ", "name", ". How are you."]
The odd items are literal strings, and the even parts are the stuff between the brackets.
Now we'll create a helper function called mapAlternate. Which takes a function to call for odd elements, and a function to call for even elements in our array.
function mapAlternate(array, fn1, fn2, thisArg) {
var fn = fn1, output = [];
for (var i=0; i<array.length; i++){
output[i] = fn.call(thisArg, array[i], i, array);
// toggle between the two functions
fn = fn === fn1 ? fn2 : fn1;
}
return output;
}
Now we can do something like this in our component:
render: function(){
var parts = str.split(/\{\{|\}\}/g);
// render the values in <strong> tags
var children = mapAlternate(parts,
function(x){ return <span>{x}</span>; },
function(x){ return <strong>{x}</strong> });
return <div>{children}</div>;
}
Which gives us: "Hello guys this is name. How are you."
Have you heard of React String Replace ?
Here is a stateless component example:
import replace from 'react-string-replace';
const reg = /\{([a-z|A-Z|0-9|\.]+)\}/g;
const OutputComponent = props => {
var str = 'Hello {name}, this is a "Super" component: {Super}';
var output = replace(str, reg, prop => props.replacements[prop]);
return <div>{output}</div>;
}
// later
import Super from './Super.jsx';
const obj = {
Super: <Super />,
name: 'John'
}
return <OutputComponent replacements={obj} />;
I just fixed this issue with react-jsx-parser
Your Example would be:
import JsxParser from 'react-jsx-parser'
export default class TagBox extends React.Component {
render() {
const sentence = "Hello guys this is <Tag>name</Tag>. How are you." // simply include the component in your string
return(
<JsxParser components={{ Tag }} jsx={ sentence } /> // identify the component in your string to inject
)
}
}
Nothing from above doesn't worked for me unfortunately. Here is a useful stable solution regexify-string (npm)
npm install --save regexify-string
Works like a charm
regexifyString({
pattern: /\[.*?\]/gim,
decorator: (match, index) => {
return (
<Link
to={SOME_ROUTE}
onClick={onClick}
>
{match}
</Link>
);
},
input: 'Some initial string with [link]',
});

Resources