Nickon
Nickon

Reputation: 10156

Binding functions in React templates

I want to create a simple Wizard component. I don't know how to bind handleChange function for onChange input event and how to get into passed context (which is my custom class defined somewhere and instanced in ParentClass).

Uncaught SyntaxError: Unexpected token }

Here's my Wizard component and simple template that I created to test it:

export class ParentClass extends React.Component {
    render() {
        let template = `<input value=${context.testVal} onChange=${context.handleChange.bind(context, event)}>`; // how to invoke this code inside Wizard using TestContext class???
        let testContext = new TestContext();

        return (
            <Wizard template={template} context={testContext} />
        );
    }
}

export class TestContext {
    testVal = null;

    constructor() {
        this.testVal = 10;
    }

    handleChange(e) {
        console.log(e);
    }
}

export class Wizard extends React.Component {
    context: null;

    constructor(props) {
        super(props);

        this.context = this.props.context;
    }

    render() {
        return (
            <div dangerouslySetInnerHTML={{__html: this.props.template}}>
            </div>
        );
    }
}

I use ES2015 and Babel for compiling.

[edit]

I edited my code and question. I see now what u guys mean saying "remove $".

U didn't understand me. I want to declare HTML code with some variable bindings (as a string) + some context class that should contain all the logic for declared template. When I have those, I want to pass them as params into Wizard and use the template to replace the HTML of this Wizard (executing JSX in the same time). In other words. I want generic mechanism for dynamic templates in Wizard component.

Upvotes: 1

Views: 1500

Answers (1)

JMM
JMM

Reputation: 26807

You're probably much better off just working with JSX here. Here is one example of how to do that:

function Template (props) {
  // Though there's no `event` variable that should be getting bound here and
  // you'd be better off binding `handleChange` to the instance in
  // TestContext's constructor.
  return <input
    value={props.context.testVal}
    onChange={props.context.handleChange.bind(props.context, event)}
  />;
}

export class ParentClass extends React.Component {
    render() {
        let testContext = new TestContext();

        // You could instead create the element here using Template and pass
        // that in. You could even pass it as a child of <Wizard> and just
        // have Wizard render its children.
        return (
            <Wizard template={Template} context={testContext} />
        );
    }
}

// ...

export class Wizard extends React.Component {
    // ...
    render() {
        return (
            <div>
              <this.props.template context={this.props.context} />
            </div>
        );
    }
}

You could do something like what you actually asked for like this, but it's not going to work the way you expect -- you can't render a function object into a string of HTML (so I just deleted the onChange part).

export class ParentClass extends React.Component {
    render() {
        let template = (context) => `<input value=${context.testVal} />`;
        let testContext = new TestContext();

        return (
            <Wizard template={template} context={testContext} />
        );
    }
}

// ...

export class Wizard extends React.Component {
    // ...
    render() {
        return (
            <div dangerouslySetInnerHTML={{__html: this.props.template(this.context)}} />
        );
    }
}

But really you can probably accomplish what you want much better by just working with JSX.

Upvotes: 1

Related Questions