Создайте динамическую форму во Vue с условными вопросами

Однако я хочу создать форму динамически с условными полями. Определение формы находится в объекте Q. Ниже приведен пример компонента Vue, использующего bootstrap-vue.

<template>
    <div>
        <div v-for="q of Q">
            <br/>
            <template v-if="q.type == 'input'">
                {{ q.question }}
                <em v-if="q.comment"><br />{{ q.comment }}</em>
                <b-form-input v-model="q.value" :type="q.subtype" :placeholder="q.placeholder"></b-form-input>
                Value: {{ q.value }}
            </template>

            <template v-if="q.type == 'radio'">
                {{ q.question }}
                <em v-if="q.comment"><br />{{ q.comment }}</em>
                <b-form-group>
                    <b-form-radio-group buttons
                                        stacked
                                        v-model="q.value"
                                        :options="q.options"/>
                </b-form-group>

                Value: {{ q.value }}
            </template>

        </div>
    </div>
</template>

<script>
    export default {
        name: 'Questionnaire',
        data() {
            return {
                locale: 'en',
                Q: [
                    {
                        name: 'age',
                        value: null,
                        question: 'How old are you?',
                        placeholder: 'Your age...',
                        comment: 'years since you were born',
                        type: 'input',
                        subtype: 'number',
                        range: [18, 99],
                    },
                    {
                        name: 'cq',
                        value: null,
                        question: 'Conditional Question?',
                        type: 'radio',
                        options: [
                            {text: 'Yes', value: '0'},
                            {text: 'No', value: '1'},
                        ],
                        if: [{object: 'age', largerthan: 30}],
                    },
                ]
            };
        },
        methods: {
            onChange: function(){
                alert('test');
            },
        },
    }
</script>

Я хочу отображать «Условный вопрос», только если возраст> 30 лет.

  • В объекте Q я не могу получить доступ к this.Q (потому что он еще не существует).
  • v-on: change = "onChange" может работать, однако это противоречит сути Vue.

Я не привязан к этой структуре объекта, однако он будет получен с помощью AJAX ...

вопрос: есть ли возможность смотреть this.Q[0].value? или другой способ сделать второй вопрос доступным только в том случае, если первый имеет определенное значение?


person Jeffrey    schedule 16.02.2018    source источник
comment
Почему бы не изменить свою структуру, чтобы использовать пары ключ: значение? Ваш массив объектов содержит 2 объекта, которые очень разные, но ваши структуры, которые он настроил, обрабатывают их так, как если бы они были одного типа.   -  person Stephan-v    schedule 16.02.2018
comment
@ Stephan-v Да, похоже, это работает! Спасибо!   -  person Jeffrey    schedule 16.02.2018


Ответы (2)


Мне удалось создать эффект с помощью директивы v-if во втором div вашего шаблона.

Затем я инициализировал массив «Q» пустым массивом и смоделировал запрос AJAX с помощью setTimeout в ловушке жизненного цикла created ().

<template>
  <div>
    <div v-if="!(q.if) || Q[0].value > q.if[0].largerthan" v-for="q of Q">
        <br/>
        <template v-if="q.type == 'input'">
            {{ q.question }}
            <em v-if="q.comment"><br />{{ q.comment }}</em>
            <b-form-input v-model="q.value" :type="q.subtype" :placeholder="q.placeholder"></b-form-input>
            Value: {{ q.value }}
        </template>

        <template v-if="q.type == 'radio'">
            {{ q.question }}
            <em v-if="q.comment"><br />{{ q.comment }}</em>
            <b-form-group>
                <b-form-radio-group buttons
                                    stacked
                                    v-model="q.value"
                                    :options="q.options"/>
            </b-form-group>

            Value: {{ q.value }}
        </template>

    </div>
  </div>
</template>

<script>
  export default {
    name: 'Questionnaire',
    data() {
        return {
            locale: 'en',
            Q: [],
        };
    },
    created() {
      setTimeout( _ => this.Q = [
                {
                    name: 'age',
                    value: null,
                    question: 'How old are you?',
                    placeholder: 'Your age...',
                    comment: 'years since you were born',
                    type: 'input',
                    subtype: 'number',
                    range: [18, 99],
                },
                {
                    name: 'cq',
                    value: null,
                    question: 'Conditional Question?',
                    type: 'radio',
                    options: [
                        {text: 'Yes', value: '0'},
                        {text: 'No', value: '1'},
                    ],
                    if: [{object: 'age', largerthan: 30}],
                },
                {
                    name: 'age',
                    value: null,
                    question: 'How old are you?',
                    placeholder: 'Your age...',
                    comment: 'years since you were born',
                    type: 'input',
                    subtype: 'number',
                    range: [18, 99],
                },
         ], 500)
    },
}

person Radovan Šurlák    schedule 16.02.2018
comment
Единственная проблема с кодом в том, что Q[0] жестко запрограммирован. Я использовал ваш метод, поместил условия в метод и добавил еще несколько условий. Теперь вроде все работает! - person Jeffrey; 16.02.2018

как говорит @ Stephan-v, я изменил объект на объект "ключ: значение", а не на массив. Как видно из сообщения @ Radovan-Šurlák, наблюдатель не нужен. Обратите внимание, что вычисляемый объект может быть создан только в «beforeCreate» и методе, переменные еще не инициализированы. Передача переменных из beforeCreate объекту кажется довольно сложной.

Таким образом, использование @ Radovan-Šurlák в качестве основы и небольшое ее улучшение приводит к:

<template>
    <div>
        <div v-for="(q, name) of Q" v-if="doShow( name )">
            <br/>
            <template v-if="q.type == 'input'">
                <b>{{ q.question }}</b>
                <em v-if="q.comment"><br/>{{ q.comment }}</em>
                <b-form-input v-model="q.value" :type="q.subtype" :placeholder="q.placeholder"></b-form-input>
            </template>

            <template v-if="q.type == 'radio'">
                <b>{{ q.question }}</b>
                <em v-if="q.comment"><br/>{{ q.comment }}</em>
                <b-form-group>
                    <b-form-radio-group buttons
                                        stacked
                                        v-model="q.value"
                                        :options="q.options"/>
                </b-form-group>
            </template>

        </div>
    </div>
</template>

<script>
    export default {
        name: 'Questionnaire',
        data() {
            return {
                locale: 'en',
                Q: {
                    age: {
                        value: null,
                        question: 'How old are you?',
                        placeholder: 'Your age...',
                        comment: 'years since you were born',
                        type: 'input',
                        subtype: 'number',
                        range: [18, 99],
                    },
                    cq: {
                        value: null,
                        question: 'Conditional Question?',
                        type: 'radio',
                        options: [
                            {text: 'Yes', value: '0'},
                            {text: 'No', value: '1'},
                        ],
                        if: [{object: 'age', largerthan: 30, smallerthan: 35, equals: 31, notequal: 32}],
                    },
                },
            };
        },
        methods: {
            doShow: function( field ) {
                for( var obj in this.Q[ field ].if )
                {
                    var ifObj = this.Q[ field ].if[ obj ];
                    if( ifObj.equals !== undefined && this.Q[ ifObj.object ].value != ifObj.equals )
                        return false;
                    if( ifObj.notequal !== undefined && this.Q[ ifObj.object ].value == ifObj.notequal )
                        return false;
                    if( ifObj.largerthan !== undefined && this.Q[ ifObj.object ].value <= ifObj.largerthan )
                        return false;
                    if( ifObj.smallerthan !== undefined && this.Q[ ifObj.object ].value >= ifObj.smallerthan )
                        return false;
                }
                return true;
            },
            submit: function () {
                console.log('Submit form, send back data via Axios')
            },
        },
        mounted() {
            // Axios call
        }
    }
</script>
person Jeffrey    schedule 16.02.2018