Skip to content
Advertisement

How can I pass innerHTML to an onClick function (Typescript)

I’m trying to pass the Square element’s innerHTML to the onClick function. I have also tried to pass in just i but it always is equal to 100. Is there a way to either pass i when it’s equal to the same value that goes into the Square or is there a way to pass the innerHTML to the function. Currently, this code generates the error: [TS: 2532]this is possibly undefined I’m making a grid of 100 squares, each one is a button, and each one should have it’s own ID/number from 1-100 to identify them. This is what I have currently: Grid of 100 squares arranged in 10×10 formation

export const Square = (props:any) =>{
    i += 1;
    if(i > 100)
    {
        i = 1;
    }
    return(
        <DefaultButton styles={factionMapButton} onClick={()=>onSquareClick(this.innerHTML,props.onClick)}>{i}</DefaultButton>
    );
}

const onSquareClick = (number:any,isOpen:any) => {
    console.log(number);
    const panelContent = document.getElementById("panelContent");
    if(panelContent !== null)
    {
        panelContent.innerHTML = number;
    }
    isOpen();
}

Advertisement

Answer

You have quite a few problems.

  • You should do your best to avoid any in TypeScript, especially not liberally – that defeats the whole purpose of type-checking. If you’re trying to fix type problems, you should start by also typing everything properly.
  • Arrow functions do not have their this altered by the calling context. If there’s no enclosing full-fledged function, the this in an arrow function will be the global object or undefined, both of which are useless to you. Either use a function to capture the this, or, even better, use the click event’s currentTarget to get a reference to the clicked button.
  • The .innerHTML of an element returns a string, not an element. If it contains a string that can be coerced to a number, explicitly coerce it to a number instead. (If the HTML content is only the string that can be coerced to the number, you should use .textContent instead – only use .innerHTML when deliberately setting or retrieving HTML markup, not plain text)
  • A better approach would be to pass down the i to onSquareClick instead of using DOM manipulation – using the closure is much easier
let i = 1;
export const Square = ({ onClick }: { onClick: () => void }) => {
    i += 1;
    if (i > 100) {
        i = 1;
    }
    return (
        <DefaultButton styles={factionMapButton} onClick={(e) => { onSquareClick(i, onClick); }}>{i}</DefaultButton>
    );
};
const onSquareClick = (number: number, isOpen: () => void) => {
    const panelContent = document.getElementById('panelContent');
    if (panelContent !== null) {
        panelContent.innerHTML = String(number);
    }
    isOpen();
};
  • If you’re using React, you should not be using vanilla DOM manipulation like panelContent.innerHTML = number; – instead, set React state that the view uses to determine what should exist in that element. Something like
// Parent component:
const [panelContentText, setPanelContentText] = useState('');
// expand as needed for the other components in your app...
return <div id="panelContent">{panelContentText}</div>
  <Square setPanelContentText={setPanelContentText} /* and other props */ />

// ...

// Then call the setPanelContentText prop in onSquareClick
const onSquareClick = (number: number, isOpen: () => void, setPanelContentText: React.Dispatch<React.SetStateAction<string>>) => {
    setPanelContentText(String(number));
    isOpen();
};

I’d recommend looking into an introductory React tutorial, it looks like you might benefit from learning the process within React’s ecosystem, rather than trying to mishmash your understanding of vanilla JS’s DOM with React.

Advertisement