Fix DataStar v1 RC8 signal attribute incompatibilities
Two bugs that caused signals to not work on the frontend: 1. data-on-signal-change → data-on-signal-patch The data-on-signal-change attribute was removed in RC8. The replacement is data-on-signal-patch. 2. data-bind-newTodo="" → data-bind="newTodo" HTML normalises attribute names to lowercase at parse time, so data-bind-newTodo becomes data-bind-newtodo in the DOM. DataStar would then bind to signal $newtodo instead of $newTodo, breaking the two-way binding. The value syntax data-bind="newTodo" preserves the camelCase name correctly. https://claude.ai/code/session_01JThiQbp3Bn9J1VhBpRuz4u
This commit is contained in:
@@ -42,7 +42,8 @@ pub fn router(state: SharedState) -> Router {
|
|||||||
///
|
///
|
||||||
/// DataStar v1 contract (verified against https://data-star.dev/reference):
|
/// DataStar v1 contract (verified against https://data-star.dev/reference):
|
||||||
/// - `data-signals` — initialize signals (JS object literal syntax)
|
/// - `data-signals` — initialize signals (JS object literal syntax)
|
||||||
/// - `data-on-signal-change` — fires when any signal changes
|
/// - `data-on-signal-patch` — fires when any signal is patched (renamed from
|
||||||
|
/// `data-on-signal-change` which was removed in RC8)
|
||||||
/// - `__debounce.300ms` — modifier: debounce 300ms
|
/// - `__debounce.300ms` — modifier: debounce 300ms
|
||||||
/// - `@post('/render')` — send all non-_ signals as JSON body
|
/// - `@post('/render')` — send all non-_ signals as JSON body
|
||||||
/// - `@get('/sse?conn=...')` — open long-lived SSE pipe
|
/// - `@get('/sse?conn=...')` — open long-lived SSE pipe
|
||||||
@@ -70,7 +71,7 @@ fn document_shell(conn_id: Uuid, initial_signals: &str, inner_html: &str) -> Str
|
|||||||
<body>
|
<body>
|
||||||
<div id="app"
|
<div id="app"
|
||||||
data-signals='{signals}'
|
data-signals='{signals}'
|
||||||
data-on-signal-change__debounce.300ms="@post('/render')"
|
data-on-signal-patch__debounce.300ms="@post('/render')"
|
||||||
data-on-load="@get('/sse?conn={conn}')">
|
data-on-load="@get('/sse?conn={conn}')">
|
||||||
{inner}
|
{inner}
|
||||||
</div>
|
</div>
|
||||||
@@ -210,7 +211,7 @@ async fn initial_about_load(State(state): State<SharedState>) -> impl IntoRespon
|
|||||||
/// `POST /render` — Signal-triggered rerender.
|
/// `POST /render` — Signal-triggered rerender.
|
||||||
///
|
///
|
||||||
/// DataStar sends all non-`_` signals as JSON body when any signal changes
|
/// DataStar sends all non-`_` signals as JSON body when any signal changes
|
||||||
/// (triggered by `data-on-signal-change` + `@post('/render')`).
|
/// (triggered by `data-on-signal-patch` + `@post('/render')`).
|
||||||
///
|
///
|
||||||
/// Returns `Content-Type: text/event-stream` with a single
|
/// Returns `Content-Type: text/event-stream` with a single
|
||||||
/// `datastar-patch-elements` event containing the full page HTML.
|
/// `datastar-patch-elements` event containing the full page HTML.
|
||||||
|
|||||||
@@ -40,13 +40,15 @@ pub async fn todo_list(cx: &mut RenderContext) -> anyhow::Result<Markup> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add todo form.
|
// Add todo form.
|
||||||
// data-bind-newTodo binds the input to the $newTodo signal.
|
// data-bind="newTodo" binds the input to the $newTodo signal.
|
||||||
// The button uses new_todo.val ("$newTodo") in a DataStar expression.
|
// Value syntax is used instead of data-bind-newTodo because HTML
|
||||||
|
// normalises attribute names to lowercase, which would corrupt the
|
||||||
|
// camelCase signal name (newTodo → newtodo).
|
||||||
div.add-form {
|
div.add-form {
|
||||||
input
|
input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="What needs to be done?"
|
placeholder="What needs to be done?"
|
||||||
data-bind-newTodo=""
|
data-bind="newTodo"
|
||||||
;
|
;
|
||||||
button
|
button
|
||||||
data-on-click="@post('/action/add_todo')"
|
data-on-click="@post('/action/add_todo')"
|
||||||
|
|||||||
Reference in New Issue
Block a user