1

I am creating a fill in the blank type game using vue. Where a based on a JSON file question the _ in the question are replaced with inputs. I am having trouble with using multiple input fields in my question.

I initialize an empty array for user input and then add an increment to the userInput value so they can be unique. When I start typing and look into the vue console it creates an array of 3 userInputs (There should only be 2, 1 for each input) And it also only fills the last item in the userInput Array 1.

I feel like a I am close and the answer lies somewhere in how I use my domProps and on: {} call but having trouble find docs on my situation. I have simplified my example to exclude the JSON for simplicity. Any help or direction is appreciated.

Here is an link to a sandbox example I have placed the code in app.vue

enter image description here

enter image description here

<template>
 <div class="interactive interactive-vue-question interactive-vue-question-iv">
   <ivInput v-bind:class="'iv-input-wrapper'"></ivInput>
 </div>  
</template>

let ivInput = {
  name: "iv",
  render: function(createElement) {
   let arr = [];
   let question = 'Old *_* had a *_*';
   let questionArray = question.split("*");
   let myInput

   let currentAnswer = 0
   //Filter/Remove any Empty or Null values
    questionArray = questionArray.filter(function(e){return e})

   for (let q in questionArray) {
    //If there is no _ wrap the text in a span and push it to the array

    if (questionArray[q] != "_") {
      let questionText = arr.push(createElement("span", questionArray[q]));

    }else{

    myInput = createElement("input", {
      attrs: {
        type: "text",
       // disabled: this.isSuccess
      },

      domProps: {
        //Get the value of the component/input
        value:  this.userInput[currentAnswer],
        name:"iv-"+ currentAnswer
      },
      //Event triggers
      on: {
        input: e => {
          this.userInput[currentAnswer] = e.target.value
        }
      },
    })
    arr.push(myInput)
    currentAnswer++
 }

}//end for loop
return createElement("div", arr);
},
data: function() {
return {
  userInput: [],
  errorMessage: "",
  //answers: this.cData.body.answers,
 // type: this.cData.body.type,
  //typeErrorMessage: this.cData.body.typeErrorMessage,
 // case: this.cData.body.case,
  //accent: this.cData.body.accent
  };
},
  props:['cData'],
}//End iv

export default {
 name: "iv-v1",
 props: ["cData"],
 components: {
  ivInput
 },
 data: function() {
  return {};
 },
};
0

1 Answer 1

2

Here is a modified, working version of the component in your question. I've added comments to explain my changes.

let ivInput = {
  name: "iv",
  render: function(h) {
    let children = [];

    for (let ndx = 0; ndx < this.questionParts.length; ndx++) {
      // always add a span containing the question part
      children.push(h("span", this.questionParts[ndx]));
      // the answers basically fill in between each question part,
      // so render an input for every question part *except* the
      // last one
      if (ndx < this.questionParts.length - 1) {
        let input = h("input", {
          // use props instead of domProps
          props: {
            value: this.userInput[ndx]
          },
          on: {
            input: evt => {
              // use $set because we are setting an array value by index
              this.$set(this.userInput, ndx, evt.target.value);
            }
          }
        });
        children.push(input);
      }
    }
    // this can be removed, its just so you can see the changes to
    // userInput as they are typed.
    children.push(h("hr"));
    children.push(h("div", JSON.stringify(this.userInput)));

    // render the component
    return h("div", children);
  },
  data: function() {
    return {
      questionParts: [],
      userInput: [],
    };
  },
  created() {
    // split the question into parts in the created handler
    let question = "Old *_* had a *_*";
    this.questionParts = question.split("*_*");
    // the input data also needs to be initialized here with blank answers
    this.userInput = Array.from(Array(this.questionParts.length - 1), () => "");
  },
  props: ["cData"],
}; //End iv

And here is the updated sandbox.

Sign up to request clarification or add additional context in comments.

2 Comments

Awesome, thanks for your help on this, Is there a reason for defining variables in a create function instead in the render function (just want to make sure I understand what is a happening), thanks again
@bilcker render will be called anytime Vue determines the component needs to be re-rendered. You don't really want to be resetting your input data or parsing the question into component parts every time the component is rendered, you only want to do that once.

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.