Dan
Dan

Reputation: 109

React render html from a string with a dynamic variable

I am working with react app in typescript. From API, I have this input:

a) list of variable names ["name", "surname"]

b) few strings in form of simple html with variables "<p>Hello, how are you {name}?</p>"

c) number of inputs with variables such as {input1: "name"}

everything as a string/JSON

what i need to do is: render simple html (only few tags) received from API but "create" binding between those dynamic inputs and variables in strings

in static world, result would look like:

[name, setName] = useState("")
<p>Hello, how are you {name}?</p>
<input type="text" onChange={e => setName(e.target.value)}/>

However, all of this is dynamic. String "<p>Hello, how are you {name}?</p>" doesnt get binded to the input on its own.

I tried:

setting variable [vars, setVars] = useState({}), property for each dynamic variable, with

a) dangerouslySetInnerHTML - renders only html (cannot bind the variable inside to the input)

b) react-html-parser - same as above

c) babel.transform - couldnt make it work as this is done dynamically and in browser, it cannot find the right preset, i couldnt make the mimified babel.js work with typescript How to render a string with JSX in React

do you see some easy way? For example how could i use React.createElement to render html with "live" variable inside, represented as {variableName}? Or maybe something out of the box? giving each elemnt a class and finding the class in DOM and editing the text with input change would be probably very non-optimal?

I hope this could be a better example:

{response:
   {
       variables: ["name", "name2", "mood"],
       texts: [
           "<em> Hello! My name is {name}</em>",
           "<p> Hi {name} ! I am <strong>{name2}</strong> and I feel {mood} today</p>"      
       ],
       inputs: [
          {
                label: "How do i feel?"
                input: {mood}
          }
       ]
   }
} 

Upvotes: 1

Views: 6426

Answers (1)

Adam Jenkins
Adam Jenkins

Reputation: 55792

EDIT:

This should give you a good idea:

https://stackblitz.com/edit/react-ts-cwm9ay?file=DynamicComponent.tsx

EDIT #2:

I'm pretty good with React and interpolation, it's still in progress (specifically the docs, but the readme is complete) but I'm going to shamelessly plug my ReactAST library

EDIT #3 - If you're interested in doing crazy dynamic interpolation, then you might also want to check out a neat dynamic interpolation (and it's reverse) library

Let's assume this:

{
   vars: ['name','surname'],
   strings: ["<p>Hello, how are you {name}?</p>","<p> It's night to meet you {name} {surname}"],
   inputs: {
      input1: 'name',
      input2: 'surname'
   }
}

Create a component (or set of components) that can do this.

I haven't even ran any of this, but here's the idea. I'll put it in a stackblitz in a bit and polish it up to make sure it works:

const MyDynamicComponent = ({vars,strings,inputs}) => {
    const [state,setState] = useState(vars.reduce((acc,var) => ({...acc,[var]:undefined}));

     return (
        <>
         <MyDynamicText vars={vars} strings={strings} state={state}/>
         <MyDynamicInputs onChange={(name,val) => setState({[name]:val}) state={state} inputs={inputs}/>
        </>
     )
}

const MyDynamicText = ({vars,strings,state}) => {
   return strings.map((s,i) => s.replaceAll(`{${vars[i]}}`,state[vars[i]])
}

const MyDynamicInputs = ({onChange,inputs,state}) => {
   return Object.entries(inputs).map(([inputName,varName]) => <input key={inputName} onChange={e => onChange(varName,e.target.value)} value={state[varName]}/>
}

Upvotes: 1

Related Questions