Skip to content

Commit f2eb488

Browse files
author
Nils Henning
committed
[TASK] add isolated component guide, minor fixes
1 parent 054803a commit f2eb488

File tree

4 files changed

+154
-10
lines changed

4 files changed

+154
-10
lines changed

docs/api/000-base/40-isolated_component.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,13 @@ rendered within a secured context.
112112
That's why we enforce the usage of the `authorized?` method to make sure, all isolated
113113
components take care of their authorization themselves.
114114

115-
If `authorized?` return `true`, the component will be rendered. If it returns `false`,
115+
If `authorized?` returns `true`, the component will be rendered. If it returns `false`,
116116
the component will not be rendered.
117117

118118
A public isolated component therefore needs an `authorized?` method simply returning `true`.
119119

120120
You can create your own isolated base components with their `authorized` methods
121-
for your use cases and thus keep your code DRY
121+
for your use cases and thus keep your code DRY.
122122

123123
### Options
124124

docs/guides/600-actions/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,6 @@ We can customize the success and failure behavior of an `action` component by sp
4949

5050
You can also combine `:emit` and one of `:transition`, `:redirect` if wanted.
5151

52+
## Complete documentation
53+
5254
If you want to know all details about the `action` component, like how you can delay it, what events it emits or how exactly the response behavior can be customized, checkout it's [api documentation](/docs/api/100-components/action.md)

docs/guides/700-async/README.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,4 @@ An `async` components wraps its content in a special html structure allowing you
5656

5757
## Complete documentation
5858

59-
If you want to know all details about the `async` component checkout it's [api documentation](/docs/api/100-components/async.md)
60-
61-
62-
63-
64-
65-
![Coming Soon](../../images/coming_soon.png)
59+
If you want to know all details about the `async` component checkout its [api documentation](/docs/api/100-components/async.md)

docs/guides/800-isolated/README.md

Lines changed: 149 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,151 @@
11
# Isolated
22

3-
![Coming Soon](../../images/coming_soon.png)
3+
Matestacks concept of isolated components has a lot in common with `async` components. Isolated components can be deferred or asynchronously rerendered like `async` components. In the difference to `async` components, isolated components are resolved completetly independent from the rest of the ui. If an isolated component gets rerendered or loaded matestack will directly render this component without touching the app or page. With `async` matestack searches in an app or page which component needs to be rerendered. Therefore executing parts of an app and page whereas isolated components don't.
4+
5+
Isolated components can not be called or used with a block like `async`, instead you need to create a component inheriting from `Matestack::Ui::IsolatedComponent`. Creation of the custom component works similar to other components, except you need to implement an `authorized?` method. As said above isolated components are completly independent and could be called directly via a url, therefore they need custom authorization. More about that later.
6+
7+
Isolated components are perfectly when you have long runnning, complex database queries or business logic which concludes to slow page loads. Use an isolated component with the `:defer` option to keep your page loads fast and present the result to the user asynchronously.
8+
9+
## Usage
10+
11+
To create an isolated component you need to create a component which inherits from `Matestack::Ui::IsolatedComponent`. Implementing your component is straight forward. As always you implement a `response` method which defines what get's rendered.
12+
13+
```ruby
14+
class CurrentTime < IsolatedComponent
15+
16+
def response
17+
div class: 'time' do
18+
paragraph text: Time.now
19+
end
20+
end
21+
22+
def authorized?
23+
true
24+
end
25+
26+
end
27+
```
28+
29+
Register it like a usual component.
30+
31+
```ruby
32+
module ComponentsRegistry
33+
Matestack::Ui::Core::Component::Registry.register_components(
34+
current_time: CurrentTime
35+
)
36+
```
37+
38+
And use it with the `:defer` or `:rerender_on` options which work the same on `async` components.
39+
40+
```ruby
41+
def response
42+
current_time defer: 1000, rerender_on: 'update-time'
43+
end
44+
```
45+
46+
### Deferred loading
47+
48+
You can configure your isolated component to request its content directly after the page load or to delay the request for a given amount of time after the page load instead of being rendered with the page. `:defer` expects either a boolean or a integer representing the delay time in milliseconds. If `:defer` is set to `false` your isolated component will be rendered on page load and not deferred. If set to `true` it will request its content directly after the page load.
49+
50+
```ruby
51+
def response
52+
current_time defer: true
53+
end
54+
```
55+
56+
The above call to your isolated component will be skipped on page load and the component will request its content asynchronously directly after the page is loaded.
57+
58+
```ruby
59+
def response
60+
current_time defer: 500
61+
end
62+
```
63+
64+
This will load your isolated component 500ms after the page is loaded.
65+
66+
### Rerendering content
67+
68+
Isolated component leverage the event hub and can react to emitted events. If they receive one or more of the with `:rerender_on` specified events they will asynchronously request a rerender of their content. The server will only render the isolated component, not touching any of the apps or pages. The response will only include the rerendered html of the isolated component which then swaps out its current content with the response. If you specify multiple events in `:rerender_on` they need to be seperated by a comma.
69+
70+
```ruby
71+
def response
72+
current_time rerender_on: 'update-time'
73+
onclick emit: 'update-time' do
74+
button text: 'Update time'
75+
end
76+
end
77+
```
78+
79+
The above snippet renders our `current_time` isolated component and a button "Update time" on page load. If the button is clicked a _update-time_ event is emitted. Our isolated component receives the event and reacts to it by requesting its rerendered content from the server and replacing its content with the received html. In this case it will rerender after button click and show the updated time.
80+
81+
Remember that you can use ActionCable to emit events on the serverside.
82+
83+
### Authorization
84+
85+
When asynchronously rendering isolated components, these HTTP calls are actually
86+
processed by the controller action responsible for the corresponding page rendering.
87+
One might think, that the optional authorization and authentication rules of that
88+
controller action should therefore be enough for securing isolated components rendering.
89+
90+
But that's not true. It would be possible to hijack public controller actions without
91+
any authorization in place and request isolated components which are only meant to be
92+
rendered within a secured context.
93+
94+
That's why we enforce the usage of the `authorized?` method to make sure, all isolated
95+
components take care of their authorization themselves.
96+
97+
If `authorized?` returns `true`, the component will be rendered. If it returns `false`,
98+
the component will not be rendered.
99+
100+
A public isolated component therefore needs an `authorized?` method simply returning `true`.
101+
102+
This might sound complicated, but it is not. For example using devise you can access the controller helper `current_user` inside your isolated component, making authorization implementations as easy as:
103+
104+
```ruby
105+
def authorized?
106+
current_user.present?
107+
end
108+
```
109+
110+
### Data acquisition
111+
112+
Use the `prepare` method in order to gather needed information from long running queries or complex business logic or use methods. The `prepare` method is executed before the `response`.
113+
114+
```ruby
115+
class BookingsList < IsolatedComponent
116+
117+
def prepare
118+
@bookings = Booking.some_long_running_query
119+
end
120+
121+
def response
122+
@bookings.each do |booking|
123+
paragraph text: booking.details
124+
end
125+
availabilities.each do |availability|
126+
paragraph text: availability.details
127+
end
128+
end
129+
130+
def authorized?
131+
true
132+
end
133+
134+
def availabilities
135+
Booking.some_long_runnning_availability_check
136+
end
137+
138+
end
139+
```
140+
141+
Deferring such slow parts of your ui speeds up your page load significantly. But remember to always try to improve your query or logic performance as isolated components are not your general solution to fast page loads.
142+
143+
144+
### Loading animations
145+
146+
Isolated components are wrapped in a special html structure allowing you to create animations while the components gets loaded or rerendered. It appends a loading class to the wrapping elements while the component is loading or rerendering. To learn more about how to animate loading isolated components checkout its [api documentation](/docs/api/100-components/async.md).
147+
148+
149+
## Complete documentation
150+
151+
If you want to know all details about isolated components checkout its [api documentation](/docs/api/000-base/40-isolated_component.md).

0 commit comments

Comments
 (0)