Vue: Arahan model-v dinamis

Dibuat pada 16 Jul 2015  ·  42Komentar  ·  Sumber: vuejs/vue

Saat ini, direktif v-model tidak mendukung pengikatan tipe kumis untuk ekspresi pengikatan, tetapi fitur ini akan sangat membantu untuk membuat implementasi seperti pembuat formulir.

Komentar yang paling membantu

anda sudah dapat melakukannya dengan v-model="form[field.name]" .

Semua 42 komentar

Bisakah Anda memberikan contoh tentang apa yang akan membantu?

Katakanlah, bayangkan kita sedang membangun tiruan dari phpmyadmin, yang menerima data dari pernyataan DESCRIBE TABLE dan membangun form editor baris dari data tersebut. Ekspresi pengikatan akan secara inheren dinamis dalam kasus ini, karena kita hanya akan mengetahui nama bidang setelah menjalankan SQL DESCRIBE TABLE.

+1, saya juga mencari ini

+1, berharap untuk melihat ini

Saya masih belum sepenuhnya memahami apa yang memungkinkan ini tidak dapat dicapai oleh sintaks saat ini. Mungkin beberapa contoh kode?

Beberapa kode semu yang terkait dengan klon phpmyadmin dijelaskan di atas:

    <script>
    modue.exports = {
        data: function(){
            //returns table structure pulled from the backend somehow
            return {fields: [
                {name: "id", type: "integer"},
                {name: "name", type: "varchar"},
                {name: "gender", type: "varchar"}
            ], 
            // this was initialised based on the structure above, does not matter how.
            form: {id: null, name: null, gender: null}); 
        },
       methods: {
          getBindingExpr: function(field){ /* blah-blah */ }
       }

    }
    </script>
    <template>
       <div v-repeat="field: fields">
          <!-- Here we need to display an editor bound to the field -->
           <input type="text" v-model="form.{{field.name}}">
        <!-- Or, we can call a function that calculates the binding expression --
          <input type="text" v-model="{{getBindingExpr(field)}}">
      </div>
    </template>

anda sudah dapat melakukannya dengan v-model="form[field.name]" .

kita dapat ? Wow !

evan dapatkah Anda memasang biola js yang menunjukkan contoh todo-ish?

@yyx990803 , itu bagus, tapi itu hanya contoh yang menunjukkan hanya satu contoh penggunaan dinamis. Logikanya mungkin lebih kompleks dalam beberapa jenis aplikasi bisnis.

Untuk memperjelas, saya menentang gagasan untuk mengizinkan interpolasi di dalam ekspresi direktif. Saat ini kumis berarti hasil yang dievaluasi diharapkan menjadi string dan digunakan sebagai string (untuk dimasukkan ke dalam DOM, atau melakukan pencarian ID). Mengevaluasi kumis menjadi ekspresi yang kemudian dapat dievaluasi membuatnya menjadi dua lapisan abstraksi dan pada akhirnya dapat membuat template Anda sangat membingungkan.

saya pikir akan sangat berharga untuk menambahkan kemampuan untuk menginterpolasi string sebelum mengevaluasi ekspresi

metode data[pathString] bekerja dengan baik untuk objek dengan 1 level bersarang tetapi untuk 2 atau lebih saya belum menemukan cara untuk mengikat secara dinamis.

mungkin menambahkan pengubah untuk mengikat sehingga lebih jelas daripada kumis

Contoh

let myData = {}
let varPath = 'myData.path.to["my"].obj'
let modelPath = 'myData.path.to["my"].model'
<component-name :myparam.interpolate='varPath'></component-name>
<input v-model.interpolate='modelPath'>

atau mungkin fungsi pengambil/penyetel yang dapat diteruskan.

penafian: saya belum membaca spesifikasi 2.0 sehingga Anda mungkin telah membahas ini di sana.

@bhoruchi mengapa tidak ada properti yang dihitung?

computed: {
  varPath: function() {
    return this.myData.path.to['my'].obj;
  },
},
<component-name :myparam="varPath"></component-name>

Dan untuk v-model Anda dapat menggunakan properti yang dihitung dengan setter.

@simplesmiler saya belum mencoba properti yang dihitung dalam pengikatan dua arah, saya akan mencobanya. terima kasih atas tipnya.

Memperbarui

@simplesmiler - jadi masalah yang saya hadapi dengan menggunakan properti yang dihitung adalah saya tidak punya cara untuk meneruskan argumen ke properti yang dihitung. this di dalam getter atau bahkan value di get(value) keduanya menunjuk ke komponen.

beberapa latar belakang pada kasus penggunaan saya.

saya membuat pembuat formulir yang menggunakan objek json untuk membuat formulir. objek config kurang lebih merupakan array objek 2 dimensi (baris/bentuk). setiap objek konfigurasi formulir memiliki bidang model yang memiliki string jalur ke bidang yang harus disetel. untuk menggunakan properti yang dihitung untuk ini, saya harus dapat menentukan dari komponen menggunakan komponen yang mengikat indeks baris/formulir apa untuk mencari jalur model dari objek konfigurasi

saat ini saya memiliki ini bekerja menggunakan array 2 dimensi pra-inisialisasi yang disebut formData yang saya ikat setiap model formulir dengan v-model="formData[rowIndex][formIndex]" dan saya melihat objek itu untuk perubahan dan memperbarui objek data induk, tetapi saya tidak menyukai pendekatan ini karena mengharuskan saya untuk melakukan pra-inisialisasi array untuk penambahan bidang dinamis.

saya perlu 2 level bersarang karena saya menggunakan komponen pembuat formulir ini pada komponen lain yang perlu mengatur objek yang terlihat seperti

data: {
  templates: {
    operatingSystems: {
      <someuuid1>: [ <osid1>, <osid2> ],
      <someuuid2>: [ <osid5>, <osid10>, <osid22> ]
   }
  }
}

di mana string jalur saya akan terlihat

templates.operatingSystems[<dynamic uuid>]

Perbarui 2

saya berubah dari menggunakan array multi-dimensi menjadi objek biasa dengan nama kunci

"<rowIndex>_<formIndex>"

dan menggunakan jam tangan yang dalam untuk menjaga agar data tetap sinkron dengan induknya. Saya masih berpikir ikatan yang diinteroprasi akan bermanfaat.

+1

Bagi saya, v-model="$data[field.name]" !

@victorwpbastos ini tidak berfungsi untuk mengatur objek yang sangat bersarang karena hanya akan menggunakan field.name sebagai kuncinya

misalnya jika Anda memiliki data dan string bidang berikut

$data = {
  'animal': {
    'dog': {
      'husky': 1
    }
  }
}
field.name = 'animal.dog.husky'

dan kamu menggunakan

v-model="$data[field.name]"

dan masukkan nilai 2 pada formulir, datanya akan terlihat seperti ini

$data = {
  'animal': {
    'dog': {
      'husky': 1
    }
  },
 'animal.dog.husky': 2
}

alasan pengikatan interpolasi berguna adalah saat Anda membangun input bersarang dinamis di mana Anda tidak dapat "mengkode keras" jalur induk (misalnya 'animal.dog') ke dalam direktif

Saya mengunjungi kembali ini menemukan solusi yang lebih sederhana. Anda dapat membuat objek khusus dan menambahkan getter/setter ke objek tersebut saat dibuat menggunakan string jalur model. Berikut adalah contoh sederhana

daftar masukan

<template lang="jade">
  div
    div(v-for="form in config.forms")
      input(v-model="formData[form.model]")
</template>

<script type="text/babel">
  import Vue from 'vue'
  import _ from 'lodash'

  export default {
    props: ['value', 'config'],
    computed: {},
    methods: {
      vueSet (obj, path, val) {
        let value = obj
        let fields = _.isArray(path) ? path : _.toPath(path)
        for (let f in fields) {
          let idx = Number(f)
          let p = fields[idx]
          if (idx === fields.length - 1) Vue.set(value, p, val)
          else if (!value[p]) Vue.set(value, p, _.isNumber(p) ? [] : {})
          value = value[p]
        }
      }
    },
    data () {
      return {
        formData: {}
      }
    },
    created () {
      _.forEach(this.config.forms, (form) => {
        Object.defineProperty(this.formData, form.model, {
          get: () => _.get(this.value, form.model),
          set: (v) => this.vueSet(this.value, form.model, v)
        })
      })
    }
  }
</script>

digunakan

<template lang="jade">
  div
    input-list(v-model="formData", :config='formConfig')
</template>

<script type="text/babel">
  import InputList from './InputList'
  export default {
    components: {
      InputList
    },
    data () {
      return {
        formData: {
          name: 'Jon',
          loc: {
            id: 1
          }
        },
        formConfig: {
          forms: [
            { type: 'input', model: 'loc.id' },
            { type: 'input', model: 'loc["name"]' }
          ]
        }
      }
    }
  }
</script>

Jika menggunakan cara ini, apakah cara kita dapat mengatur watcher untuk setiap data reaktif yang dibuat secara dinamis?

@luqmanrom Saya tidak terbiasa dengan cara kerja bagian dalam vue watcher tetapi saya percaya apa pun yang dibuat dengan vue.set dapat ditonton sehingga Anda dapat menambahkan beberapa kode untuk menonton props dinamis dan memancarkan perubahan atau Anda dapat merembes menonton objek target. Orang lain mungkin punya saran yang lebih baik

Saya menulis toolkit untuk ini. juga memungkinkan Anda untuk mengubah vuex menggunakan v-model

https://github.com/bhoriuchi/vue-deepset

Ini harus melakukan trik:

Pengarahan

Vue.directive('deep-model', {
    bind(el, binding, vnode) {
        el.addEventListener('input', e => {
            new Function('obj', 'v', `obj.${binding.value} = v`)(vnode.context.$data, e.target.value);
        });
    },
    unbind(el) {
        el.removeEventListener('input');
    },
    inserted(el, binding, vnode) {
        el.value = new Function('obj', `return obj.${binding.value}`)(vnode.context.$data);
    },
    update(el, binding, vnode) {
        el.value = new Function('obj', `return obj.${binding.value}`)(vnode.context.$data);
    }
});

Penggunaan (Komponen)

const component = Vue.extend({
    template: `<input v-deep-model="'one.two.three'">`,
    data() {
        return {
            one: { two: { three: 'foo' } }
        };
    }
});

Berikut adalah Referensi Inti .

Hai tubuh mana pun di sini. Saya menggunakan VUE.js dengan Laravel. Saya memiliki bidang Formulir Kustom Dinamis yang berasal dari database. Saya mengikuti @yyx990803 . v-model="form['nama']". Lapangan bekerja. Tetapi masalahnya adalah saya tidak bisa mendapatkan nilai bidang di laravel Controller. Ada orang disini. Saya menggunakan Kelas @tylerOtwell Form.js.
bantuan Anda akan sangat dihargai.
Terima kasih

Ini bukan forum bantuan. Kami memiliki satu yang didedikasikan untuk menjawab pertanyaan di https://forum.vuejs.org

Saya benar-benar kesulitan mencoba menjalankan fungsi untuk mengetahui nilai v-model . Berikut ini contoh.

Saya mencoba membuat pemilih rentang tanggal yang terlihat seperti ini.
image

Di sini, preset berasal dari array yang terlihat seperti ini..

presets = [
  {
    label: 'Today',
    range: [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')]
  },
]

Sekarang, saya juga memiliki dua tanggal untuk bidang input tersebut di komponen data . startDate & endDate .

Yang benar-benar ingin saya lakukan adalah membandingkan tanggal yang dipilih pengguna dengan tanggal yang dilewatkan dalam konfigurasi prasetel saya dan menyetel nilai v-model ke true atau false tetapi saya tidak dapat karena...

  • v-model tidak menerima kondisi jadi saya tidak bisa melakukan preset.range[0] === startDate && preset.range[1] === endDate .
  • v-model tidak mengizinkan alias v-for diteruskan ke suatu fungsi. Jadi saya tidak bisa melakukan sesuatu seperti
<li v-model="isActive(index)" v-for="(preset, index) in presets">
...
</li>

Membiarkan memiliki pernyataan bersyarat setidaknya dapat menyelesaikan masalah ini dengan mudah.

Juga, saya mungkin melakukan sesuatu yang salah secara fundamental, jadi tolong tunjukkan jika saya dapat mencapainya dengan cara yang berbeda.

Saat ini saya telah memecahkan masalah dengan memanfaatkan fakta bahwa properti yang dihitung adalah panggilan fungsi.

Naskah

computed: {
  isActive() {
      return this.presets.map(
        preset =>
          preset.range[0] === this.startDate && preset.range[1] === this.endDate
      );
    }
}

Templat

<li v-model="isActive[index]" v-for="(preset, index) in presets">
...
</li>

Tapi itu benar-benar tampak seperti peretasan bagi saya. Tidak yakin. Silakan menyarankan.

Adakah yang tahu apakah ini juga berfungsi dalam kombinasi dengan Vuex seperti yang dijelaskan di sini? https://vuex.vuejs.org/guide/forms.html

Saya ingin memiliki bidang input yang sedikit dinamis.

<input v-model="dataHandler" :scope="foo" type="checkbox" />

Bagaimana saya bisa mengakses "lingkup" elemen dom di dalam kode berikut?

computed: {
  message: {
    get () {
      //
    },
    set (value) {
      //
    }
  }
}

@vielhuber mencoba menggunakan ref ?

<input ref="myInput" v-model="dataHandler" :scope="foo" type="checkbox" />
this.$refs.myInput.getAttribute('scope') // => 'foo'

Hai, saya punya pertanyaan Vue terkait dengan topik ini - "dinamis v-model directive":

Ketika saya mengimplementasikan komponen Vue, bagaimana saya bisa mengontrol modifier v-model secara dinamis - .lazy , dll??
Misalnya:

<el-input v-model[field.lazy ? '.lazy' : '']="model[field.key]">

Ini bekerja untuk saya.

<input v-model="$data[field].key" type="text">

@fritx Untuk "secara dinamis" mengubah pengubah, saya menggunakan direktur v-if seperti ini.

<input v-if="field.lazy" v-model.lazy="model[field.key]">
<input v-else v-model="model[field.key]">

Ini bisa menjadi rumit meskipun jika Anda ingin berbagai macam kombinasi pengubah.

Saya kira satu opsi adalah membuat komponen yang dapat digunakan kembali yang berisi semua pernyataan if dan meneruskannya ke komponen input yang ingin Anda render dan array pengubah yang menentukan input mana dengan pengubah yang diinginkan yang dirender. Menggunakan pernyataan if seperti di atas sudah cukup baik untuk saya.

Saya tidak dapat menemukan cara untuk mengakses properti yang dihitung secara dinamis dalam arahan v-model.
Tidak ada cara bagi saya untuk mengakses properti yang dihitung karena Anda dapat mengakses properti data dengan
v-model="$data[sesuatu]"

Kode saya kira-kira seperti ini:

computed: { get () { // }, set (value) { // } } }

Saya memerlukan cara untuk mengakses properti yang dihitung dengan string, yang tidak dapat saya temukan.
Ini adalah contoh tetapi solusi yang berbeda akan bekerja juga.
<input v-model="$computed[someDynamicString]">
atau hanya
<input v-model="[someDynamicString]">

Hal terdekat yang saya temukan adalah "_computedWatchers[someDynamicString].value" tetapi itu tidak bekerja dengan setter dan getter, mungkin itu akan berhasil jika itu hanya nilai yang dihitung.

v-model="dialogTemp.tmBasFuelEntities[dialogTemp.tmBasFuelEntities.findIndex(t=>t.paramCode==item.paramCode)].paramValue"

Ini adalah dialogTemp saya:

dialogTemp: {
  tmBasFuelEntities: [
    {
      paramCode: '',
      paramValue: ''
    },
    {
      paramCode: '',
      paramValue: ''
    },
    {
      paramCode: '',
      paramValue: ''
    },
  ]
}

@fritx Untuk "secara dinamis" mengubah pengubah, saya menggunakan direktur v-if seperti ini.

<input v-if="field.lazy" v-model.lazy="model[field.key]">
<input v-else v-model="model[field.key]">

Ini bisa menjadi rumit meskipun jika Anda ingin berbagai macam kombinasi pengubah.

Saya kira satu opsi adalah membuat komponen yang dapat digunakan kembali yang berisi semua pernyataan if dan meneruskannya ke komponen input yang ingin Anda render dan array pengubah yang menentukan input mana dengan pengubah yang diinginkan yang dirender. Menggunakan pernyataan if seperti di atas sudah cukup baik untuk saya.

Itu keren tapi saya harus memberikan banyak alat peraga ke yang sangat bertele-tele, ada ide? @danhanson

<template v-else-if="itemCom">
        <component v-if="getFieldType(field) === 'number'"
          :is="itemCom"
          :model="model"
          :field="field"
          :schema="schema"
          v-model.number="model[field.key]"
          v-loading="field.loading"
          v-bind="getFieldAttrs(field)"
          v-on="field.listen"
          @form-emit="handleFormEmit"
        ></component>
        <component v-else
          :is="itemCom"
          :model="model"
          :field="field"
          :schema="schema"
          v-model="model[field.key]"
          v-loading="field.loading"
          v-bind="getFieldAttrs(field)"
          v-on="field.listen"
          @form-emit="handleFormEmit"
        ></component>

@fritx Anda dapat mengubah v-model menjadi :value / @input dan menguraikannya secara manual.

</template>
        <component v-if="getFieldType(field) === 'number'"
          :is="itemCom"
          :model="model"
          :field="field"
          :schema="schema"
          :value="parseField(field, model[field.key])"
          @input="model[field.key] = parseField(field, $event.target.value)"
          v-loading="field.loading"
          v-bind="getFieldAttrs(field)"
          v-on="field.listen"
          @form-emit="handleFormEmit"
        ></component>
<template>
<script>

export default {
    ...
    methods: {
        parseField (field, val) {
            if (this.getFieldType(field) === 'number') {
                return Number(val);
            }
            return val;
        }
    }
};
</script>

@danhanson terlihat hebat,

@danhanson saya khawatir seharusnya:

:value="getFieldValue(field, model[field.key])"
@input="model[field.key] = getFieldValue(field, $event)"
@change="model[field.key] = getFieldValue(field, $event)"

Saya tidak yakin, saya akan mencoba. Terima kasih!

@ninojovic

Saya menemukan solusi di sini: https://forum.vuejs.org/t/accessing-computed-properties-from-template-dynamically/4798/9

<input v-model="_self[someDynamicString]">
bekerja untuk saya

Sesuatu seperti ini

<el-input
  v-if="!nestedField.widget"
  v-model="form[nestedField.id]"
  placeholder=""
  v-bind="nestedField.rest"
>
[
  {
    label: '收房价格',
    id: 'housePrice',
    type: Number,
    widget: 'div',
    fieldSet: [
      {
        label: '',
        id: 'housePrice',
        type: Number,
        defaultValue: 0,
        rest: {
          style: 'width:5em;'
        },
      },
      {
        label: '',
        id: 'priceUnit',
        type: String,
        widget: 'select',
        defaultValue: '元/月',
        options: [
          { label: '元/月', value: '元/月' },
          { label: '元/年', value: '元/年' },
          { label: ' 元/天·m2', value: '元/天·m2' },
        ],
        rest: {
          style: 'width:6em;'
        },
      },
    ],
  },
]

Ketika tipe bidang adalah Number , saya ingin menggunakan v-model.number , yang jauh lebih nyaman. @fritx

Saya merobohkan model-v agar sesuai dengan itu.

<el-input
  v-if="!nestedField.widget"
  :value="form[nestedField.id]"
  @input="v => { form[nestedField.id] = isNumber(nestedField.type) ? Number(v) : v }"
  placeholder=""
  v-bind="nestedField.rest"
>
  <template v-if="nestedField.suffixText" slot="append">{{nestedField.suffixText}}</template>
</el-input>

Saya telah mengkloning HMTL menggunakan (beberapa bagian untuk input formulir) yang saya masukkan menggunakan jquery. (jangan katakan mengapa saya menggunakan jquery). sekarang elemen saya sedang dimasukkan oleh jquery. jadi apakah mungkin untuk mengikat v-model.

$('.area').append('formPart')
in form i have some inputs like
<div class="form-group">
<input type="text" name="area2" /> 
<input type="text" name="area3" />
</div>

Jadi bagaimana saya bisa mengikat v-model di area 2 dan 3.

@ninojovic

Saya menemukan solusi di sini: https://forum.vuejs.org/t/accessing-computed-properties-from-template-dynamically/4798/9

<input v-model="_self[someDynamicString]">
bekerja untuk saya

Bekerja untuk saya juga, tetapi variabel "_self" dicadangkan untuk properti internal Vue (lihat #2098).

Dengan kata lain, implementasi ini dapat melanggar di masa depan.

Saya lebih suka cara ini:

<template>
  <input v-model="mySelf[someDynamicString]">
</template>

<script>
export default {
  data() {
    return {
      mySelf: this
    }
  }
}
</script>

Untuk detail lebih lanjut, lihat: https://stackoverflow.com/questions/52104176/use-of-self-attribute-from-vue-vm-is-reliable

Apakah halaman ini membantu?
0 / 5 - 0 peringkat