Error in v-on handler: "TypeError: Cannot read property 'value' of undefined"
Errors are reported as follows: The above error occurred while running the Vue project because its container was initialized before it was generated.
First, check whether there are the following operations
//The original operation of fetching dom document.getElementById('textarea'); //After correction, the operation of taking demo in Vue this.$refs.textarea
If the problem hasn't been solved, it is that $refs still can't get the value, that is, it can't get the sub component object in the El dialog dialog box, and all returned objects are undefined. Add the following on the outside,
this.$nextTick(function () { });
For example, I can't get the value of this.$refs.textarea in my this. Initialize() method. It's undefined all the time. I'll add it outside
this.$nextTick(function () { this._initialize(); });
If the problem hasn't been solved, you need to open El dialog first to initialize the pop-up box. Only when El dialog is initialized can you get the sub components in Vue's rendering engine.
As follows, what I want to do is to open a pop-up box. The pop-up box is a table of the form form. There is an element in the table that is used to edit the code online. It supports the highlighting of each code language. The core code is as follows
<template> <div> <!-- Operation button --> <el-button @click="handleAdd">Newly added</el-button> <!-- Dialog content --> <el-dialog :title="title" :visible.sync="open" width="1000px"> <el-form ref="form" :model="form" label-width="80px"> <el-form-item label="Script content"> <div class="in-coder-panel"> <textarea ref="textarea"></textarea> <el-select class="code-mode-select" v-model="mode" @change="changeMode"> <el-option v-for="mode in modes" :key="mode.value" :label="mode.label" :value="mode.value"> </el-option> </el-select> </div> </el-form-item> </el-form> </el-dialog> </div> </template> <script> // Introduce global instance import CodeMirror from 'codemirror' // Core style import 'codemirror/lib/codemirror.css' // After the theme is introduced, you need to specify the theme in options to take effect import 'codemirror/theme/idea.css' // You need to introduce a specific syntax highlighting library to have the corresponding syntax highlighting effect // codemirror officially supports dynamic loading of corresponding syntax highlight library through / addon/mode/loadmode.js and / mode/meta.js // However, vue does not seem to be able to dynamically load the corresponding JS after instance initialization, so the corresponding JS is introduced in advance here import 'codemirror/mode/javascript/javascript.js' import 'codemirror/mode/css/css.js' import 'codemirror/mode/xml/xml.js' import 'codemirror/mode/shell/shell.js' import 'codemirror/mode/sql/sql.js' //Code completion prompt import 'codemirror/addon/hint/anyword-hint.js'; import 'codemirror/addon/hint/css-hint.js'; import 'codemirror/addon/hint/html-hint.js'; import 'codemirror/addon/hint/javascript-hint.js'; import 'codemirror/addon/hint/show-hint.css'; import 'codemirror/addon/hint/show-hint.js'; import 'codemirror/addon/hint/sql-hint.js'; import 'codemirror/addon/hint/xml-hint.js'; export default { name: "Code", props: { // External incoming content for two-way binding value: String, // Syntax type passed in from outside language: { type: String, default: null } }, data() { return { // What's real inside code: '#!/bin/bash\n' + 'cd /root/\n' + 'list=(`ls`)\n' + ' \n' + 'for i in ${list[@]}\n' + 'do\n' + ' if [ -d $i ]\n' + ' then\n' + ' cp -r $i /tmp/\n' + ' fi\n' + 'done', // Default syntax type mode: 'shell', // Editor instance coder: null, // Default configuration options: { // Indentation format tabSize: 4, // Subject, corresponding subject library JS needs to be introduced in advance theme: 'idea', // set number lineNumbers: true, line: true, extraKeys: {"Ctrl": "autocomplete"}, }, // The syntax highlighting type that supports switching. The corresponding JS has been introduced in advance // MIME type is used, but text / as prefix is written dead when specified later modes: [{ value: 'css', label: 'CSS' }, { value: 'javascript', label: 'Javascript' }, { value: 'html', label: 'XML/HTML' }, { value: 'x-sh', label: 'Shell' }, { value: 'x-sql', label: 'SQL' }], // Pop up layer title title: "", // Show pop-up layer or not open: false, }, methods: { // Initialization _initialize() { // Initialize the editor instance, pass in the text field object and default configuration to be instantiated this.coder = CodeMirror.fromTextArea(this.$refs.textarea, this.options) // Editor assignment this.coder.setValue(this.value || this.code) // Supports two-way binding this.coder.on('change', (coder) => { this.code = coder.getValue() if (this.$emit) { this.$emit('input', this.code) } }) // Attempt to get syntax type from parent container if (this.language) { // Get specific syntax type object let modeObj = this._getLanguage(this.language) // Determine whether the syntax passed in by the parent container is supported if (modeObj) { this.mode = modeObj.label } } }, // Get the current syntax type _getLanguage(language) { // Find the incoming syntax type in the list of supported syntax types return this.modes.find((mode) => { // All values ignore case for comparison let currentLanguage = language.toLowerCase() let currentLabel = mode.label.toLowerCase() let currentValue = mode.value.toLowerCase() // Because the real value may not be standardized, for example, the real value of Java is x-java, so it is said that value and label are compared with the incoming syntax at the same time return currentLabel === currentLanguage || currentValue === currentLanguage }) }, // Change mode changeMode(val) { // Modify the syntax configuration of the editor this.coder.setOption('mode', `text/${val}`) // Get the modified syntax let label = this._getLanguage(val).label.toLowerCase() // Allows the parent container to listen for the current syntax value through the following functions this.$emit('language-change', label) }, /** Button operation */ handleAdd() { this.open = true; this.title = "New script"; this.$nextTick(function () { this._initialize(); }); }, } }; </script> <style lang="stylus" rel="stylesheet/stylus"> .in-coder-panel flex-grow 1 display flex position relative .CodeMirror flex-grow 1 z-index 1 .CodeMirror-code line-height 19px .code-mode-select position absolute z-index 2 right 10px top 10px max-width 130px </style>
The final rendering is as follows