-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhttp%3A%2F%2Fhelp.metaphacts.com%2Fresource%2FComponentTutorial.html
219 lines (189 loc) · 9.06 KB
/
http%3A%2F%2Fhelp.metaphacts.com%2Fresource%2FComponentTutorial.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
<div class="metaphacts_help">
<ol class="breadcrumb" style="background:white;border:none;padding-left:0px;">
<li>
<semantic-link title="Help" uri="http://help.metaphacts.com/resource/Start">Help</semantic-link>
</li>
<li>
<semantic-link title="Documentation" uri="http://help.metaphacts.com/resource/DocumentationOverview">Documentation</semantic-link>
</li>
<li class="active">Simple Component Tutorial</li>
</ol>
<h1> Simple Component Tutorial </h1>
<h2> Hello World Component </h2>
The goal is to create the most simple "Hello World!"-like component.
<p>First, we need to create the JavaScript implementation for our new component. Put the code below into platform-web/src/main/common/ts/components/HelloWorldComponent.ts file. If this is your first encounter with React.js we recommend first to read <a href="https://facebook.github.io/react/docs/tutorial.html">React Getting Started</a>.
</p>
<pre>
<code mode='application/typescript'>
import {DOM as D, Component, createFactory} from 'react';
// React's component properties interface
interface HelloWorldComponentProps {
name: string
}
interface HelloWorldComponentState {
addition: string
}
class HelloWorldComponent extends Component<HelloWorldComponentProps, HelloWorldComponentState> {
constructor(props: HelloWorldComponentProps) {
super(props);
this.state = {
addition: '',
};
}
render() {
return D.div(
{},
D.div(
{},
`Hello ${this.props.name}! ${this.state.addition}`
),
D.input(
{
onChange: this.onAdditionChange,
}
)
);
}
private onAdditionChange = (event) : void => {
this.setState({
addition: event.target.value,
});
}
}
// register HelloWorldComponent as the default export for this source file
export type component = HelloWorldComponent;
export const component = HelloWorldComponent;
export const factory = createFactory(component);
export default component;
</code>
</pre>
<p>
Now, we have to define our custom HTML tag that would display this component on the web page. Supposedly, we want to use the tag <code>my-hello-world-component</code> for that. Then, we need to open the file platform-web/component.json. It defines a map that links the name of the custom tag with the source script file, specifically, with default exported class from this file (note the <code>export</code> statements at the end of our source file). Here we need to register the link between our tag name and the source file by adding a line to the map:
</p>
<pre>
<code>
...
"my-hello-world-component": "./src/main/common/ts/components/HelloWorldComponent.ts",
...
</code>
</pre>
<p>Let's try to embed our new component into some page. Go to a new page, for example, <semantic-link title="HelloWorld" uri="[[resolvePrefix ":HelloWorld"]]">HelloWorld</semantic-link> and edit the page by clicking on the edit button. Copy and paste the component definition below into the page and save the page.</p>
<mp-code-example show-code='true'>
<my-hello-world-component name='World'></my-hello-world-component>
</mp-code-example>
<h2> Gallery Component </h2>
Let's create a component which retrieves some entities from the triplestore and visualize them in a simple, floating grid. For this, please, first load the pre-requisite data as described <semantic-link title="Basic Tutorial" uri="[[resolvePrefix "Help:Tutorial"]]">here</semantic-link>.
<div style="color:red;font-weight: bold; ">
[[#if (ask "ASK { <http://example.org/bob#me> a foaf:Person }") ]]
Check: It seems that you have already correctly loaded the sample data.
[[else]]
Check: It seems that you have not yet loaded the sample data.
[[/if]]
</div>
<p>As before, the first step involves creating a TypeScript file implementing the behaviour of our component and saving it as platform-web/src/main/common/ts/components/GalleryComponent.ts.</p>
<p></p>
<pre>
<code mode='application/typescript'>
import {DOM as D, Component, createFactory} from 'react';
// safe alternative to null values, similar to Optional in Java 8
import maybe = require('data.maybe');
// imports select query function from SparqlClient
import {SparqlClient} from 'platform/api/sparql';
// imports helper component which can render HTML Handlebars.js templates.
import TemplateItem from '../../../common/ts/templates/components/TemplateItem';
// Now we want to use a complex configuration with two parameters
interface GalleryComponentProps {
query: string
tupleTemplate: string
}
interface GalleryComponentState {
queryResult: Data.Maybe<SparqlClient.SparqlSelectResult>
}
class GalleryComponent extends Component<GalleryComponentProps, GalleryComponentState> {
constructor(props: GalleryComponentProps) {
super(props);
this.state = {
queryResult: maybe.Nothing<SparqlClient.SparqlSelectResult>(),
};
}
// this function is called by React when component is mounted to the DOM.
componentDidMount() {
// evaluate asynchronous sparql select query
SparqlClient.select(this.props.query).onValue(
res => this.setState({
queryResult: maybe.Just(res),
})
);
}
render() {
return this.state.queryResult.map(
res =>
D.div(
{},
this.createTuplesHtml(
res, this.props.tupleTemplate
), D.div({ style: { clear: 'both' } })
)
).getOrElse(
D.div({}, 'Loading the data ...')
);
}
private createTuplesHtml(queryResult: SparqlClient.SparqlSelectResult, template: string) {
return _.map(
queryResult.results.bindings,
tuple => TemplateItem({
template: {
source: template,
options: tuple,
},
component: D.div,
})
);
}
}
export type component = GalleryComponent;
export const component = GalleryComponent;
export const factory = createFactory(component);
export default component;
</code>
</pre>
Now, we need to register the tag <code>gallery-component</code> and associate it with our TypeScript file.
<pre>
<code>
...
"gallery-component": "./src/main/common/ts/components/GalleryComponent.ts",
...
</code>
</pre>
To see how our new gallery component looks like, let's add it to our <semantic-link title="HelloWorld" uri="[[resolvePrefix ":HelloWorld"]]">HelloWorld</semantic-link> page:
<mp-code-example show-code='true'>
<gallery-component query='SELECT ?uri ?thumbnail
WHERE {
?uri <http://schema.org/thumbnail> ?thumbnail
}'
tuple-template='<img style="float: left; height: 300px; margin: 10px; border: 1px solid;" src="{{thumbnail.value}}"/>'>
</gallery-component>
</mp-code-example>
<br/>
<p>
Here, we used a SPARQL query to select links to thumbnail images of the data instances from our repository. Then, we render each of these links as an image and display them in a row.
</p>
<h2>Dynamic Query Parameters</h2>
<p>Now let's check how our components can play nicely with the templating mechanism (refer to <semantic-link uri="[[resolvePrefix "Help:TemplateAndApplicationPages"]]">Templates and Application Pages</semantic-link> for more details about the templates concept).</p>
<p>Let's try to apply our new GalleryComponent to the <code>foaf:Person</code> template.
Now we want to show the thumbnail image of the Person on the page of each person.</p>
<p>To do this, just navigate to the template page <a href="/resource/?action=edit&uri=Template%3Ahttp%3A%2F%2Fxmlns.com%2Ffoaf%2F0.1%2FPerson">Template:foaf:Person</a> and copy/paste to add the component definition from below.
<pre>
<code>
<gallery-component query='SELECT ?label ?thumbnail
WHERE {
?? rdfs:label ?label;
<http://schema.org/thumbnail> ?thumbnail
}'
tuple-template='<b>{{label.value}}</b><img style="float: left; height: 300px; margin: 10px; border: 1px solid;" src="{{thumbnail.value}}"/>'>
</gallery-component>
</code>
</pre>
To see your component in action, try to navigate to a page of some Person having a thumbnail image, e.g., in our case, <semantic-link uri="http://example.org/bob#me">bob#me</semantic-link>.
The most interesting part of the component configuration from above is dynamic query parameter - ??. At runtime, this parameter will be bound to the selected resource. E.g., if you navigate to the <code>bob#me</code> page, ?? will be substituted with the <code><http://example.org/bob#me></code> URI.
</div>