Skip to content

Confirm before deleting ​

Task: ask "are you sure?" before deleting, without JavaScript.

yaml
# Recipe: ask before deleting, with a page of its own and no JavaScript.
paths:
  components: ./components
  migrations: ./migrations

datasources:
  db:
    driver: sqlite
    database: ./data/contacts.db
sql
CREATE TABLE contacts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL
);

INSERT INTO contacts (name) VALUES ('Ana'), ('Bruno');

The list has a link, not a button. Opening a link only reads, so it can only ask:

xml
<q:component name="Contacts">
  <q:query name="contacts" datasource="db">
    SELECT id, name FROM contacts ORDER BY name
  </q:query>

  <ui:window title="Contacts">
    <q:if condition="flash">
      <ui:alert variant="success">{flash}</ui:alert>
    </q:if>
    <q:loop query="contacts">
      <ui:hbox gap="sm">
        <ui:text>{contacts.name}</ui:text>
        <!-- A link, not a button: opening it only asks. -->
        <ui:link to="/delete/{contacts.id}">Delete</ui:link>
      </ui:hbox>
    </q:loop>
  </ui:window>
</q:component>

The question is a page of its own, components/delete/[id].q. Its button posts to the remove action, which deletes and goes back to the list. If the contact is already gone (a second tab, a reload), the page says so instead of asking.

xml
<q:component name="ConfirmDelete">
  <q:action name="remove" method="POST">
    <q:param name="id" type="integer" required="true" />
    <q:query name="removed" datasource="db">
      DELETE FROM contacts WHERE id = :id
      <q:param name="id" value="{id}" type="integer" />
    </q:query>
    <q:redirect url="/" flash="Deleted." />
  </q:action>

  <q:query name="contact" datasource="db">
    SELECT id, name FROM contacts WHERE id = :id
    <q:param name="id" value="{id}" type="integer" />
  </q:query>

  <ui:window title="Delete a contact">
    <q:if condition="contact_result.recordCount == 0">
      <ui:text>That contact is already gone.</ui:text>
    </q:if>
    <q:else>
      <ui:text>Delete {contact.name}? This cannot be undone.</ui:text>
      <ui:hbox gap="sm">
        <ui:button on-click="remove" with="id={contact.id}" variant="danger">Yes, delete</ui:button>
        <ui:link to="/">Cancel</ui:link>
      </ui:hbox>
    </q:else>
  </ui:window>
</q:component>
xml
<q:test name="opening the link only asks" page="/delete/1">
  <test:visit />
  <test:expect text="Delete Ana? This cannot be undone." />
  <test:expect table="contacts" count="2" />
</q:test>

<q:test name="yes deletes that contact and goes back to the list" page="/delete/1">
  <test:submit action="remove" id="1" />
  <test:expect redirect="/" flash="Deleted." />
  <test:expect table="contacts" count="0" where="name = 'Ana'" />
  <test:expect no-text="Ana" />
  <test:expect text="Bruno" />
</q:test>

<q:test name="a contact already deleted says so" page="/delete/9">
  <test:visit />
  <test:expect text="That contact is already gone." />
  <test:expect no-text="Yes, delete" />
</q:test>
text
tests/delete.test.q
  PASS  opening the link only asks
  PASS  yes deletes that contact and goes back to the list
  PASS  a contact already deleted says so
3 passed, 0 failed

MIT Licensed · Built with VitePress