For AI agents: the complete documentation index is available at https://nhanbe.id.vn/llms.txt, the full documentation bundle is available at https://nhanbe.id.vn/llms-full.txt, and this page is available as Markdown at https://nhanbe.id.vn/frontend/vue2.7/form-input-binding.md.

Working with two-way data binding and form inputs using v-model in Vue 2.7.

Form Input Binding

v-model tạo two-way binding giữa form input và state. Trong AEM, dùng cho các form phía client (search bar, filter, contact form) nằm trong component Vue mount lên DOM HTL render.

Bản chất v-model

v-model là cú pháp rút gọn của việc bind value cộng lắng nghe event cập nhật. Vue tự chọn property và event phù hợp theo loại input:

InputProperty bindEvent lắng nghe
text, textareavalueinput
checkbox, radiocheckedchange
selectvaluechange

Text và textarea

<input v-model="message" placeholder="edit me">
<p>Message: {{ message }}</p>

<textarea v-model="message"></textarea>

Nội suy bên trong textarea không hoạt động: <textarea>{{ text }}</textarea> sai. Phải dùng v-model.

Checkbox

Một checkbox đơn bind giá trị boolean:

<input type="checkbox" id="agree" v-model="checked">
<label for="agree">{{ checked }}</label>

Nhiều checkbox cùng bind vào một mảng:

<input type="checkbox" value="Jack" v-model="checkedNames">
<input type="checkbox" value="John" v-model="checkedNames">
<input type="checkbox" value="Mike" v-model="checkedNames">
<span>Checked: {{ checkedNames }}</span>
data() {
  return { checkedNames: [] }
}

Radio

<input type="radio" value="One" v-model="picked">
<input type="radio" value="Two" v-model="picked">
<span>Picked: {{ picked }}</span>

Select

Single select. Nên có một option disabled với value rỗng làm placeholder, tránh lỗi trạng thái unselected trên iOS.

<select v-model="selected">
  <option disabled value="">Chọn một mục</option>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>
data() {
  return { selected: '' }
}

Multiple select bind vào mảng:

<select v-model="selected" multiple>
  <option>A</option>
  <option>B</option>
</select>

Option động render bằng v-for:

<select v-model="selected">
  <option v-for="opt in options" :value="opt.value" :key="opt.value">
    {{ opt.text }}
  </option>
</select>
data() {
  return {
    selected: 'A',
    options: [
      { text: 'One', value: 'A' },
      { text: 'Two', value: 'B' }
    ]
  }
}

Value bindings

Mặc định v-model bind giá trị tĩnh (string với radio, boolean với checkbox). Cần bind giá trị động hoặc kiểu khác thì dùng các attribute sau.

Checkbox với giá trị tùy chỉnh:

<input type="checkbox" v-model="toggle" true-value="yes" false-value="no">

Khi checked thì toggle === 'yes', khi unchecked thì toggle === 'no'. Lưu ý true-value/false-value không ảnh hưởng attribute value thật, nên unchecked box không được gửi trong form submit. Cần đảm bảo gửi một trong hai giá trị thì dùng radio.

Radio bind giá trị động:

<input type="radio" v-model="pick" :value="a">

Select option bind object:

<select v-model="selected">
  <option :value="{ number: 123 }">123</option>
</select>

Modifiers

ModifierTác dụng
.lazySync sau event change thay vì input (gõ xong, rời focus mới cập nhật)
.numberTự ép kiểu sang Number; không parse được thì giữ nguyên giá trị gốc
.trimTự cắt khoảng trắng đầu/cuối
<input v-model.lazy="msg">
<input v-model.number="age" type="number">
<input v-model.trim="msg">

Lưu ý .number: input HTML luôn trả về string kể cả khi type="number", nên cần .number nếu muốn nhận kiểu Number trong state.

Tips cho AEM

Endpoint hoặc cấu hình lấy từ Sling Model qua data attribute, state form quản lý bằng v-model.

<!-- HTL mount point -->
<div id="contact" data-endpoint="${model.formEndpoint}"></div>
new Vue({
  el: '#contact',
  data() {
    return {
      endpoint: this.$el.dataset.endpoint,
      form: { name: '', email: '', topic: '' }
    }
  },
  methods: {
    async submit() {
      await fetch(this.endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(this.form)
      })
    }
  }
})
<!-- template Vue -->
<form @submit.prevent="submit">
  <input v-model.trim="form.name" placeholder="Tên">
  <input v-model.trim="form.email" type="email" placeholder="Email">
  <select v-model="form.topic">
    <option disabled value="">Chọn chủ đề</option>
    <option>Hỗ trợ</option>
    <option>Góp ý</option>
  </select>
  <button type="submit">Gửi</button>
</form>

Gom các field vào một object form để gửi nguyên cụm và dễ reset. Bind state nguồn vào computed có setter nếu cần biến đổi giá trị trước khi lưu.