diff --git a/README.md b/README.md
index b47c08f..1076c37 100644
--- a/README.md
+++ b/README.md
@@ -45,23 +45,12 @@ remote-input[loading] .loading-icon { display: inline; }
### Events
-```js
-const remoteInput = document.querySelector('remote-input')
-
-// Network request lifecycle events.
-remoteInput.addEventListener('loadstart', function(event) {
- console.log('Network request started', event)
-})
-remoteInput.addEventListener('loadend', function(event) {
- console.log('Network request complete', event)
-})
-remoteInput.addEventListener('load', function(event) {
- console.log('Network request succeeded', event)
-})
-remoteInput.addEventListener('error', function(event) {
- console.log('Network request failed', event)
-})
-```
+- `loadstart` - The server fetch has started.
+- `load` - The network request completed successfully.
+- `error` - The network request failed.
+- `loadend` - The network request has completed.
+- `remote-input-success` – Received a successful response (status code 200-299). Bubbles.
+- `remote-input-error` – Received a not successful response. Bubbles.
## Browser support
diff --git a/index.js b/index.js
index 16a1227..45e12d6 100644
--- a/index.js
+++ b/index.js
@@ -70,18 +70,30 @@ async function fetchResults(remoteInput: RemoteInputElement, checkCurrentQuery:
remoteInput.dispatchEvent(new CustomEvent('loadstart'))
remoteInput.setAttribute('loading', '')
+ let response
+ let errored = false
+ let html = ''
try {
- const response = await fetch(url, {
+ response = await fetch(url, {
credentials: 'same-origin',
headers: {accept: 'text/html; fragment'}
})
- const html = await response.text()
+ html = await response.text()
remoteInput.dispatchEvent(new CustomEvent('load'))
- resultsContainer.innerHTML = html
} catch {
+ errored = true
remoteInput.dispatchEvent(new CustomEvent('error'))
}
remoteInput.removeAttribute('loading')
+ if (errored) return
+
+ if (response && response.ok) {
+ remoteInput.dispatchEvent(new CustomEvent('remote-input-success', {bubbles: true}))
+ resultsContainer.innerHTML = html
+ } else {
+ remoteInput.dispatchEvent(new CustomEvent('remote-input-error', {bubbles: true}))
+ }
+
remoteInput.dispatchEvent(new CustomEvent('loadend'))
}
diff --git a/test/karma.config.js b/test/karma.config.js
index edf3501..8c2620a 100644
--- a/test/karma.config.js
+++ b/test/karma.config.js
@@ -1,13 +1,23 @@
function reply(request, response, next) {
if (request.method === 'GET') {
- response.writeHead(200)
- response.end(`
-
- - item
- - item
- - item
-
- `)
+ if (request.url.startsWith('/500')) {
+ response.writeHead(500)
+ response.ok = false
+ response.end('Server error')
+ } else if (request.url.startsWith('/network-error')) {
+ request.destroy(new Error())
+ response.end()
+ } else {
+ response.writeHead(200)
+ response.ok = true
+ response.end(`
+
+ - item
+ - item
+ - item
+
+ `)
+ }
return
}
next()
diff --git a/test/test.js b/test/test.js
index 00b6ef0..81b2e79 100644
--- a/test/test.js
+++ b/test/test.js
@@ -30,7 +30,12 @@ describe('remote-input', function() {
const input = document.querySelector('input')
const results = document.querySelector('#results')
assert.equal(results.innerHTML, '')
+ let successEvent = false
+ remoteInput.addEventListener('remote-input-success', function() {
+ successEvent = true
+ })
remoteInput.addEventListener('loadend', function() {
+ assert.ok(successEvent, 'success event happened')
assert.equal(results.querySelector('ol').getAttribute('data-src'), '/results?q=test')
done()
})
@@ -38,6 +43,42 @@ describe('remote-input', function() {
input.focus()
})
+ it('handles not ok responses', function(done) {
+ const remoteInput = document.querySelector('remote-input')
+ const input = document.querySelector('input')
+ const results = document.querySelector('#results')
+ remoteInput.src = '/500'
+ assert.equal(results.innerHTML, '')
+ let errorEvent = false
+ remoteInput.addEventListener('remote-input-error', function() {
+ errorEvent = true
+ })
+ remoteInput.addEventListener('loadend', function() {
+ assert.ok(errorEvent, 'error event happened')
+ assert.equal(results.innerHTML, '', 'nothing was appended')
+ done()
+ })
+ input.value = 'test'
+ input.focus()
+ })
+
+ it('handles network error', function(done) {
+ const remoteInput = document.querySelector('remote-input')
+ const input = document.querySelector('input')
+ const results = document.querySelector('#results')
+ remoteInput.src = '/network-error'
+ assert.equal(results.innerHTML, '')
+ remoteInput.addEventListener('error', async function() {
+ await Promise.resolve()
+ assert.equal(results.innerHTML, '', 'nothing was appended')
+ assert.notOk(remoteInput.hasAttribute('loading'), 'loading attribute was removed')
+ done()
+ })
+ input.value = 'test'
+ input.focus()
+ assert.ok(remoteInput.hasAttribute('loading'), 'loading attribute was added')
+ })
+
it('repects param attribute', function(done) {
const remoteInput = document.querySelector('remote-input')
const input = document.querySelector('input')