Natcho
Natcho

Reputation: 27

How to pass the value of AceEditor to the component state using the onClick of a button? ReactJS

I'm currently trying to implement a CodeMirror of sorts with the help of ACE Editor. I've tried using state alongside the 'onClick' button param but am unable to actually get this working.

import React, { Component } from 'react';
import { makeStyles, createStyles } from '@material-ui/core/styles';
import './CodeMirror.css';
import { Box, Button } from '@material-ui/core';
// Import Brace and the AceEditor Component
import AceEditor from 'react-ace';
import TryItButton from '../CustomButton/TryItButton';
// Import a Mode (language)
import 'ace-builds/src-noconflict/mode-javascript';
// Import a Theme (okadia, github, xcode etc)
import 'ace-builds/src-noconflict/theme-twilight';

export interface AppProps {
  headings: {
    key: number;
    name: string;
    pathname: string;
  }[];
  subheadings: {
    key: number;
    name: string;
    calls: string[];
  }[];
}

interface AppState {
  value: string;
}

function onChange(newValue: string) {
  console.log('CodeMirror value: ', newValue);
}

export default class CodeMirror extends Component<AppProps, AppState> {
  constructor(props: AppProps) {
    super(props);
    this.state = { value: '' };
  }

  render(): JSX.Element {
    return (
      <>
        <div className="main-container-codemirror">
          <div className="top-block-codemirror">
            <Box className="top-bar-text-codemirror">
              <i className="white">Example Call</i>
            </Box>
          </div>

          <div className="example-block-codemirror">
            <div className="textarea-example">
              <AceEditor
                // placeholder="Enter a call here..."
                mode="javascript"
                theme="twilight"
                name="ace-editor"
                fontSize={12}
                showPrintMargin
                wrapEnabled
                showGutter
                highlightActiveLine
                value={this.state.value}
                setOptions={{
                  enableBasicAutocompletion: true,
                  enableLiveAutocompletion: true,
                  enableSnippets: false,
                  showLineNumbers: true,
                  tabSize: 2,
                  useWorker: false,
                }}
                style={{
                  position: 'relative',
                  width: '100%',
                  height: '100%',
                }}
                onChange={onChange}
              />
            </div>

            <div className="spacer">
              <Button
                className="try-it-button"
                style={{
                  backgroundColor: '#533cf8',
                  color: 'white',
                  borderRadius: 0,
                  fontSize: 13,
                  fontWeight: 200,
                }}
              >
                Try it!
              </Button>
              <div className="spacer-text-div">
                auto-update 'fat', alphabetize payload, and make the example
                call below
              </div>
            </div>

            <div className="header-2">
              <i className="white">Example Response</i>
            </div>

            <div className="textarea-example">
              <textarea
                readOnly
                className="example-code"
                value="Response code"
              />
            </div>

            <div className="bottom-block-codemirror" />
          </div>
        </div>
      </>
    );
  }
}

This is my code so far, but what I am trying to do is to get the text that is input into the AceEditor component to be stored in the component state, upon selecting 'Try it' (see below. It would be nice to have the inputted text display in the bottom text area as well, but getting this value in the state is good enough to get me going with the rest of this project.

I'm currently displaying whatever is input in AceEditor using 'onChange' in the console, but am having issues with passing this value between the individual pieces in this component itself. Thank you.

CodeMirror Component

Upvotes: 1

Views: 733

Answers (1)

Sarun UK
Sarun UK

Reputation: 6746

Try this approach,

import "./styles.css";

import React, { Component } from "react";
import { makeStyles, createStyles } from "@material-ui/core/styles";
// import './CodeMirror.css';
import { Box, Button } from "@material-ui/core";
// Import Brace and the AceEditor Component
import AceEditor from "react-ace";
import TryItButton from "../CustomButton/TryItButton";
// Import a Mode (language)
import "ace-builds/src-noconflict/mode-javascript";
// Import a Theme (okadia, github, xcode etc)
import "ace-builds/src-noconflict/theme-twilight";

export default function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <CodeMirror />
      dsdsd
    </div>
  );
}

export interface AppProps {
  headings?: {
    key: number;
    name: string;
    pathname: string;
  }[];
  subheadings?: {
    key: number;
    name: string;
    calls: string[];
  }[];
}

interface AppState {
  value: string;
  textAreaValue?: string;
}

class CodeMirror extends Component<AppProps, AppState> {
  constructor(props: AppProps) {
    super(props);
    this.state = { value: "", textAreaValue: "" };
  }

  onChange(newValue: string) {
    console.log("CodeMirror value: ", newValue);
    this.setState({ value: newValue });
  }

  render() {
    return (
      <>
        <div className="main-container-codemirror">
          <div className="top-block-codemirror">
            <Box className="top-bar-text-codemirror">
              <i className="white">Example Call</i>
            </Box>
          </div>

          <div className="example-block-codemirror">
            <div className="textarea-example">
              <AceEditor
                // placeholder="Enter a call here..."
                mode="javascript"
                theme="twilight"
                name="ace-editor"
                fontSize={12}
                showPrintMargin
                wrapEnabled
                showGutter
                highlightActiveLine
                value={this.state.value}
                setOptions={{
                  enableBasicAutocompletion: true,
                  enableLiveAutocompletion: true,
                  enableSnippets: false,
                  showLineNumbers: true,
                  tabSize: 2,
                  useWorker: false
                }}
                style={{
                  // position: 'relative',
                  width: "100%",
                  height: "200px"
                }}
                onChange={(e) => this.onChange(e)}
              />
            </div>

            <div className="spacer">
              <Button
                className="try-it-button"
                onClick={() =>
                  this.setState((prev) => ({
                    ...prev,
                    textAreaValue: prev["value"]
                  }))
                }
                style={{
                  backgroundColor: "#533cf8",
                  color: "white",
                  borderRadius: 0,
                  fontSize: 13,
                  fontWeight: 200
                }}
              >
                Try it!
              </Button>
              <div className="spacer-text-div">
                auto-update 'fat', alphabetize payload, and make the example
                call below
              </div>
            </div>

            <div className="header-2">
              <i className="white">Example Response</i>
            </div>

            <div className="textarea-example">
              <textarea
                readOnly
                className="example-code"
                value={this.state.textAreaValue || "Response code"}
              />
            </div>

            <div className="bottom-block-codemirror" />
          </div>
        </div>
      </>
    );
  }
}

codeSandbox - https://codesandbox.io/s/reverent-microservice-yp2ff?file=/src/App.tsx:0-3764

Upvotes: 1

Related Questions