Skip to content

Commit c6fb2a7

Browse files
Openblocks-docsgitbook-bot
Openblocks-docs
authored andcommitted
GITBOOK-108: No subject
1 parent 7420adb commit c6fb2a7

File tree

10 files changed

+196
-0
lines changed

10 files changed

+196
-0
lines changed
148 KB
Loading
83.5 KB
Loading
199 KB
Loading
38.2 KB
Loading
107 KB
Loading
95.4 KB
Loading
206 KB
Loading
167 KB
Loading

docs/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
* [List View](build-apps/component-guides/list-view.md)
3838
* [Drawer](build-apps/component-guides/drawer.md)
3939
* [Image](build-apps/component-guides/image.md)
40+
* [Custom component](build-apps/component-guides/custom-component.md)
4041
* [Use Markdown](build-apps/component-guides/use-markdown.md)
4142
* [Module](build-apps/module.md)
4243
* [Navigation](build-apps/navigation.md)
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# Custom component
2+
3+
In Openblocks, you can design custom components using React.js library to satisfy specific needs when building your app. The custom component can be static or dynamic, but either requires coding.
4+
5+
{% hint style="info" %}
6+
If you consider the custom component you are crafting suits general use cases, contact us and we are happy to do coding.
7+
{% endhint %}
8+
9+
## Prerequisites
10+
11+
* Good understanding of how to build an app in Openblocks.
12+
* Familiar with HTML/CSS/JS and the React.js library.
13+
14+
## Basics
15+
16+
Drag a **Custom component** onto the canvas. By default, Openblocks adds a title box, a text box, and two buttons into it, as shown below. You can modify **Data** and **Code** in the **Properties** pane to tailor it according to your requirements.
17+
18+
{% hint style="info" %}
19+
Click the border instead of the inside area to select a **Custom component** and display its property settings.
20+
{% endhint %}
21+
22+
<figure><img src="../../.gitbook/assets/custom-component-1.png" alt=""><figcaption></figcaption></figure>
23+
24+
### Data
25+
26+
**Data** stores information in key-value pairs, providing an interface for the **Custom component** to interact with data outside it. For instance, you can reference data of the **Custom component** in other components in your app via `customComponentName.model`, or pass data from other components to the **Custom component**.
27+
28+
<figure><img src="../../.gitbook/assets/custom-component-2.png" alt=""><figcaption></figcaption></figure>
29+
30+
### Code
31+
32+
By default, Openblocks defines the object `model`, and two functions `runQuery` and `updateModel`.
33+
34+
<figure><img src="../../.gitbook/assets/custom-component-3.png" alt=""><figcaption></figcaption></figure>
35+
36+
* `runQuery` is a function that accepts a query name in string format. For example, `runQuery(model.query)`.
37+
* `updateModel` is a function that accepts a single argument of object type. The argument passed to `updateModel` will be merged with data of the **Custom component**.
38+
39+
## Implementation
40+
41+
All code of your **Custom component**, including HTML, CSS, and JavaScript, stores in the **Code** box in the **Properties** pane. When your app runs, the custom component will be embedded into an [iframe](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe) element.To facilitate the interaction between the **Custom component** and other components in your app, Openblocks offers an API for you through global objects. The type definition and description of the objects are as follows.
42+
43+
```javascript
44+
interface Openblocks {
45+
// Subscribe to data change
46+
// When data changes, handler will be triggered
47+
// The returned value is the unsubscribe function
48+
subscribe(handler: SubscribeHandler): () => void;
49+
// React HOC component function that accepts a React component
50+
// Return a new component that contains properties: runQuery, model, updateModel
51+
connect(Component: ComponentType<any>): ComponentType;
52+
// Run the specified query
53+
runQuery(queryName: string): Promise<void>;
54+
// Update data
55+
updateModel(patch: any): Promise<any>;
56+
}
57+
58+
interface SubscribeHandler {
59+
(data: IDataPayload): void;
60+
}
61+
62+
interface IDataPayload {
63+
model: any;
64+
}
65+
```
66+
67+
The following example is the least code that a custom component requires to work.
68+
69+
```javascript
70+
<div id="react"></div>
71+
<script type="text/babel">
72+
const MyCustomComponent = ({ runQuery, model, updateModel }) => (
73+
<p>Hello, world!</p>
74+
);
75+
const ConnectedComponent = Openblocks.connect(MyCustomComponent);
76+
ReactDOM.render(<ConnectedComponent />,
77+
document.getElementById("react"));
78+
</script>
79+
```
80+
81+
## Data interaction
82+
83+
### Pass data from app to custom component
84+
85+
For instance, to pass the text in an input box to a custom component, you can use the `{{}}` syntax to reference data from this **Text** component. Note that you can also reference data from queries in the same way.
86+
87+
<figure><img src="../../.gitbook/assets/custom-component-5.png" alt=""><figcaption></figcaption></figure>
88+
89+
Below is the code for this example.
90+
91+
```javascript
92+
<div id="root"></div>
93+
94+
<script type="text/babel">
95+
96+
const { Button, Card, Space } = antd;
97+
98+
const MyCustomComponent = ({ runQuery, model, updateModel}) => (
99+
<Card title={"Hello, " + model.name}>
100+
<p>{model.text}</p>
101+
<Space>
102+
<Button
103+
type="primary"
104+
onClick={() => runQuery(model.query)}
105+
>
106+
Trigger query
107+
</Button>
108+
<Button
109+
onClick={() => updateModel({ text: "I'm also in a good mood!" })}
110+
>
111+
Update data
112+
</Button>
113+
</Space>
114+
</Card>
115+
);
116+
117+
const ConnectedComponent = Openblocks.connect(MyCustomComponent);
118+
119+
const root = ReactDOM.createRoot(document.getElementById("root"));
120+
root.render(<ConnectedComponent />);
121+
122+
</script>
123+
```
124+
125+
### Pass data from custom component to app
126+
127+
For instance, to display certain text from the **Custom component** in an **Input** component in the app, you can set the value of `custom1.model.name` as the default value of `input1`. The dot notation `custom1.model.name` accesses the name of the **Custom component**.
128+
129+
<figure><img src="../../.gitbook/assets/custom-component-6.png" alt=""><figcaption></figcaption></figure>
130+
131+
### Trigger query from custom component
132+
133+
For instance, given table `users` which displays information of all users, you want to filter data based on the inputted text in a **Custom component**. Besides, the filter operation is triggered by clicking a button inside the same **Custom component**.
134+
135+
<figure><img src="../../.gitbook/assets/custom-component-7.png" alt=""><figcaption></figcaption></figure>
136+
137+
According to the requirement, the **Custom component** contains an **Input** component and a **Button** component. You can also add a **Text** component to provide context to the users of your app. When a user inputs into the text box, for example "gov", and then clicks the search button, the table only presents the entries in which the "email" field contains "gov".
138+
139+
<figure><img src="../../.gitbook/assets/custom-component-8.png" alt=""><figcaption></figcaption></figure>
140+
141+
To implement such a **Custom component**, first you create query `filterUser` to access data from the custom component and set it to run by manual invoke.
142+
143+
```SQL
144+
select * from users where email like '%{{custom1.model.search}}%';
145+
```
146+
147+
Then, you import the "antd" library and use the components **Button**, **Input**, **Card**, and **Space**. Finally, one more setting for each component inside the **Custom component**:
148+
149+
* Configure the `updateModel` method to run and update the data of the **Custom component** when the text in the **Input** component changes.
150+
* Trigger the query `filterUser` by the `runQuery` method when the **Search** button is clicked.
151+
152+
```javascript
153+
<style type="text/css">
154+
body {
155+
padding: 5px;
156+
}
157+
</style>
158+
159+
<link rel="stylesheet" type="text/css" href="https://unpkg.com/antd@4.21.4/dist/antd.min.css"/>
160+
161+
<script type="text/javascript" src="https://unpkg.com/antd@4.21.4/dist/antd.min.js" ></script>
162+
163+
<div id="root"></div>
164+
165+
<script type="text/babel">
166+
167+
const { Button, Card, Input, Space } = antd;
168+
169+
const MyCustomComponent = ({ runQuery, model, updateModel}) => (
170+
<Card title={"Hello, " + model.name + " filters data for you!"}>
171+
172+
<Space>
173+
<Input
174+
value={model.search}
175+
onChange={e => updateModel({ search: e.target.value})}
176+
placeholder="Input a name"
177+
/>
178+
<Button
179+
type="primary"
180+
onClick={() => runQuery(filterUser)}
181+
>
182+
Search
183+
</Button>
184+
185+
</Space>
186+
</Card>
187+
);
188+
189+
const ConnectedComponent = Openblocks.connect(MyCustomComponent);
190+
191+
const root = ReactDOM.createRoot(document.getElementById("root"));
192+
root.render(<ConnectedComponent />);
193+
194+
</script>
195+
```

0 commit comments

Comments
 (0)