Search code examples
javascriptvue.jsvue-componentvuejs3codemirror

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'language')


I am very new to Vue and JavaScript, so I imagine this is a really simple fix. There are similar posts on here, but those solutions I implemented did not fix the problem.

I was able to utilize the CodeMirror library to get a codeboard, as well as an HTML dropdown with languages to select (without functioning).

From there, given the selected language in the dropdown, I was trying to update the language field, based on some examples I've seen of others implementing CodeMirror.

Any idea of what is going on? Any help would be greatly appreciated.

<script>
import { Codemirror } from "vue-codemirror";
import { javascript } from "@codemirror/lang-javascript";
import { python } from "@codemirror/lang-python";
import { oneDark } from "@codemirror/theme-one-dark";
import { reactive, computed } from "vue";

const themes = { oneDark };
const languages = {
  javascript: javascript(),
  python: python(),
};

const state = reactive({
  language: "python",
  theme: "oneDark",
});

const extensions = computed(() => {
  const result = [];
  result.push(languages[state.language]);
  if (themes[state.theme]) {
    result.push(themes[state.theme]);
  }
  return result;
});

export default {
  components: {
    Codemirror,
  },
  setup() {
    return {
      extensions,
      log: console.log,
    };
  },
};
</script>

<template>
  <div class="toolbar">
    <pre class="state">{{ state }}</pre>
    <div class="config">
      <p>
        <label for="language">language:</label>
        <select name="language" id="language" v-model="state.language">
          <option
            :value="option"
            :key="option"
            v-for="option in ['python', 'javascript']"
          >
            {{ option }}
          </option>
        </select>
      </p>
    </div>
  </div>

  <codemirror
    v-model="code"
    placeholder=""
    :style="{ height: '400px' }"
    :autofocus="true"
    :indent-with-tab="true"
    :tab-size="2"
    :extensions="extensions"
    @ready="log('ready', $event)"
    @change="log('change', $event)"
    @focus="log('focus', $event)"
    @blur="log('blur', $event)"
  />
</template>

Solution

  • Try to move your state and computed property to setup function:

    export default {
      components: {
        Codemirror,
      },
      setup() {
        const state = reactive({
          language: "python",
          theme: "oneDark",
        });
    
        const extensions = computed(() => {
          const result = [];
          result.push(languages[state.language]);
          if (themes[state.theme]) {
            result.push(themes[state.theme]);
          }
          return result;
        });
        return {
          extensions, state,
          log: console.log,
        };
      },
    };