Cool Tricks: Inline GraphQL Scripts
You can provide a GraphQL document string in your markup. The declarative query, mutation, and subscription components all come with this built in. By appending or updating a GraphQL script child, the Apollo element will read it's query document.
Add it to your custom components via the graphql-script-child-mixin
.
Example
Say you had a <greet-me>
element which extends ApolloQuery
.
<apollo-query>
<script type="application/graphql">
query Greeting {
greeting {
name
greeting
}
}
</script>
<template>
<p>
{{ data.greeting || 'Hello' }},
{{ data.name || 'friend' }}
</p>
</template>
</apollo-query>
import { ApolloQueryMixin, GraphQLScriptChildMixin } from '@apollo-elements/mixins';
interface Data {
name: string;
greeting: string;
}
const template = document.createElement('template');
template.innerHTML = `<p></p>`;
template.content.querySelector('p').append(new Text('Hello'));
template.content.querySelector('p').append(new Text(', '));
template.content.querySelector('p').append(new Text('friend'));
class GreetMe extends GraphQLScriptChildMixin(ApolloQueryMixin(HTMLElement))<Data, null> {
#data: Data = null;
get data() {
return this.#data;
}
set data(value: Data) {
this.#data = value;
this.render();
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.append(template.content.cloneNode(true));
}
render() {
const [greetingNode, , nameNode] =
this.shadowRoot.querySelector('p').childNodes;
greetingNode.data = this.data?.greeting ?? 'Hello';
nameNode.data = this.data?.name ?? 'friend';
}
}
customElements.define('greet-me', GreetMe);
import { ApolloQuery, customElement, html } from '@apollo-elements/lit-apollo';
import { GraphQLScriptChildMixin } from '@apollo-elements/mixins';
interface Data {
name: string;
greeting: string;
}
@customElement('greet-me')
class GreetMe extends GraphQLScriptChildMixin(ApolloQuery)<typeof HelloQuery> {
render() {
return html`
<p>
${this.data?.greeting ?? 'Hello'},
${this.data?.name ?? 'friend'}
</p>
`;
}
}
import { customElement, html, ViewTemplate } from '@microsoft/fast-element';
import { ApolloQuery } from '@apollo-elements/fast/bases/apollo-query';
import { GraphQLScriptChildMixin } from '@apollo-elements/mixins';
const template: ViewTemplate<GreetMe> = html`
<p>
${x => x.data?.greeting ?? 'Hello'},
${x => x.data?.name ?? 'friend'}
</p>
`;
@customElement({ name, 'greet-me', template })
class GreetMe extends GraphQLScriptChildMixin(ApolloQuery)<typeof HelloQuery> { }
import { useEffect, useQuery, component, html } from '@apollo-elements/haunted';
import { GraphQLScriptChildMixin } from '@apollo-elements/mixins';
function GreetMe(hostElement) {
// NOTE: must pass `hostElement: this` to use `<apollo-client>`
const query = useQuery(null, { hostElement });
// When GraphQLScriptChildMixin resolves the query and variables,
// set them on the query controller to start the query
useEffect(() => { query.variables = hostElement.variables }, [hostElement.variables]);
useEffect(() => { query.query = hostElement.document }, [hostElement.document]);
return html`
<p>
${query.data?.greeting ?? 'Hello'},
${query.data?.name ?? 'friend'}
</p>
`;
}
customElements.define('greet-me', GraphQLScriptChildMixin(component(GreetMe)));
import { useEffect, useQuery, useHost, c } from '@apollo-elements/atomico';
import { GraphQLScriptChildMixin } from '@apollo-elements/mixins';
function GreetMe(props) {
const ref = useHost();
// NOTE: must pass `hostElement` to use `<apollo-client>`
const query = useQuery(null, { hostElement: ref.current });
// When GraphQLScriptChildMixin resolves the query and variables,
// set them on the query controller to start the query
useEffect(() => { query.variables = props.variables }, [props.variables]);
useEffect(() => { query.query = props.document }, [props.document]);
return (
<host shadowDom>
<p>
{query.data?.greeting ?? 'Hello'},
{query.data?.name ?? 'friend'}
</p>
</host>
);
}
customElements.define('greet-me', GraphQLScriptChildMixin(c(GreetMe)));
// while you can't use the mixin, you can roll your own
import { query, define, html } from '@apollo-elements/hybrids';
import { gql } from '@apollo/client/core';
function matchNode(host, node) {
if (!(node instanceof HTMLScriptElement))
return; /* c8 ignore next */ // it's covered
if (node.matches('[type="application/graphql"]'))
host.query.document = gql(node.textContent);
if (node.matches('[type="application/json"]'))
host.query.variables = JSON.parse(node.textContent);
}
define('greet-me', {
query: query(HelloQuery),
_domQuery: {
connect(host) {
const mo = new MutationObserver(records => {
for (const { target: node, addedNodes = [] } of records) {
matchNode(host, node);
for (const added of addedNodes)
matchNode(host, added);
}
});
mo.observe(host, { characterData: true, childList: true, subtree: true });
return () => mo.disconnect();
}
}
render: ({ query }) => html`
<p>${query.data?.greeting ?? 'Hello'}, ${query.data?.name ?? 'friend'}</p>
`
})
You can add it to your page like so, and it will start querying.
<greet-me>
<script type="application/graphql">
query Greeting {
greeting {
name
greeting
}
}
</script>
</greet-me>