Switch Ajax transport to JSON with proper Content-Type
Migrate $name from Form_Field to input components Refactor form inputs: $name moves from Form_Field to input components 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -46,20 +46,18 @@ class Ajax_Batch_Controller extends Rsx_Controller_Abstract
|
|||||||
\App\RSpade\Core\Debug\Debugger::disable_console_html_output();
|
\App\RSpade\Core\Debug\Debugger::disable_console_html_output();
|
||||||
|
|
||||||
// Get batch calls from request
|
// Get batch calls from request
|
||||||
$batch_calls_json = $request->input('batch_calls');
|
// With JSON Content-Type, Laravel auto-decodes the body
|
||||||
|
$batch_calls = $request->input('batch_calls');
|
||||||
|
|
||||||
if (empty($batch_calls_json)) {
|
if (empty($batch_calls)) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'error' => 'Missing batch_calls parameter'
|
'error' => 'Missing batch_calls parameter'
|
||||||
], 400);
|
], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse batch calls
|
|
||||||
$batch_calls = json_decode($batch_calls_json, true);
|
|
||||||
|
|
||||||
if (!is_array($batch_calls)) {
|
if (!is_array($batch_calls)) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'error' => 'Invalid batch_calls format - must be JSON array'
|
'error' => 'Invalid batch_calls format - must be array'
|
||||||
], 400);
|
], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -195,7 +195,8 @@ class Ajax {
|
|||||||
$.ajax({
|
$.ajax({
|
||||||
url: url,
|
url: url,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: params,
|
contentType: 'application/json',
|
||||||
|
data: JSON.stringify(params),
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
__local_integration: true, // Bypass $.ajax override
|
__local_integration: true, // Bypass $.ajax override
|
||||||
success: (response) => {
|
success: (response) => {
|
||||||
@@ -364,7 +365,8 @@ class Ajax {
|
|||||||
const response = await $.ajax({
|
const response = await $.ajax({
|
||||||
url: '/_ajax/_batch',
|
url: '/_ajax/_batch',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: { batch_calls: JSON.stringify(calls_to_send) },
|
contentType: 'application/json',
|
||||||
|
data: JSON.stringify({ batch_calls: calls_to_send }),
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
__local_integration: true, // Bypass $.ajax override
|
__local_integration: true, // Bypass $.ajax override
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -455,12 +455,12 @@ EDIT PAGE (ADD/EDIT COMBINED)
|
|||||||
<Form_Hidden_Field $name="id" />
|
<Form_Hidden_Field $name="id" />
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<Form_Field $name="name" $label="Name" $required=true>
|
<Form_Field $label="Name" $required=true>
|
||||||
<Text_Input />
|
<Text_Input $name="name" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<Form_Field $name="status" $label="Status">
|
<Form_Field $label="Status">
|
||||||
<Select_Input $options="<%= JSON.stringify(this.data.status_options) %>" />
|
<Select_Input $name="status" $options="<%= JSON.stringify(this.data.status_options) %>" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary">Save</button>
|
<button type="submit" class="btn btn-primary">Save</button>
|
||||||
@@ -479,11 +479,11 @@ RSX_FORM
|
|||||||
$method - Ajax endpoint method name
|
$method - Ajax endpoint method name
|
||||||
|
|
||||||
Form Fields
|
Form Fields
|
||||||
<Form_Field $name="fieldname" $label="Label" $required=true>
|
<Form_Field $label="Label" $required=true>
|
||||||
<Text_Input />
|
<Text_Input $name="fieldname" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
The $name must match:
|
The $name on the input component must match:
|
||||||
- The key in $data JSON
|
- The key in $data JSON
|
||||||
- The key in server-side $params
|
- The key in server-side $params
|
||||||
- The key in validation $errors array
|
- The key in validation $errors array
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ NAME
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
Client-side (template):
|
Client-side (template):
|
||||||
<Form_Field $name="schedule" $label="Date & Time">
|
<Form_Field $label="Date & Time">
|
||||||
<Schedule_Input />
|
<Schedule_Input $name="schedule" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
Server-side:
|
Server-side:
|
||||||
@@ -42,8 +42,8 @@ DESCRIPTION
|
|||||||
|
|
||||||
Schedule_Input combines all scheduling fields into one component:
|
Schedule_Input combines all scheduling fields into one component:
|
||||||
|
|
||||||
<Form_Field $name="schedule">
|
<Form_Field $label="Schedule">
|
||||||
<Schedule_Input />
|
<Schedule_Input $name="schedule" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
Submits as JSON:
|
Submits as JSON:
|
||||||
@@ -90,8 +90,8 @@ SCHEDULE_INPUT COMPONENT
|
|||||||
Template Usage
|
Template Usage
|
||||||
|
|
||||||
Basic usage:
|
Basic usage:
|
||||||
<Form_Field $name="schedule" $label="Date & Time" $required=true>
|
<Form_Field $label="Date & Time" $required=true>
|
||||||
<Schedule_Input />
|
<Schedule_Input $name="schedule" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
Without timezone picker:
|
Without timezone picker:
|
||||||
@@ -334,12 +334,12 @@ COMPLETE EXAMPLE
|
|||||||
Template
|
Template
|
||||||
|
|
||||||
<Rsx_Form $data=this.data.form_data $controller="Events_Controller" $method="save">
|
<Rsx_Form $data=this.data.form_data $controller="Events_Controller" $method="save">
|
||||||
<Form_Field $name="title" $label="Title" $required=true>
|
<Form_Field $label="Title" $required=true>
|
||||||
<Text_Input />
|
<Text_Input $name="title" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<Form_Field $name="schedule" $label="Date & Time" $required=true>
|
<Form_Field $label="Date & Time" $required=true>
|
||||||
<Schedule_Input $sid="schedule_input" />
|
<Schedule_Input $name="schedule" $sid="schedule_input" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary">Save</button>
|
<button type="submit" class="btn btn-primary">Save</button>
|
||||||
|
|||||||
@@ -116,16 +116,16 @@ TEMPLATE PATTERN
|
|||||||
<Form_Hidden_Field $name="id" />
|
<Form_Hidden_Field $name="id" />
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<Form_Field $name="title" $label="Title" $required=true>
|
<Form_Field $label="Title" $required=true>
|
||||||
<Text_Input />
|
<Text_Input $name="title" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<Form_Field $name="status_id" $label="Status">
|
<Form_Field $label="Status">
|
||||||
<Select_Input $options=this.data.status_options />
|
<Select_Input $name="status_id" $options=this.data.status_options />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<Form_Field $name="team_members" $label="Team">
|
<Form_Field $label="Team">
|
||||||
<Form_Repeater
|
<Form_Repeater $name="team_members"
|
||||||
$edit_input="Team_Member_Edit"
|
$edit_input="Team_Member_Edit"
|
||||||
$display_input="Team_Member_Display"
|
$display_input="Team_Member_Display"
|
||||||
/>
|
/>
|
||||||
@@ -350,7 +350,8 @@ COMMON MISTAKES
|
|||||||
this.data.form_data = { name: 'Test' };
|
this.data.form_data = { name: 'Test' };
|
||||||
|
|
||||||
// Template uses 'title' - VALUE WILL BE EMPTY
|
// Template uses 'title' - VALUE WILL BE EMPTY
|
||||||
<Form_Field $name="title">
|
<Form_Field $label="Title">
|
||||||
|
<Text_Input $name="title" />
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
forms_and_widgets(3), jqhtml(3), ajax(3)
|
forms_and_widgets(3), jqhtml(3), ajax(3)
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ SYNOPSIS
|
|||||||
<Rsx_Form $data="{{ json_encode($form_data) }}"
|
<Rsx_Form $data="{{ json_encode($form_data) }}"
|
||||||
$action="{{ Rsx::Route('Controller', 'save') }}">
|
$action="{{ Rsx::Route('Controller', 'save') }}">
|
||||||
|
|
||||||
<Form_Field $name="email" $label="Email Address" $required=true>
|
<Form_Field $label="Email Address" $required=true>
|
||||||
<Text_Input $type="email" $placeholder="user@example.com" />
|
<Text_Input $name="email" $type="email" $placeholder="user@example.com" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<Form_Field $name="bio" $label="Biography">
|
<Form_Field $label="Biography">
|
||||||
<Text_Input $type="textarea" $rows=5 />
|
<Text_Input $name="bio" $type="textarea" $rows=5 />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<button type="button" id="save-btn">Save</button>
|
<button type="button" id="save-btn">Save</button>
|
||||||
@@ -69,12 +69,12 @@ RSX_FORM COMPONENT
|
|||||||
Example - Basic Form:
|
Example - Basic Form:
|
||||||
|
|
||||||
<Rsx_Form $action="{{ Rsx::Route('Users_Controller', 'save') }}">
|
<Rsx_Form $action="{{ Rsx::Route('Users_Controller', 'save') }}">
|
||||||
<Form_Field $name="first_name" $label="First Name">
|
<Form_Field $label="First Name">
|
||||||
<Text_Input />
|
<Text_Input $name="first_name" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<Form_Field $name="last_name" $label="Last Name">
|
<Form_Field $label="Last Name">
|
||||||
<Text_Input />
|
<Text_Input $name="last_name" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<button type="button" id="save-btn">Save</button>
|
<button type="button" id="save-btn">Save</button>
|
||||||
@@ -119,39 +119,38 @@ FORM_FIELD WRAPPER
|
|||||||
|
|
||||||
Responsibilities:
|
Responsibilities:
|
||||||
- Display label with optional required indicator
|
- Display label with optional required indicator
|
||||||
- Set data-name attribute on child widget
|
- Read data-name from child widget (set by Form_Input_Abstract)
|
||||||
- Display validation errors returned from server
|
- Display validation errors returned from server
|
||||||
- Provide consistent spacing and styling
|
- Provide consistent spacing and styling
|
||||||
|
|
||||||
Example - Basic Field:
|
Example - Basic Field:
|
||||||
|
|
||||||
<Form_Field $name="email" $label="Email Address">
|
<Form_Field $label="Email Address">
|
||||||
<Text_Input $type="email" />
|
<Text_Input $name="email" $type="email" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
Example - Required Field with Help Text:
|
Example - Required Field with Help Text:
|
||||||
|
|
||||||
<Form_Field $name="password"
|
<Form_Field $label="Password"
|
||||||
$label="Password"
|
|
||||||
$required=true
|
$required=true
|
||||||
$help="Must be at least 8 characters">
|
$help="Must be at least 8 characters">
|
||||||
<Text_Input $type="password" />
|
<Text_Input $name="password" $type="password" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
Example - Field with HTML in Label:
|
Example - Field with HTML in Label:
|
||||||
|
|
||||||
<Form_Field $name="twitter" $label="<i class='bi bi-twitter'></i> Twitter">
|
<Form_Field $label="<i class='bi bi-twitter'></i> Twitter">
|
||||||
<Text_Input $prefix="@" />
|
<Text_Input $name="twitter" $prefix="@" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
Form_Field_Abstract:
|
Form_Field_Abstract:
|
||||||
Use Form_Field_Abstract directly when you need field functionality
|
Use Form_Field_Abstract directly when you need field functionality
|
||||||
without visual formatting (e.g., for hidden fields or custom layouts).
|
without visual formatting (e.g., for custom layouts).
|
||||||
|
|
||||||
Example - Unformatted Field:
|
Example - Unformatted Field:
|
||||||
|
|
||||||
<Form_Field_Abstract $name="custom_field">
|
<Form_Field_Abstract>
|
||||||
<Custom_Widget />
|
<Custom_Widget $name="custom_field" />
|
||||||
</Form_Field_Abstract>
|
</Form_Field_Abstract>
|
||||||
|
|
||||||
Form_Hidden_Field:
|
Form_Hidden_Field:
|
||||||
@@ -388,14 +387,14 @@ DISABLED STATE
|
|||||||
|
|
||||||
Example - Disable Individual Fields:
|
Example - Disable Individual Fields:
|
||||||
|
|
||||||
<Form_Field $name="email" $label="Email (Cannot Edit)">
|
<Form_Field $label="Email (Cannot Edit)">
|
||||||
<Text_Input $type="email" $disabled=true />
|
<Text_Input $name="email" $type="email" $disabled=true />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
Example - Conditional Disable:
|
Example - Conditional Disable:
|
||||||
|
|
||||||
<Form_Field $name="status" $label="Status">
|
<Form_Field $label="Status">
|
||||||
<Select_Input $options="{{ json_encode($statuses) }}"
|
<Select_Input $name="status" $options="{{ json_encode($statuses) }}"
|
||||||
$disabled="{{ !$can_edit_status }}" />
|
$disabled="{{ !$can_edit_status }}" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
@@ -465,31 +464,31 @@ MULTI-COLUMN LAYOUTS
|
|||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<Form_Field $name="first_name" $label="First Name">
|
<Form_Field $label="First Name">
|
||||||
<Text_Input />
|
<Text_Input $name="first_name" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<Form_Field $name="last_name" $label="Last Name">
|
<Form_Field $label="Last Name">
|
||||||
<Text_Input />
|
<Text_Input $name="last_name" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<Form_Field $name="city" $label="City">
|
<Form_Field $label="City">
|
||||||
<Text_Input />
|
<Text_Input $name="city" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<Form_Field $name="state" $label="State">
|
<Form_Field $label="State">
|
||||||
<Text_Input $maxlength=2 />
|
<Text_Input $name="state" $maxlength=2 />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<Form_Field $name="zip" $label="ZIP Code">
|
<Form_Field $label="ZIP Code">
|
||||||
<Text_Input />
|
<Text_Input $name="zip" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -547,8 +546,8 @@ CREATING CUSTOM WIDGETS
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
<Form_Field $name="satisfaction" $label="Rate Your Experience">
|
<Form_Field $label="Rate Your Experience">
|
||||||
<Rating_Input />
|
<Rating_Input $name="satisfaction" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
EXAMPLES
|
EXAMPLES
|
||||||
@@ -573,34 +572,34 @@ EXAMPLES
|
|||||||
<Form_Hidden_Field $name="id" />
|
<Form_Hidden_Field $name="id" />
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<Form_Field $name="name" $label="Company Name" $required=true>
|
<Form_Field $label="Company Name" $required=true>
|
||||||
<Text_Input $seeder="company_name" />
|
<Text_Input $name="name" $seeder="company_name" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<Form_Field $name="email" $label="Email">
|
<Form_Field $label="Email">
|
||||||
<Text_Input $type="email" $seeder="email" />
|
<Text_Input $name="email" $type="email" $seeder="email" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<Form_Field $name="phone" $label="Phone">
|
<Form_Field $label="Phone">
|
||||||
<Text_Input $type="tel" $seeder="phone" />
|
<Text_Input $name="phone" $type="tel" $seeder="phone" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Form_Field $name="industry" $label="Industry">
|
<Form_Field $label="Industry">
|
||||||
<Select_Input $options="{{ json_encode($industries) }}"
|
<Select_Input $name="industry" $options="{{ json_encode($industries) }}"
|
||||||
$placeholder="Select Industry..." />
|
$placeholder="Select Industry..." />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<Form_Field $name="notes" $label="Notes">
|
<Form_Field $label="Notes">
|
||||||
<Text_Input $type="textarea" $rows=5 />
|
<Text_Input $name="notes" $type="textarea" $rows=5 />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<Form_Field $name="active" $label=" ">
|
<Form_Field $label=" ">
|
||||||
<Checkbox_Input $label="Active Client" />
|
<Checkbox_Input $name="active" $label="Active Client" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<button type="button" class="btn btn-primary" id="save-btn">
|
<button type="button" class="btn btn-primary" id="save-btn">
|
||||||
|
|||||||
@@ -570,16 +570,16 @@ Full implementation showing modal class, form component, and page integration:
|
|||||||
2. Form Component (add_user_modal_form.jqhtml):
|
2. Form Component (add_user_modal_form.jqhtml):
|
||||||
|
|
||||||
<Define:Add_User_Modal_Form tag="div">
|
<Define:Add_User_Modal_Form tag="div">
|
||||||
<Form_Field $name="email" $label="Email" $required=true>
|
<Form_Field $label="Email" $required=true>
|
||||||
<Text_Input $type="email" />
|
<Text_Input $name="email" $type="email" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<Form_Field $name="first_name" $label="First Name">
|
<Form_Field $label="First Name">
|
||||||
<Text_Input />
|
<Text_Input $name="first_name" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<Form_Field $name="last_name" $label="Last Name">
|
<Form_Field $label="Last Name">
|
||||||
<Text_Input />
|
<Text_Input $name="last_name" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
</Define:Add_User_Modal_Form>
|
</Define:Add_User_Modal_Form>
|
||||||
|
|
||||||
|
|||||||
100
app/RSpade/upstream_changes/form_input_abstract_12_29_2.txt
Executable file
100
app/RSpade/upstream_changes/form_input_abstract_12_29_2.txt
Executable file
@@ -0,0 +1,100 @@
|
|||||||
|
# Form Input $name Migration
|
||||||
|
|
||||||
|
**Date:** 2025-12-29
|
||||||
|
**Affects:** All forms, all custom input components
|
||||||
|
|
||||||
|
## Breaking Change
|
||||||
|
|
||||||
|
The `$name` attribute now belongs on the **input component**, not on `Form_Field`.
|
||||||
|
|
||||||
|
### Before (Old Pattern)
|
||||||
|
```html
|
||||||
|
<Form_Field $name="email" $label="Email Address" $required=true>
|
||||||
|
<Text_Input $placeholder="user@example.com" />
|
||||||
|
</Form_Field>
|
||||||
|
```
|
||||||
|
|
||||||
|
### After (New Pattern)
|
||||||
|
```html
|
||||||
|
<Form_Field $label="Email Address" $required=true>
|
||||||
|
<Text_Input $name="email" $placeholder="user@example.com" />
|
||||||
|
</Form_Field>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Core Principle: Components Are Black Boxes
|
||||||
|
|
||||||
|
The input component IS the input. The form system interacts with components through:
|
||||||
|
- `data-name` attribute on the component's root element (set automatically by Form_Input_Abstract.on_create())
|
||||||
|
- `val()` method for getting/setting values
|
||||||
|
|
||||||
|
Internal elements are implementation details. The form system never looks inside components.
|
||||||
|
|
||||||
|
## Migration Checklist
|
||||||
|
|
||||||
|
### 1. Move $name from Form_Field to Input
|
||||||
|
|
||||||
|
Find and update all forms:
|
||||||
|
```bash
|
||||||
|
grep -r '<Form_Field[^>]*\$name=' rsx/app --include="*.jqhtml" --include="*.blade.php"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Ensure extends="Form_Input_Abstract" on all input templates
|
||||||
|
|
||||||
|
```html
|
||||||
|
<Define:My_Custom_Input extends="Form_Input_Abstract">
|
||||||
|
...
|
||||||
|
</Define:My_Custom_Input>
|
||||||
|
```
|
||||||
|
|
||||||
|
Without this, `data-name` won't be set on the component root.
|
||||||
|
|
||||||
|
### 3. Call super.on_create() in subclasses
|
||||||
|
|
||||||
|
All input components overriding `on_create()` MUST call `super.on_create()`:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
class My_Input extends Form_Input_Abstract {
|
||||||
|
on_create() {
|
||||||
|
super.on_create(); // REQUIRED - sets data-name
|
||||||
|
// ... rest of initialization
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Remove name from internal elements
|
||||||
|
|
||||||
|
Input components must NOT put `name` on internal elements:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- WRONG -->
|
||||||
|
<input type="hidden" name="<%= this.args.name %>" />
|
||||||
|
|
||||||
|
<!-- CORRECT - no name attribute, data-name is on component root -->
|
||||||
|
<input type="hidden" $sid="hidden_input" />
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Remove deprecated methods
|
||||||
|
|
||||||
|
Remove any implementations of:
|
||||||
|
- `_transform_value(value)` - no longer in base class
|
||||||
|
- `seed()` - removed from Form_Input_Abstract contract
|
||||||
|
|
||||||
|
## How It Works Now
|
||||||
|
|
||||||
|
1. Input component receives `$name="email"` as argument
|
||||||
|
2. `Form_Input_Abstract.on_create()` sets `data-name="email"` on component root
|
||||||
|
3. `Form_Field` finds child `.Form_Input_Abstract` and reads its `data-name`
|
||||||
|
4. `Rsx_Form.vals()` finds all `[data-name]` elements and calls `val()` on each
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
After migration, verify:
|
||||||
|
```bash
|
||||||
|
# No $name on Form_Field
|
||||||
|
grep -r '<Form_Field[^>]*\$name=' rsx/app --include="*.jqhtml"
|
||||||
|
# Should return nothing
|
||||||
|
|
||||||
|
# No name on internal elements
|
||||||
|
grep -rn 'name="<%' rsx/theme/components/inputs --include="*.jqhtml"
|
||||||
|
# Should return nothing
|
||||||
|
```
|
||||||
@@ -1078,7 +1078,8 @@ Detailed guidance for specific tasks is available via Claude Code skills. These
|
|||||||
| `migrations` | Raw SQL, make:migration:safe, forward-only |
|
| `migrations` | Raw SQL, make:migration:safe, forward-only |
|
||||||
| `polymorphic` | Type refs, morphTo, Polymorphic_Field_Helper |
|
| `polymorphic` | Type refs, morphTo, Polymorphic_Field_Helper |
|
||||||
|
|
||||||
Skills location: `~/.claude/skills/` (symlinked from `system/docs/skills/`)
|
**Framework skills**: `~/.claude/skills/` (symlinked from `system/docs/skills/`) - READ-ONLY, do not modify
|
||||||
|
**Project skills**: `/var/www/html/.claude/skills/` - Custom skills for this specific project go here
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -232,12 +232,12 @@ class Contacts_Edit_Action extends Spa_Action {
|
|||||||
$data="<%= JSON.stringify(this.data.form_data) %>">
|
$data="<%= JSON.stringify(this.data.form_data) %>">
|
||||||
<Form_Hidden_Field $name="id" />
|
<Form_Hidden_Field $name="id" />
|
||||||
|
|
||||||
<Form_Field $name="name" $label="Name" $required=true>
|
<Form_Field $label="Name" $required=true>
|
||||||
<Text_Input />
|
<Text_Input $name="name" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<Form_Field $name="email" $label="Email">
|
<Form_Field $label="Email">
|
||||||
<Text_Input $type="email" />
|
<Text_Input $name="email" $type="email" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary">
|
<button type="submit" class="btn btn-primary">
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ Forms use `<Rsx_Form>` with automatic data binding:
|
|||||||
```jqhtml
|
```jqhtml
|
||||||
<Rsx_Form $data="<%= JSON.stringify(this.data.form_data) %>"
|
<Rsx_Form $data="<%= JSON.stringify(this.data.form_data) %>"
|
||||||
$controller="Controller" $method="save">
|
$controller="Controller" $method="save">
|
||||||
<Form_Field $name="email" $label="Email" $required=true>
|
<Form_Field $label="Email" $required=true>
|
||||||
<Text_Input $type="email" />
|
<Text_Input $name="email" $type="email" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
|
|
||||||
<Form_Hidden_Field $name="id" />
|
<Form_Hidden_Field $name="id" />
|
||||||
@@ -84,13 +84,13 @@ Use Bootstrap grid for multi-column field layouts:
|
|||||||
```jqhtml
|
```jqhtml
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<Form_Field $name="first_name" $label="First Name">
|
<Form_Field $label="First Name">
|
||||||
<Text_Input />
|
<Text_Input $name="first_name" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<Form_Field $name="last_name" $label="Last Name">
|
<Form_Field $label="Last Name">
|
||||||
<Text_Input />
|
<Text_Input $name="last_name" />
|
||||||
</Form_Field>
|
</Form_Field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user