I have a backend service that can be called using http://localhost:7070/search?q=someterm
and I'm trying to implement a frontend using Solidjs. I used their documentation and examples to come up with this very simple, working component:
import { Component, createResource, createSignal } from 'solid-js';
const searchQuery = async (text: any) =>
(await fetch(`http://localhost:7070/search\?q=${text}`)).json();
const [query, setSearchQuery] = createSignal();
const [queryResponse] = createResource(query, searchQuery);
const Search: Component = () => {
return (
<div>
<div>
<label for="query"></label>
<input id="query" onInput={(e) => setSearchQuery(e.currentTarget.value)} />
</div>
<span>{queryResponse.loading && "Loading..."}</span>
<div>
<pre>{JSON.stringify(queryResponse(), null, 2)}</pre>
</div>
<button type="submit" >Search</button>
</div>
)
}
export default Search;
The query does work and I can see the JSON response in the correct div
. However, the search occurs as I am typing due to the onInput
. I want to only active the query via clicking the button, which has proven to be a lot more difficult that I anticipated.
Looking through several tutorials, I attempted to separate out my code into a useSearch.ts
. I created a full type for the query. Even though it only contains a single text field right now, I do anticipate adding several other query parameters. This is my attempt at a useSearch.ts
:
import { createSignal, createResource } from "solid-js";
import { createStore } from "solid-js/store";
import { render } from "solid-js/web";
export type SearchResponse = {
id: string;
createdAt: string;
uri: string;
content: string;
};
export type SearchRequest = {
text: string;
};
const useSearch = () => {
const searchQuery = async (text: String) =>
(await fetch(`http://localhost:7070/search\?q=${text}`)).json();
const runSearch = async (req: SearchRequest) => {
// should be submitting your form to some backend service
console.log(`submitting ${req.text}`);
const res = await searchQuery(req.text);
setQueryResponse(res);
};
const [query, setQuery] = createStore<SearchRequest>({
text: ""
});
const [queryResponse, setQueryResponse] = createSignal([]);
const updateSearchField = (fieldName: string) => (event: Event) => {
const inputElement = event.currentTarget as HTMLInputElement;
if (inputElement.type === "checkbox") {
setQuery({
[fieldName]: !!inputElement.checked
});
} else {
setQuery({
[fieldName]: inputElement.value
});
}
}
return { query, runSearch, updateSearchField, queryResponse }
}
export { useSearch }
and My component calls it here:
import { Component, createResource, createSignal } from 'solid-js';
import { createStore } from "solid-js/store";
import { useSearch } from './useSearch';
const Search: Component = () => {
const { query, runSearch, updateSearchField, queryResponse } = useSearch();
const handleSubmit = (event: Event): void => {
event.preventDefault();
runSearch(query);
};
return (
<form onSubmit={handleSubmit}>
<div>
<label for="query"></label>
<input id="query" onInput={(e) => updateSearchField("queryString")} />
</div>
<div>
<pre>{JSON.stringify(queryResponse(), null, 2)}</pre>
</div>
<button type="submit" onclick={() => runSearch}>Search</button>
</form>
)
}
export default Search;
I see the submitting
entry in the browser console/logs, but I don't get a response. I realize I've got a lot of issues here (like how I should be correctly URL encoding the query parameters), but I just want to get the basics of submitting a call to my service via the button and displaying the results. My questions:
solidjs
.Here is my solution. It adds support for search being passed in by query parameters as well.
import { useSearchParams } from '@solidjs/router';
import { Component, Show, createSignal, onMount } from 'solid-js';
const searchQuery = async (text: string) =>
(await fetch(`http://localhost:7070/search\?q=${text}`)).json();
const Search: Component = () => {
const [searchParams, setSearchParams] = useSearchParams<{ q: string }>();
const [query, setSearchQuery] = createSignal(searchParams.q);
const [queryResponse, setQueryResponse] = createSignal("");
const [loading, setLoading] = createSignal(false);
const search = async (q: string) => {
setLoading(true)
const queryResult = await searchQuery(q)
setQueryResponse(JSON.stringify(queryResult, null, 2))
setSearchParams({q: q})
setLoading(false)
}
const handleSubmit = async (event: Event) => {
event.preventDefault();
search(query())
};
onMount(async () => {
if(searchParams.q != "") {
search(query())
}
})
return (
<form onSubmit={handleSubmit}>
<div>
<label for="query"></label>
<input id="query" value={query()} onInput={e => setSearchQuery(e.target.value)} />
</div>
<Show when={loading()}>
Loading...
</Show>
<Show when={!loading()}>
<pre>{queryResponse()}</pre>
</Show>
<button type="submit" >Search</button>
</form>
)
}
export default Search;