diff --git a/app/RSpade/Core/Ajax/Ajax_Batch_Controller.php b/app/RSpade/Core/Ajax/Ajax_Batch_Controller.php
index f96936f02..22319174d 100644
--- a/app/RSpade/Core/Ajax/Ajax_Batch_Controller.php
+++ b/app/RSpade/Core/Ajax/Ajax_Batch_Controller.php
@@ -46,20 +46,18 @@ class Ajax_Batch_Controller extends Rsx_Controller_Abstract
\App\RSpade\Core\Debug\Debugger::disable_console_html_output();
// 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([
'error' => 'Missing batch_calls parameter'
], 400);
}
- // Parse batch calls
- $batch_calls = json_decode($batch_calls_json, true);
-
if (!is_array($batch_calls)) {
return response()->json([
- 'error' => 'Invalid batch_calls format - must be JSON array'
+ 'error' => 'Invalid batch_calls format - must be array'
], 400);
}
diff --git a/app/RSpade/Core/Js/Ajax.js b/app/RSpade/Core/Js/Ajax.js
index 26896a855..6ab0735c1 100755
--- a/app/RSpade/Core/Js/Ajax.js
+++ b/app/RSpade/Core/Js/Ajax.js
@@ -195,7 +195,8 @@ class Ajax {
$.ajax({
url: url,
method: 'POST',
- data: params,
+ contentType: 'application/json',
+ data: JSON.stringify(params),
dataType: 'json',
__local_integration: true, // Bypass $.ajax override
success: (response) => {
@@ -364,7 +365,8 @@ class Ajax {
const response = await $.ajax({
url: '/_ajax/_batch',
method: 'POST',
- data: { batch_calls: JSON.stringify(calls_to_send) },
+ contentType: 'application/json',
+ data: JSON.stringify({ batch_calls: calls_to_send }),
dataType: 'json',
__local_integration: true, // Bypass $.ajax override
});
diff --git a/app/RSpade/man/crud.txt b/app/RSpade/man/crud.txt
index be47a8ed9..4da4d21b4 100755
--- a/app/RSpade/man/crud.txt
+++ b/app/RSpade/man/crud.txt
@@ -455,12 +455,12 @@ EDIT PAGE (ADD/EDIT COMBINED)
<% } %>
-
-
+
+
-
- " />
+
+ " />
@@ -479,11 +479,11 @@ RSX_FORM
$method - Ajax endpoint method name
Form Fields
-
-
+
+
- The $name must match:
+ The $name on the input component must match:
- The key in $data JSON
- The key in server-side $params
- The key in validation $errors array
diff --git a/app/RSpade/man/datetime_inputs.txt b/app/RSpade/man/datetime_inputs.txt
index 44b7d160a..9bdd90ec8 100755
--- a/app/RSpade/man/datetime_inputs.txt
+++ b/app/RSpade/man/datetime_inputs.txt
@@ -5,8 +5,8 @@ NAME
SYNOPSIS
Client-side (template):
-
-
+
+
Server-side:
@@ -42,8 +42,8 @@ DESCRIPTION
Schedule_Input combines all scheduling fields into one component:
-
-
+
+
Submits as JSON:
@@ -90,8 +90,8 @@ SCHEDULE_INPUT COMPONENT
Template Usage
Basic usage:
-
-
+
+
Without timezone picker:
@@ -334,12 +334,12 @@ COMPLETE EXAMPLE
Template
-
-
+
+
-
-
+
+
diff --git a/app/RSpade/man/form_conventions.txt b/app/RSpade/man/form_conventions.txt
index eac65d8de..1df88dfee 100755
--- a/app/RSpade/man/form_conventions.txt
+++ b/app/RSpade/man/form_conventions.txt
@@ -116,16 +116,16 @@ TEMPLATE PATTERN
<% } %>
-
-
+
+
-
-
+
+
-
-
+
@@ -350,7 +350,8 @@ COMMON MISTAKES
this.data.form_data = { name: 'Test' };
// Template uses 'title' - VALUE WILL BE EMPTY
-
+
+
SEE ALSO
forms_and_widgets(3), jqhtml(3), ajax(3)
diff --git a/app/RSpade/man/forms_and_widgets.txt b/app/RSpade/man/forms_and_widgets.txt
index ee00eede6..340242b3f 100755
--- a/app/RSpade/man/forms_and_widgets.txt
+++ b/app/RSpade/man/forms_and_widgets.txt
@@ -8,12 +8,12 @@ SYNOPSIS
-
-
+
+
-
-
+
+
@@ -69,12 +69,12 @@ RSX_FORM COMPONENT
Example - Basic Form:
-
-
+
+
-
-
+
+
@@ -119,39 +119,38 @@ FORM_FIELD WRAPPER
Responsibilities:
- 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
- Provide consistent spacing and styling
Example - Basic Field:
-
-
+
+
Example - Required Field with Help Text:
-
-
+
Example - Field with HTML in Label:
-