> 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.

# Props

Props là cách cha truyền dữ liệu xuống con. Trong AEM, đây là điểm nối chính: dữ liệu từ Sling Model (qua data attribute) đi vào props của root component, rồi truyền tiếp xuống các child component.

## Khai báo props

Khai báo dạng object để có kiểu và validation. Tránh dạng mảng tên đơn thuần trong code thực tế.

```js
export default {
  props: {
    title: { type: String, required: true },
    count: { type: Number, default: 0 },
    tags: { type: Array, default: () => [] },
    config: { type: Object, default: () => ({}) }
  }
}
```

Default của Array/Object phải là factory function (trả về giá trị mới), tránh share tham chiếu giữa các instance.

## Truyền props

```html
<!-- truyền giá trị tĩnh (luôn là string) -->
<blog-post title="Hello"></blog-post>

<!-- bind động bằng v-bind / : -->
<blog-post :title="post.title" :count="post.views"></blog-post>

<!-- truyền number/boolean/array phải dùng v-bind -->
<blog-post :count="42" :is-active="true"></blog-post>
```

Không có `:`, giá trị luôn là string. Cần Number, Boolean, Array, Object thì phải `v-bind`.

## camelCase vs kebab-case

Khai báo prop bằng camelCase trong JS, dùng kebab-case trong template HTML.

```js
props: { postTitle: String }
```

```html
<blog-post post-title="Hello"></blog-post>
```

## Prop types

| Type       | Ví dụ                                   |
| ---------- | --------------------------------------- |
| String     | `{ type: String }`                      |
| Number     | `{ type: Number }`                      |
| Boolean    | `{ type: Boolean }`                     |
| Array      | `{ type: Array, default: () => [] }`    |
| Object     | `{ type: Object, default: () => ({}) }` |
| Function   | `{ type: Function }`                    |
| Nhiều type | `{ type: [String, Number] }`            |

Validation custom:

```js
props: {
  status: {
    validator(value) {
      return ['active', 'pending', 'closed'].includes(value)
    }
  }
}
```

## One-way data flow

Props chỉ chảy một chiều từ cha xuống con. Cha đổi thì con cập nhật, nhưng con KHÔNG được sửa prop. Sửa prop trực tiếp gây warning và dễ tạo bug khó lần.

Hai trường hợp hay muốn sửa prop và cách xử lý đúng:

```js
// 1. Prop dùng làm giá trị khởi tạo cho state cục bộ
props: { initialCount: Number },
data() {
  return { count: this.initialCount }
}

// 2. Prop cần biến đổi để hiển thị: dùng computed
props: { size: String },
computed: {
  normalizedSize() {
    return this.size.trim().toLowerCase()
  }
}
```

Cần đổi giá trị nguồn thì emit event báo cha (xem note Custom Events).

## Non-prop attributes

Attribute truyền vào component nhưng không khai báo trong `props` (vd `class`, `id`, `data-*`) sẽ tự gắn vào phần tử gốc của component. Hữu ích khi truyền `class` hoặc thuộc tính accessibility xuống.

## Tips cho AEM

Root component nhận props từ JSON do Sling Model serialize. Đặt tên prop khớp key trong JSON (không nhất thiết khớp tên field Java).

```js
const el = document.getElementById('hero')
new Vue({
  render: h => h(Hero, {
    props: JSON.parse(el.dataset.props || '{}')
  })
}).$mount(el)
```

```vue
<!-- Hero.vue truyền tiếp xuống con -->
<template>
  <section>
    <h1>{{ title }}</h1>
    <product-card
      v-for="item in items"
      :key="item.id"
      :title="item.title"
      :price="item.price" />
  </section>
</template>

<script>
export default {
  props: {
    title: { type: String, default: '' },
    items: { type: Array, default: () => [] }
  }
}
</script>
```
