-1

I am building a react component which is a form. Some of the form elements are pulled in from an ajax call. One of the elements needs to have a JavaScript function attached to it. When I use an if/else statement in the render function to detect if the form variables have been pulled in from the server yet, the attachment of the JavaScript function to one of the form elements 'breaks'.

Here is are the relevant functions.

    getModalities() {
    fetch('/services/reader_worklist_services/get_modalities')
        .then(res => res.json())
        .then(
            (result) => {
                this.setState({
                    modalities: {
                        isLoaded: true,
                        items: result
                    },
                });
            },
            (error) => {
                this.setState({
                    modalities: {
                        isLoaded: true,
                        error
                    }
                });
            }
        );
    }

handleChange(event) {
    this.setState({value: event.target.value});
}

    componentDidMount() {
    //attach autodate below start and end dates
    $('#autodate').autodate({ start_date: $('#start_date'), end_date: $('#end_date') });
    this.getModalities();
}

 render() {
    const {error, isLoaded, items} = this.state.modalities;
    debugger;
    let modality_dropdown = '';
    if (error) {
        //return <div>Error: {error.message}</div>
        console.log('Error:');
    } else if (!isLoaded) {
        //return <div>Loading Modalities ...</div>
        console.log("Loading modalities...");
    } else {
        modality_dropdown = '<select>';
        items.map(item => (
            modality_dropdown += "<option value='" + item + "'>" + item + "</option>"
        ));
        modality_dropdown += '</select>'
    }

    return (
        <div className={'main-theme tools_screen'}>
            <form method="post">
                <div className="search-form-layout">
                    <fieldset>
                        <div className="field"><label htmlFor="start_date">Start Date</label><input type="date"
                                                                                                    id="start_date"
                                                                                                    name="search[start_date]"/>
                        </div>
                        <br/>
                        <div className="field"><label htmlFor="end_date">End Date</label><input type="date"
                                                                                                id="end_date"
                                                                                                name="search[end_date]"/>
                        </div>
                        <div id="autodate"/>
                    </fieldset>
                </div>

                <div className="search-form-layout">
                    <div className="field"><label htmlFor="patient_name">Last Name</label><input type="text"
                                                                                                 id="patient_name"
                                                                                                 name="search[patient_name]"/>
                    </div>
                    <br/>
                    <div className="field"><label htmlFor="modality">Modality</label>
                        {parse(modality_dropdown)}
                    </div>
                    <br/>
                    <br/>
                    <div className="field">
                        <button>Search</button>
                    </div>
                </div>
            </form>
            <div id="search_results">
                {this.getSearchResults()}
            </div>
        </div>
    );


};

If I remove the if/else statement in the render function (but build the select box using the code in the final else), everything works fine, but the component no longer gives the nice 'loading...' message and will not longer properly report errors.

With the if/else statement, this line:

$('#autodate').autodate({ start_date: $('#start_date'), end_date: $('#end_date') });

no longer works.

I think the reason is I have multiple return statements in the render function and the componentDidMount function doesn't know when to fire. But that is just a guess.

Does anyone know of a solution for this issue?

J.T.
  • 61
  • 8
  • Why mix jQ and React? Why not use the event binding system built into React itself? That is likely the root of the issue. – zero298 Dec 02 '21 at 15:34
  • Consider reading this: [What is the right way to use Jquery in React?](https://stackoverflow.com/q/51304288/691711) – zero298 Dec 02 '21 at 15:43
  • Don't mix jQ with React unless you understand both perfectly. – Oleg Imanilov Dec 02 '21 at 17:13
  • 'Why not using event binding system...'? Can you please give me an example of how to use the event binding system to attach the autodate function to an element? – J.T. Dec 03 '21 at 14:23
  • Hey zero298 - The solution below doesn't really work perfectly. Can you please give me an example of how to bind the function to an element the react way? – J.T. Dec 03 '21 at 16:59

1 Answers1

0

The solution was found here:

https://reactjs.org/docs/integrating-with-other-libraries.html

It partially works, but it is necessary to make the 'Loading Modalities...' in the if/else statement into a console log rather than returning it to the message to the DOM. If it is issued as a return statement, it still partially breaks the attaching of the autodate function to the element in the next return statement.

So, in the render function the autodate div becomes

<div id="autodate" ref={el => this.el = el} />

And componentDidMount becomes:

    componentDidMount() {
    //attach autodate below start and end dates
    this.$el = $(this.el);
    this.$el.autodate({ start_date: $('#start_date'), end_date: $('#end_date') });
    this.getModalities();
}

And then add a new function componentWillUnmount to keep things clean:

componentWillUnmount() {
    this.$el.autodate('destroy');
}

Thanks zero298. I found the link to the correct way to do this off of the link you sent me above.

J.T.
  • 61
  • 8