1

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}
          }
       ]
   }
} 
6
  • Seems like a fun problem - could you define your input a bit better - could you post the JSON as it looks like when it's returned from the API? Commented Nov 5, 2020 at 0:00
  • Would something like "<p>Hello, how are you {name}?</p>".replaceAll("{name}", "Dan") do? Commented Nov 5, 2020 at 0:04
  • @Tur1ng the problem is that the name should be binded to changes from the input, so if the input marked as {name} changes, the {name} from label string should too. At the moment i dont see how the changes are binded together in this way Commented Nov 5, 2020 at 0:13
  • 1
    @Dan that shouldn't be hard to do with the way React works. I guess Adam is working on a solution for you that uses String.replaceAll, I'll let him fill in the details! Commented Nov 5, 2020 at 0:17
  • 1
    @Adam sorry i just accidentally changed the way i marked it before, should have been just input: "mood" Commented Nov 5, 2020 at 0:31

1 Answer 1

1

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]}/>
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, took me a while to understand some functional concepts but this is exactly what i have been looking for
@Dan - see my updated answer with a stackblitz here: stackblitz.com/edit/react-ts-cwm9ay?file=DynamicComponent.tsx

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.