2
2
title : Reactivity
3
3
---
4
4
5
- We have used ` poll ` and ` bind ` so far to make widgets
6
- have content dynamically. There is also ` on ` , ` hook ` and ` keybind ` methods.
5
+ In order for widgets to have dynamic content we pass ` Binding ` s as properties
6
+ or setup a ` hook ` .
7
+ A ` Binding ` is just an object that holds information for widget constructors
8
+ to setup a listener.
9
+
10
+ ## Property Bindings
11
+
12
+ We can make a ` Binding ` from a Variable
13
+
14
+ ``` js
15
+ const percent = Variable (0.5 )
16
+ const slider = Widget .Slider ({
17
+ value: percent .bind (),
18
+ onChange : ({ value }) => percent .value = value,
19
+ })
20
+ ```
21
+
22
+ From a ` Service `
23
+
24
+ ``` js
25
+ const { speaker } = await Service .import (" audio" )
26
+ const slider = Widget .Slider ({
27
+ value: speaker .bind (" volume" ),
28
+ onChange : ({ value }) => speaker .volume = value,
29
+ })
30
+ ```
31
+
32
+ Merge any number of ` Binding ` s into another ` Binding `
33
+
34
+ ``` js
35
+ const a = Variable (0.3 )
36
+ const b = Variable (0.7 )
37
+ const merged = Utils .merge ([a .bind (), b .bind ()], (a , b ) => {
38
+ return a * b
39
+ })
40
+
41
+ const level = Widget .LevelBar ({
42
+ value: merged
43
+ })
44
+ ```
45
+
46
+ Turn one or multiple Service signals into a ` Binding `
47
+
48
+ ``` js
49
+ const mpris = await Service .import (" mpris" )
50
+
51
+ const label = Widget .Label ({
52
+ label: Utils .watch (" initial-label" , mpris, " player-added" , (busName ) => {
53
+ return ` player ${ busName} was added`
54
+ })
55
+ })
56
+
57
+ const label = Widget .Label ({
58
+ label: Utils .watch (" initial-label" , [
59
+ [mpris, " player-added" ],
60
+ [mpris, " player-removed" ],
61
+ ], (busName ) => {
62
+ return ` player ${ busName} was added or removed`
63
+ })
64
+ })
65
+ ```
66
+
67
+ A ` Binding ` can be transformed according to need
68
+
69
+ ``` js
70
+ const num = Variable (0 )
71
+
72
+ const label = Widget .Label ({
73
+ // will throw an error, because number is not assignable to string
74
+ label: num .bind (),
75
+
76
+ // will have to be transformed
77
+ label: num .bind ().as (n => n .toString ()),
78
+ label: num .bind ().as (String )
79
+ })
80
+ ```
81
+
82
+ ## Hooks
7
83
8
84
You can call these on any Widget that you have a reference on.
9
85
They will return ` this ` reference, meaning you
@@ -12,90 +88,69 @@ can chain them up in any order in any number.
12
88
``` js
13
89
const widget = Widget ()
14
90
widget .hook ()
15
- widget .bind ()
91
+ widget .on ()
92
+ widget .poll ()
93
+ widget .keybind ()
16
94
```
17
95
18
96
``` js
19
97
const widget = Widget ()
20
98
.hook ()
21
- .bind ()
99
+ .on ()
22
100
```
23
101
24
102
``` js
25
103
const widget = Widget ({
26
104
setup : self => {
27
- self .bind ()
28
105
self .hook ()
106
+ self .on ()
29
107
}
30
108
})
31
109
```
32
110
33
111
``` js
34
112
const widget = Widget ({
35
113
setup : self => self
36
- .bind ()
37
114
.hook ()
115
+ .on ()
38
116
})
39
117
```
40
118
41
- ## Hook
119
+ ### Hook
42
120
43
121
` hook ` will setup a listener to a ` GObject ` and will handle disconnection
44
122
when the widget is destroyed. It will connect
45
123
to the ` changed ` signal by default when not specified otherwise.
46
124
47
125
``` js
126
+ const battery = await Service .import (" battery" )
127
+
48
128
// .hook(GObject, callback, signal?)
49
129
const BatteryPercent = () => Label ()
50
- .hook (Battery, label => {
51
- label .label = ` ${ Battery .percent } %`
52
- label .visible = Battery .available
53
- }, ' changed' )
130
+ .hook (battery, self => {
131
+ self .label = ` ${ battery .percent } %`
132
+ self .visible = battery .available
133
+ }, " changed" )
54
134
```
55
135
56
- ## Bind
57
-
58
- ` bind ` can be directly translated to ` hook ` .
59
- It will setup a listener based on property changes
136
+ ::: caution
137
+ A ` hook ` callback will be executed on startup.
138
+ If you are connecting to a signal that has an argument
139
+ you will need to check if its defined first
60
140
61
141
``` js
62
- const label = Label ()
142
+ const mpris = await Service .import (" mpris" )
143
+ const label = Widget .Label ().hook (mpris, (self , busName ) => {
144
+ if (! busName)
145
+ return // skip startup execution
63
146
64
- label .bind (
65
- ' label' , // self property to bind
66
- Battery, // GObject to listen to
67
- ' percent' , // target property
68
- p => ` ${ p} %` ) // optional transform method
69
-
70
- // translates to
71
- label .hook (
72
- Battery,
73
- self => self [' label' ] = ` ${ Battery[' percent' ]} %` ,
74
- ' notify::percent' )
147
+ self .label = busName
148
+ }, " player-added" )
75
149
```
76
150
77
- It is also possible to call ` bind ` on [ Services] ( ./services )
78
- and [ Variables] ( ./variables ) that can be used inside constructors.
151
+ :::
79
152
80
- ``` js
81
- Label ({
82
- label: Battery
83
- .bind (' percent' )
84
- .as (p => ` ${ p} %` )
85
- })
86
- ```
87
-
88
- ``` js
89
- const text = Variable (' hello' )
90
-
91
- Label ({
92
- label: text
93
- .bind ()
94
- .as (v => ` transformed ${ v} ` )
95
- })
96
- ```
97
-
98
- ## On
153
+ ### On
99
154
100
155
` on ` is the same as ` connect ` but instead of the signal handler id,
101
156
it returns a reference to the widget. ` on ` will setup a callback on a widget signal.
@@ -106,8 +161,8 @@ These two are equivalent
106
161
function MyButton () {
107
162
const self = Widget .Button ()
108
163
109
- self .connect (' clicked' , () => {
110
- print (self , ' is clicked' )
164
+ self .connect (" clicked" , () => {
165
+ print (self , " is clicked" )
111
166
})
112
167
113
168
return self
@@ -116,12 +171,24 @@ function MyButton() {
116
171
117
172
``` js
118
173
const MyButton = () => Widget .Button ()
119
- .on (' clicked' , self => {
120
- print (self , ' is clicked' )
174
+ .on (" clicked" , self => {
175
+ print (self , " is clicked" )
121
176
})
122
177
```
123
178
124
- ## Poll
179
+ ::: note
180
+ Most signals like ` clicked ` are available as a propety on the widget.
181
+ So its rare that ` .on ` or ` .connect ` will be needed.
182
+
183
+ ``` js
184
+ Widget .Button ({
185
+ on_clicked : self => print (self , " was clicked" )
186
+ })
187
+ ```
188
+
189
+ :::
190
+
191
+ ### Poll
125
192
126
193
Avoid using this as much as possible, using this is considered bad practice.
127
194
@@ -146,7 +213,7 @@ const MyLabel = () => Widget.Label()
146
213
})
147
214
```
148
215
149
- ## Keybind
216
+ ### Keybind
150
217
151
218
It is possible to setup keybindings on focused widgets
152
219
0 commit comments