Skip to content

Instantly share code, notes, and snippets.

@wvbe
Last active May 24, 2019 09:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wvbe/d38a6ac8a374c546ea16ae98db25d8ff to your computer and use it in GitHub Desktop.
Save wvbe/d38a6ac8a374c546ea16ae98db25d8ff to your computer and use it in GitHub Desktop.
A React hook for Fonto applications that makes it easy to build a (metadata) form for an XML subtree
/**
* This is an example of how the `useXQueryDataBinding` hook can be implemented for a simple form field (in this case the
* FDS `TextInput` component.
* The readQuery argument to `useXQueryDataBinding` returns a format (string) that is useful for the TextInput. I
* another case you might choose to return an XPath `map` or `array` instead and distribute that over multiple or more
* complex form components.
*
* The writeQuery argument is given the `$data('value')` XPath variable, which is whatever `TextInput` returns in its
* `onChange` callback - for this component, that is also a string.
*/
import React from 'react';
import {
FormRow,
TextInput
} from 'fds/components';
import useXQueryDataBinding from './useXQueryDataBinding.js';
export default function ExampleMetadataTextInput ({ contextNodeId }) {
const [value, setValue] = useXQueryDataBinding(
contextNodeId,
`./meta/doi/string()`,
`replace value of node $data('contextNode')/meta/doi with $data('value')`);
return <FormRow label="Digital object identifier" labelPosition='before'>
<TextInput
value={ value }
onChange={setValue}
/>
</FormRow>;
}
import { useState, useEffect } from 'react';
import documentsManager from 'fontoxml-documents/src/documentsManager.js';
import evaluateXPath from 'fontoxml-selectors/src/evaluateXPath.js';
import operationsManager from 'fontoxml-operations/src/operationsManager.js';
import readOnlyBlueprint from 'fontoxml-blueprints/src/readOnlyBlueprint.js';
function getValue(contextNodeId, readQuery) {
return evaluateXPath(readQuery, documentsManager.getNodeById(contextNodeId), readOnlyBlueprint);
}
export default function useXQueryDataBinding(contextNodeId, readQuery, writeQuery) {
const [value, setValue] = useState(getValue(contextNodeId, readQuery));
// Whenever the `contextNodeId` prop changes, update state with the new value:
useEffect(() => {
setValue(getValue(contextNodeId, readQuery));
}, [contextNodeId]);
return [
value,
function setXQueryDataBindingValue (value) {
// Update React state
setValue(value);
// Update XML document using the `execute-update-script` operation. The React state is made available
// as XQuery variable `$data('value')`.
operationsManager
.executeOperation('execute-update-script', {
contextNodeId,
expression: writeQuery,
value
})
.catch(error => {
console.warn('Could not update', error.message, value, contextNodeId, writeQuery);
});
}
];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment