Skip to content

Commit

Permalink
Add x-headers and $ajax headers option (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
imacrayon authored Feb 9, 2024
1 parent e2cd8e3 commit 5976933
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 6 deletions.
18 changes: 17 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function Ajax(Alpine) {
window.location.reload(true)
})

Alpine.directive('target', (el, { modifiers, expression }, { cleanup }) => {
Alpine.directive('target', (el, { modifiers, expression }, { evaluate, cleanup }) => {
let config = {
targets: parseIds(el, expression),
events: true,
Expand All @@ -25,6 +25,8 @@ function Ajax(Alpine) {

sendConfig.set(el, config)

config.headers = evaluate(Alpine.bound(el, 'x-headers', '{}'))

if (isLocalLink(el)) {
cleanup(listenForNavigate(el, config))
} else if (isForm(el)) {
Expand Down Expand Up @@ -62,10 +64,18 @@ function Ajax(Alpine) {
}
}

let headers = options.headers
if (!headers) {
headers = el.hasAttribute('x-headers')
? Alpine.evaluate(el, Alpine.bound(el, 'x-headers', '{}'))
: {}
}

let request = {
action,
method,
body,
headers,
referrer: source(el),
}

Expand Down Expand Up @@ -141,6 +151,7 @@ function listenForNavigate(el, config) {
event.stopPropagation()

let request = navigateRequest(el)
request.headers = config.headers || {}
let targets = addSyncTargets(findTargets(config.targets))

try {
Expand Down Expand Up @@ -180,6 +191,7 @@ function listenForSubmit(el, config) {
event.stopPropagation()

let request = formRequest(el, event.submitter)
request.headers = config.headers || {}
let targets = addSyncTargets(findTargets(config.targets))

try {
Expand Down Expand Up @@ -268,10 +280,14 @@ async function render(request, targets, el, config) {

if (!dispatch(el, 'ajax:before')) return

let targetIds = []
targets.forEach(target => {
target.setAttribute('aria-busy', 'true')
targetIds.push(target.id)
})

request.headers['X-Alpine-Request'] = 'true'
request.headers['X-Alpine-Target'] = targetIds.join(' ')
let response = await send(request, config.followRedirects)

if (response.ok) {
Expand Down
4 changes: 2 additions & 2 deletions src/send.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
let jobs = {}

export async function send({ method, action, body, referrer }, followRedirects) {
export async function send({ method, action, body, referrer, headers }, followRedirects) {
// When duplicate `GET` requests are issued we'll proxy
// the initial request to save network roundtrips.
let proxy
Expand All @@ -19,7 +19,7 @@ export async function send({ method, action, body, referrer }, followRedirects)
referrer = referrer || window.location.href

let response = fetch(action, {
headers: { 'X-Alpine-Request': 'true' },
headers,
referrer,
method,
body,
Expand Down
29 changes: 29 additions & 0 deletions tests/ajax.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,35 @@ test('GET request data is added to the URL',
}
)

test('custom headers can be set through options',
html`<button type="button" id="replace" x-init @click="$ajax('/tests', {
method: 'POST',
headers: { 'X-Test': 'test' }
})"></button>`,
({ intercept, get, wait }) => {
intercept('POST', '/tests', {
statusCode: 200,
body: '<h1 id="title">Success</h1><div id="replace">Replaced</div>'
}).as('response')
get('button').click()
wait('@response').its('request.headers').should('have.property', 'x-test', 'test')
}
)

test('[x-headers] can set custom headers',
html`<button type="button" id="replace" x-init x-headers="{ 'X-Test': 'test' }" @click="$ajax('/tests', {
method: 'POST',
})"></button>`,
({ intercept, get, wait }) => {
intercept('POST', '/tests', {
statusCode: 200,
body: '<h1 id="title">Success</h1><div id="replace">Replaced</div>'
}).as('response')
get('button').click()
wait('@response').its('request.headers').should('have.property', 'x-test', 'test')
}
)

test('follows redirects by default',
html`<button type="button" id="replace" x-init @click="$ajax('/tests', {
method: 'POST',
Expand Down
18 changes: 15 additions & 3 deletions tests/form.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,19 @@ test('[x-target] handles extra whitespace',
}
)

test('ajax:before event is fired',
test('[x-headers] sets request headers',
html`<form x-init x-target x-headers="{ 'x-test': 'test' }" id="replace" method="post"><button></button></form>`,
({ intercept, get, wait }) => {
intercept('POST', '/tests', {
statusCode: 200,
body: '<h1 id="title">Success</h1><div id="replace">Replaced</div>'
}).as('response')
get('button').click()
wait('@response').its('request.headers').should('have.property', 'x-test', 'test')
}
)

test('[ajax:before] event is fired',
html`<p id="before">CHANGE ME</p><form x-init x-target id="replace" @ajax:before="document.getElementById('before').textContent = 'Changed'" method="post" action="/tests"><button></button></form>`,
({ intercept, get, wait }) => {
intercept('POST', '/tests', {
Expand All @@ -185,7 +197,7 @@ test('ajax:before event is fired',
}
)

test('ajax:before can cancel AJAX requests',
test('[ajax:before] can cancel AJAX requests',
html`<h1 id="title">Replace me</h1><form x-init x-target="title" @ajax:before="$event.preventDefault()" method="post" action="/tests"><button></button></form>`,
({ intercept, get, wait }) => {
cy.on('fail', (error, runnable) => {
Expand All @@ -204,7 +216,7 @@ test('ajax:before can cancel AJAX requests',
}
)

test('formnoajax can cancel AJAX requests',
test('[formnoajax] can cancel AJAX requests',
html`<h1 id="title">Replace me</h1><form x-init x-target="title" method="post" action="/tests"><button formnoajax></button></form>`,
({ intercept, get, wait }) => {
cy.on('fail', (error, runnable) => {
Expand Down
12 changes: 12 additions & 0 deletions tests/link.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,15 @@ test('target can be set in attribute',
})
}
)

test('[x-headers] sets request headers',
html`<div id="replace"></div><a href="/tests" x-init x-target="replace" x-headers="() => ({ 'x-test': 'te' + 'st' })">Link</a>`,
({ intercept, get, wait }) => {
intercept('GET', '/tests', {
statusCode: 200,
body: '<h1 id="title">Success</h1><div id="replace">Replaced</div>'
}).as('response')
get('a').click()
wait('@response').its('request.headers').should('have.property', 'x-test', 'test')
}
)

0 comments on commit 5976933

Please sign in to comment.