2

I am needing to create a button as people search for locations. When a user clicks on the button it should run an onClick function. However because it is an innerHTML += button it seems to not want to find the function.

The error Can't find variable: addToResult

class NewCampaign extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
          value: null
        };
      }
    
  
    


    render(){
        var currentTimeoutId;
        var areas = [];

       
        function addToResult(e){
            areas.push(e);
        }

        function checkAnswer(event, e) {
    
            if(currentTimeoutId){
                clearTimeout(currentTimeoutId);
             }
         
             currentTimeoutId = setTimeout(function(){
                 currentTimeoutId = null;
                    axios.get('https://nominatim.openstreetmap.org/search.php?city='+e+'&countrycodes=AU&featuretype=county&polygon_geojson=1&format=json')
                    .then(function (response) {
                    // handle success
                    document.getElementById("results").innerHTML = "";
                    for (let i = 0; i < response.data.length; i++) { 
                        document.getElementById("results").innerHTML +="<button onClick={addToResult("+response.data[i].osm_id+")}>ID:"+response.data[i].osm_id+" - "+response.data[i].display_name+"</button>\n\n"
                    }
        
                    })
                    .catch(function (error) {
                    // handle error
                    console.log(error);
                    })
                    .then(function () {
                    // always executed
                    });
                },1000);
        
        }
        return (
            <React.Fragment>
                <div>
            <input name="search" id="search" placeholder='Suburbs'
             value={this.state.value}
             onChange={e => {this.setState({ value: e.currentTarget.value})}}
             onKeyUp={(event) => {checkAnswer(event, this.state.value)}} />
            <div id="results"></div>
            <div id="debug"></div>
             
       
            </div></React.Fragment>  );
    }
}

export default NewCampaign;

After more research I worked out I need to do something like the following

    checkAnswer = (event, e) => {
        if(currentTimeoutId){
            clearTimeout(currentTimeoutId);
         }
     
         currentTimeoutId = setTimeout(function(){
             currentTimeoutId = null;
             alert(e)
                axios.get('https://nominatim.openstreetmap.org/search.php?city='+e+'&countrycodes=AU&featuretype=county&polygon_geojson=1&format=json')
                .then(response => {
                    console.log(response);
                    return response.data.map(user => ({
                      Id: `${user.osm_id}`,
                      name: `${user.place_id}`,
                      Company: `${user.display_name}`,
                    }))
                  })
                      .then(users => {
                        this.setState({
                          users,
                          isLoading: true
                        });
                      })
                  .catch(function (error) {
                // handle error
                console.log(error);
                })
                .then(function () {
                // always executed
                
                //alert(response)
                });
            },1000);
    
    }   

However I am still getting

TypeError: _this.setState is not a function. (In '_this.setState({
                        users: users,
                        isLoading: true
                    })', '_this.setState' is undefined)

HoweverI defined it in

   constructor(props) {
        super(props);
        this.state = {
          value: null,
          users: [],
          isLoading: false
        };
      }

Note I was able to get it to work if it was auto loader at launch

https://codepen.io/redimongo/pen/dydNbGX?editors=1111

was a simple fix

I changed

currentTimeoutId = setTimeout(function(){

to

currentTimeoutId = setTimeout(() => {
2
  • 1
    You're going to have to think in terms of React and change your approach. Mixing native DOM methods like innerHTML with the specific way React updates the DOM is never a good idea, and will cause you a lot of problems. Commented May 15, 2022 at 13:47
  • @Andy I figured that out, after I posted - I am searching for a dropbox plugin, but all require you to refill. Is there away a input can talk to a function and return in a DIV? Commented May 15, 2022 at 13:53

1 Answer 1

0

The error is due to this piece of your code:

"<button onClick={addToResult("+response.data[i].osm_id+")}>ID:"+response.data[i].osm_id+" - "+response.data[i].display_name+"</button>\n\n"

I would suggest you make another component to render both "addToResult" as well as the inner content instead of using the ".innerHTML"

A possible good approach would be to have a state for the results of your data fetching:

const [results,setResults] = useState([]);

Then, you could have a custom Button to render each result:

const Button = ({onClick, children}) => <button onClick={onClick}>{children}</button>

and later on your render section just map the results and display them like:

{results.map(result => <Button onClick={}>{result.osm_id}</Button>}
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks, however, I am not quite following - I have never done something like this before. Where I need to communicate within two sections. The code while I am trying to follow - I am not understanding.
Could I not just set the response.data[i] in a this.state = { results: [], };
Hey, @RussellHarrower , I've made this to help you out getting started: codesandbox.io/s/elegant-benji-9d7lqg
made a few changes to the above code - if you don't mind taking a quick look.

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.