287 lines
5.7 KiB
Markdown
287 lines
5.7 KiB
Markdown
# Payload Cleaning - Form Data Transformation
|
|
|
|
## Problem
|
|
The form was sending empty strings (`""`) instead of `null` for empty fields, and checkbox was sending `0` instead of `true/false`.
|
|
|
|
## Solution
|
|
Added data cleaning logic before submitting the form.
|
|
|
|
## Changes Made
|
|
|
|
### 1. Clean Empty Strings to Null
|
|
**Before:**
|
|
```json
|
|
{
|
|
"name": "",
|
|
"email": "",
|
|
"phone": "",
|
|
"vat_number": ""
|
|
}
|
|
```
|
|
|
|
**After:**
|
|
```json
|
|
{
|
|
"name": null,
|
|
"email": null,
|
|
"phone": null,
|
|
"vat_number": null
|
|
}
|
|
```
|
|
|
|
### 2. Ensure Boolean for is_active
|
|
**Before:**
|
|
```json
|
|
{
|
|
"is_active": 0 // or "" or undefined
|
|
}
|
|
```
|
|
|
|
**After:**
|
|
```json
|
|
{
|
|
"is_active": true // or false
|
|
}
|
|
```
|
|
|
|
### 3. Remove Empty Type Field
|
|
The `type` field is not used by the backend, so we remove it if empty.
|
|
|
|
## Implementation
|
|
|
|
```javascript
|
|
const submitForm = async () => {
|
|
// Clear errors before submitting
|
|
fieldErrors.value = {};
|
|
errors.value = [];
|
|
|
|
// Clean up form data: convert empty strings to null
|
|
const cleanedForm = {};
|
|
for (const [key, value] of Object.entries(form)) {
|
|
if (value === '' || value === null || value === undefined) {
|
|
cleanedForm[key] = null;
|
|
} else {
|
|
cleanedForm[key] = value;
|
|
}
|
|
}
|
|
|
|
// Ensure is_active is boolean
|
|
cleanedForm.is_active = Boolean(form.is_active);
|
|
|
|
// Remove type field if it's empty (not needed for backend)
|
|
if (!cleanedForm.type) {
|
|
delete cleanedForm.type;
|
|
}
|
|
|
|
// Emit the cleaned form data to parent
|
|
emit("createClient", cleanedForm);
|
|
};
|
|
```
|
|
|
|
## Example Payloads
|
|
|
|
### Empty Form (Only Required Fields)
|
|
**Before cleaning:**
|
|
```json
|
|
{
|
|
"client_category_id": null,
|
|
"type": "",
|
|
"name": "",
|
|
"vat_number": "",
|
|
"siret": "",
|
|
"email": "",
|
|
"phone": "",
|
|
"billing_address_line1": "",
|
|
"billing_address_line2": "",
|
|
"billing_postal_code": "",
|
|
"billing_city": "",
|
|
"billing_country_code": "",
|
|
"group_id": null,
|
|
"notes": "",
|
|
"is_active": 0,
|
|
"default_tva_rate_id": null
|
|
}
|
|
```
|
|
|
|
**After cleaning:**
|
|
```json
|
|
{
|
|
"client_category_id": null,
|
|
"name": null,
|
|
"vat_number": null,
|
|
"siret": null,
|
|
"email": null,
|
|
"phone": null,
|
|
"billing_address_line1": null,
|
|
"billing_address_line2": null,
|
|
"billing_postal_code": null,
|
|
"billing_city": null,
|
|
"billing_country_code": null,
|
|
"group_id": null,
|
|
"notes": null,
|
|
"is_active": true,
|
|
"default_tva_rate_id": null
|
|
}
|
|
```
|
|
|
|
### Filled Form
|
|
**Before cleaning:**
|
|
```json
|
|
{
|
|
"client_category_id": 4,
|
|
"type": "",
|
|
"name": "SARL TechnoPlus",
|
|
"vat_number": "FR98765432109",
|
|
"siret": "98765432100019",
|
|
"email": "compta@technoplus.fr",
|
|
"phone": "+33198765432",
|
|
"billing_address_line1": "789 Boulevard Haussmann",
|
|
"billing_address_line2": "",
|
|
"billing_postal_code": "75009",
|
|
"billing_city": "Paris",
|
|
"billing_country_code": "FR",
|
|
"group_id": null,
|
|
"notes": "Nouveau client entreprise",
|
|
"is_active": 1,
|
|
"default_tva_rate_id": null
|
|
}
|
|
```
|
|
|
|
**After cleaning:**
|
|
```json
|
|
{
|
|
"client_category_id": 4,
|
|
"name": "SARL TechnoPlus",
|
|
"vat_number": "FR98765432109",
|
|
"siret": "98765432100019",
|
|
"email": "compta@technoplus.fr",
|
|
"phone": "+33198765432",
|
|
"billing_address_line1": "789 Boulevard Haussmann",
|
|
"billing_address_line2": null,
|
|
"billing_postal_code": "75009",
|
|
"billing_city": "Paris",
|
|
"billing_country_code": "FR",
|
|
"group_id": null,
|
|
"notes": "Nouveau client entreprise",
|
|
"is_active": true,
|
|
"default_tva_rate_id": null
|
|
}
|
|
```
|
|
|
|
## Benefits
|
|
|
|
### 1. Cleaner Database
|
|
- `null` values instead of empty strings
|
|
- Easier to query for "no value" vs "empty string"
|
|
|
|
### 2. Laravel Validation Works Better
|
|
Laravel handles `null` better than `""` for:
|
|
- Optional fields
|
|
- Email validation (null is ok, "" might fail)
|
|
- Exists validation (null is ok, "" will try to find empty key)
|
|
|
|
### 3. Boolean Logic Works Correctly
|
|
```php
|
|
// In Laravel
|
|
if ($request->is_active) {
|
|
// This now works correctly
|
|
}
|
|
```
|
|
|
|
### 4. Consistent Data Types
|
|
- Strings stay strings
|
|
- Nulls stay nulls
|
|
- Booleans stay booleans
|
|
- Numbers stay numbers
|
|
|
|
## Checkbox Behavior
|
|
|
|
### Initial State
|
|
```vue
|
|
<input
|
|
type="checkbox"
|
|
v-model="form.is_active"
|
|
:checked="form.is_active"
|
|
/>
|
|
```
|
|
|
|
```javascript
|
|
const form = reactive({
|
|
is_active: true, // ✅ Starts checked
|
|
});
|
|
```
|
|
|
|
### When User Unchecks
|
|
- `form.is_active` becomes `false`
|
|
- Payload sends: `"is_active": false`
|
|
|
|
### When User Checks
|
|
- `form.is_active` becomes `true`
|
|
- Payload sends: `"is_active": true`
|
|
|
|
## Testing
|
|
|
|
### Test 1: Submit Empty Form
|
|
Expected validation error:
|
|
```json
|
|
{
|
|
"errors": {
|
|
"name": ["Le nom du client est obligatoire."]
|
|
}
|
|
}
|
|
```
|
|
|
|
### Test 2: Submit with Only Name
|
|
Payload sent:
|
|
```json
|
|
{
|
|
"client_category_id": null,
|
|
"name": "Test Client",
|
|
"vat_number": null,
|
|
"siret": null,
|
|
"email": null,
|
|
"phone": null,
|
|
"billing_address_line1": null,
|
|
"billing_address_line2": null,
|
|
"billing_postal_code": null,
|
|
"billing_city": null,
|
|
"billing_country_code": null,
|
|
"group_id": null,
|
|
"notes": null,
|
|
"is_active": true,
|
|
"default_tva_rate_id": null
|
|
}
|
|
```
|
|
|
|
Backend should accept this and create client with only name and is_active set.
|
|
|
|
### Test 3: Submit with Inactive Client
|
|
Uncheck "Client actif" checkbox, then submit.
|
|
|
|
Payload sent:
|
|
```json
|
|
{
|
|
"name": "Inactive Client",
|
|
"is_active": false,
|
|
// ... other fields
|
|
}
|
|
```
|
|
|
|
## Why Not Clean on Backend?
|
|
|
|
We clean on frontend because:
|
|
1. **Better UX**: Smaller payload size
|
|
2. **Clearer Intent**: `null` explicitly means "no value"
|
|
3. **Type Safety**: Ensures correct data types before sending
|
|
4. **Validation**: Easier to validate before API call
|
|
5. **Debugging**: Easier to see what data is being sent
|
|
|
|
## Laravel Backend Handles Both
|
|
|
|
The Laravel backend will accept:
|
|
- `"field": null` ✅
|
|
- `"field": ""` ✅ (but converts to null for nullable fields)
|
|
- `"field": "value"` ✅
|
|
|
|
But we send `null` for consistency and clarity.
|