neo.mjs 6.13.0 → 6.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/apps/covid/neo-config.json +1 -1
  2. package/apps/portal/view/ViewportController.mjs +5 -4
  3. package/apps/portal/view/home/ContentBox.mjs +80 -0
  4. package/apps/portal/view/home/MainContainer.mjs +51 -15
  5. package/apps/portal/view/learn/ContentTreeList.mjs +10 -3
  6. package/apps/portal/view/learn/MainContainerController.mjs +37 -5
  7. package/apps/portal/view/learn/MainContainerModel.mjs +51 -7
  8. package/apps/portal/view/learn/PageContainer.mjs +21 -9
  9. package/apps/sharedcovid/neo-config.json +1 -1
  10. package/examples/form/field/select/MainContainer.mjs +1 -1
  11. package/package.json +3 -3
  12. package/resources/data/deck/learnneo/pages/2023-10-14T19-25-08-153Z.md +16 -1
  13. package/resources/data/deck/learnneo/pages/ComponentsAndContainers.md +180 -0
  14. package/resources/data/deck/learnneo/pages/Config.md +11 -4
  15. package/resources/data/deck/learnneo/pages/DescribingTheUI.md +6 -0
  16. package/resources/data/deck/learnneo/pages/Earthquakes.md +36 -9
  17. package/resources/data/deck/learnneo/pages/Events.md +55 -43
  18. package/resources/data/deck/learnneo/pages/GuideEvents.md +9 -8
  19. package/resources/data/deck/learnneo/pages/References.md +14 -7
  20. package/resources/data/deck/learnneo/pages/TodoList.md +241 -0
  21. package/resources/data/deck/learnneo/pages/WhyNeo-Quick.md +6 -11
  22. package/resources/data/deck/learnneo/tree.json +2 -0
  23. package/resources/scss/src/apps/portal/home/ContentBox.scss +26 -0
  24. package/resources/scss/src/apps/portal/home/MainContainer.scss +4 -12
  25. package/resources/scss/src/apps/portal/learn/MainContainer.scss +0 -7
  26. package/resources/scss/src/apps/portal/learn/PageContainer.scss +35 -0
  27. package/resources/scss/src/apps/portal/learn/PageSectionsPanel.scss +8 -0
  28. package/src/component/Base.mjs +16 -1
  29. package/src/controller/Application.mjs +12 -1
  30. package/src/controller/Base.mjs +15 -4
  31. package/src/controller/Component.mjs +5 -1
  32. package/src/core/Observable.mjs +62 -22
  33. package/src/form/field/Base.mjs +21 -9
  34. package/src/form/field/Select.mjs +166 -117
  35. package/src/form/field/Text.mjs +7 -10
  36. package/src/main/DomEvents.mjs +2 -1
  37. package/src/main/addon/MonacoEditor.mjs +2 -2
  38. package/src/main/addon/Navigator.mjs +27 -24
  39. package/src/selection/ListModel.mjs +13 -14
  40. package/src/selection/Model.mjs +10 -10
  41. package/src/util/HashHistory.mjs +1 -0
  42. package/src/worker/App.mjs +5 -1
  43. package/src/worker/Manager.mjs +14 -7
  44. package/test/components/files/form/field/Select.mjs +6 -4
@@ -0,0 +1,180 @@
1
+ ## Introduction
2
+
3
+ Neo.mjs views are made up of components and containers.
4
+
5
+ A component is a visual widget, such as a button, label, or text field. A container is a visual
6
+ collection of components.
7
+
8
+ `Neo.component.Base` is the base class for all components. It introduces some common features, such as
9
+ event handling, binding, and some life-cycle methods.
10
+
11
+ `Neo.container.Base` is the base class for all containers. Containers are also components.
12
+
13
+ ## Neo.container.Base
14
+
15
+ Containers are commonly used, although there are many specialized sub-classes, such as panels and toolbars.
16
+
17
+
18
+ Containers have two key properties:
19
+
20
+ - `items`, which are the components within the container, and
21
+ - `layout`, which describes how the items are arranged
22
+
23
+ ## Neo.component.Base
24
+
25
+ The component base class introduces common component features, but is rarely used itself because it's so
26
+ primitive. Components introduce various properties, such as `width`, `height`, `cls` (to specify CSS classes for the component).
27
+
28
+ Here's a container, with one child item.
29
+
30
+ <pre data-neo>
31
+ import Container from '../../../../src/container/Base.mjs';
32
+
33
+ class MainView extends Container {
34
+ static config = {
35
+ className: 'Example.view.MainView',
36
+ layout : {ntype:'vbox', align:'start'},
37
+ items : [{
38
+ ntype : 'component', // Or module:Component
39
+ style : {border: 'thin solid red;'}, // Styling is usually done via "cls"
40
+ height: 100,
41
+ width : 200
42
+ }]
43
+ }
44
+ }
45
+
46
+ Neo.setupClass(MainView);
47
+ </pre>
48
+
49
+ Components also have an `html`. The `html` property is rarely used, and goes against the abstract philosophy of Neo.mjs, but
50
+ sometimes it's handy as a placeholder as you stub out views.
51
+
52
+ <pre data-neo>
53
+ import Container from '../../../../src/container/Base.mjs';
54
+
55
+ class MainView extends Container {
56
+ static config = {
57
+ className: 'Example.view.MainView',
58
+ layout : {ntype:'vbox', align:'start'},
59
+ items : [{
60
+ ntype : 'component', // Or module:Component
61
+ style : {border: 'thin solid red;'}, // Styling is usually done via "cls"
62
+ html : 'This is a placeholder for a more sophisticated component we\'ll add later.',
63
+ height: 100,
64
+ width : 200
65
+ }]
66
+ }
67
+ }
68
+
69
+ Neo.setupClass(MainView);
70
+ </pre>
71
+
72
+
73
+ ## Layout
74
+
75
+ The `layout` config specifies how components are arranged within a container. Here are examples of
76
+ some commonly-used layouts.
77
+
78
+ ### Fit layout
79
+
80
+ Fix is used when there's a single child. The component is sized to fit the container.
81
+
82
+ <pre data-neo>
83
+ import Container from '../../../../src/container/Base.mjs';
84
+
85
+ class MainView extends Container {
86
+ static config = {
87
+ className: 'Example.view.MainView',
88
+ layout : 'fit', // If no configs are needed, simply use the ntype of the layout
89
+ items : [{
90
+ ntype: 'component',
91
+ style: {backgroundColor: 'lightgreen'}, // The camel-cased property converts to the hyphenated css style
92
+ }]
93
+ }
94
+ }
95
+
96
+ Neo.setupClass(MainView);
97
+ </pre>
98
+
99
+ ### Vbox and hbox
100
+
101
+ Items are arranged vertically or horizontally. On-axis and off-axis alignment can be specified.
102
+
103
+ <pre data-neo>
104
+ import Button from '../../../../src/button/Base.mjs';
105
+ import Container from '../../../../src/container/Base.mjs';
106
+
107
+ class MainView extends Container {
108
+ static config = {
109
+ className: 'Example.view.MainView',
110
+ layout : {ntype:'vbox', align:'start'}, // Change the ntype to 'hbox'
111
+ items : [{
112
+ module : Button,
113
+ iconCls: 'fa fa-home',
114
+ text : 'Home'
115
+ }, {
116
+ module : Button,
117
+ iconCls: 'fa fa-star',
118
+ text : 'Star'
119
+ }]
120
+ }
121
+ }
122
+
123
+ Neo.setupClass(MainView);
124
+ </pre>
125
+
126
+ ### Card
127
+
128
+ Having multiple child items, one of which is visible.
129
+
130
+ <pre data-neo>
131
+ import Button from '../../../../src/button/Base.mjs';
132
+ import Base from '../../../../src/container/Base.mjs';
133
+
134
+ class MainView extends Base {
135
+ static config = {
136
+ className: 'Example.view.MainView',
137
+ layout : 'vbox',
138
+ items : [{
139
+ ntype: 'toolbar',
140
+ dock : 'top',
141
+ items: [{
142
+ ntype: 'button',
143
+ text: 'Click me to cycle through the cards',
144
+ ui: 'ghost',
145
+ iconCls: 'fa fa-chevron-right',
146
+ iconPosition: 'right',
147
+ handler: data => {
148
+ const container = data.component.up('container').getReference('cardContainer');
149
+ container.layout.activeIndex = (container.layout.activeIndex +1) % container.items.length;
150
+ }
151
+ }]
152
+ }, {
153
+ ntype: 'container',
154
+ reference: 'cardContainer',
155
+ layout: 'card',
156
+ flex: 1,
157
+ items: [{
158
+ ntype : 'component',
159
+ style: {backgroundColor: 'lightsalmon'}, // The camel-cased property converts to the hyphated css style
160
+ }, {
161
+ ntype : 'component',
162
+ style: {backgroundColor: 'darkseagreen'} // https://drafts.csswg.org/css-color/#named-colors
163
+ }, {
164
+ ntype : 'component',
165
+ style: {backgroundColor: 'cornflowerblue'} // Who came up with these names?
166
+ }]
167
+ }]
168
+ }
169
+ }
170
+
171
+ Neo.setupClass(MainView);
172
+ </pre>
173
+
174
+
175
+
176
+
177
+ ## Reusing containers
178
+
179
+
180
+ ## Lifecycle methods
@@ -1,9 +1,13 @@
1
+ ## Introduction
2
+
1
3
  As you've probably noticed, Neo.mjs classes have a `static config` property.
2
4
 
3
5
  The config describes properties you can specify as you create an instance of the class.
4
6
  Any config in the class, or its ancestors, can be specified.
5
7
 
6
- In addition, Neo.mjs uses that information to set up propoerty lifecycle
8
+ ## Simple properties and lifecycle properties
9
+
10
+ In addition, Neo.mjs uses that information to set up property lifecycle
7
11
  methods.
8
12
 
9
13
  Here's an example of a new component class `Simple` with three config properties:
@@ -12,6 +16,9 @@ Here's an example of a new component class `Simple` with three config properties
12
16
  2. `foo` &mdash; an instance property
13
17
  2. `bar_` &mdash; another instance property
14
18
 
19
+ The `Simple` class introduces syntax. It doesn't have any content, so if you run the code you won't
20
+ see anything. We'll change that in the next example.
21
+
15
22
  <pre data-neo>
16
23
  import Component from '../../../../src/component/Base.mjs';
17
24
  import Container from '../../../../src/container/Base.mjs';
@@ -46,8 +53,7 @@ class MainView extends Container {
46
53
  Neo.setupClass(MainView);
47
54
  </pre>
48
55
 
49
- The `Simple` class doesn't have any content, so if you run the code you won't see anything. We'll
50
- change that in the next example.
56
+ ## Detecting when a value changes
51
57
 
52
58
  Note that the `bar` property is defined with an underscore at the end. That tags the property as
53
59
  a _lifecyle property_. A lifecycle property provides methods that are run as the property is
@@ -75,7 +81,6 @@ class Simple extends Component {
75
81
  }
76
82
  afterSetBar(value, oldValue){
77
83
  this.html = value;
78
- this.fire('barChange', {component: this, value, oldValue});
79
84
  }
80
85
 
81
86
  }
@@ -103,6 +108,8 @@ This time if you run the code you'll see "hi there" in the view. That's because
103
108
  configured with `bar: 'hi there'`, and since that's a lifecycle property the `afterSetBar()` method
104
109
  is run. That method updates the view with the passed value.
105
110
 
111
+ ## Firing an event when a value changes
112
+
106
113
  Typically, the _afterSet_ method is used to update a view or to fire an event.
107
114
 
108
115
  Look at this code: `afterSetBar()` fires an event, and the config in the `items[]` is listening to it.
@@ -1,3 +1,5 @@
1
+ ## Introduction
2
+
1
3
  A Neo.mjs view is comprised of components and containers. A component is a visual widget, like a button,
2
4
  and a container is a visual collection of components.
3
5
 
@@ -8,6 +10,8 @@ have a few key configs, including `text` and `iconCls`. The configs are properti
8
10
  use to describe the component you're creating> You can also access or set the properties dynamically.
9
11
 
10
12
 
13
+ ## A view with one component
14
+
11
15
  <pre data-neo>
12
16
  import Button from '../../../../src/button/Base.mjs';
13
17
  import Container from '../../../../src/container/Base.mjs';
@@ -42,6 +46,8 @@ Containers also have a `layout` property, which describes how the items are arra
42
46
 
43
47
  Let's put a second button in the container.
44
48
 
49
+ ## A view with two components
50
+
45
51
  <pre data-neo>
46
52
  import Button from '../../../../src/button/Base.mjs';
47
53
  import Container from '../../../../src/container/Base.mjs';
@@ -120,7 +120,7 @@ As you can see, `MicroLoader.mjs` runs `Main.mjs`, which in turn spawns the thre
120
120
  - `neomjs-app-worker` is where app logic is run
121
121
 
122
122
  Neo.mjs apps run in multiple webworkers, and each webworker is run in a separate parallel thread.
123
- Parallel processing &mdash; along wih the efficient way the `neomjs-vdom-worker` applies delta updates &mdash; is why Neo.mjs applications run so fast.
123
+ Parallel processing &mdash; along wih the efficient way the vdom worker applies delta updates &mdash; is why Neo.mjs applications run so fast.
124
124
 
125
125
  ##Commonly-used Scripts
126
126
 
@@ -294,7 +294,7 @@ layout: {
294
294
 
295
295
  ## Debugging
296
296
 
297
- At startup a Neo.mjs application launches three Web Workers:
297
+ At startup, a Neo.mjs application launches three Web Workers:
298
298
 
299
299
  - neomjs-app-worker
300
300
  - neomjs-data-worker
@@ -1153,7 +1153,7 @@ and each class is simpler than using complex source files that try to configure
1153
1153
 
1154
1154
  <!-- /lab -->
1155
1155
 
1156
- ### Google Maps Add-on
1156
+ ## Google Maps Add-on
1157
1157
 
1158
1158
  Neo.mjs has a Google Map component. This component is a little different than a button or table,
1159
1159
  becauase it's implemented as a _main thread add-on_.
@@ -1169,14 +1169,10 @@ to also provide a wrapper class so it can be used like any other component withi
1169
1169
  Maps is implemented: there's a main-thread add-on and a corresponding Neo.mjs component. The add-on is
1170
1170
  specified in _neo-config.json_, and the component is imported and used like any other component.
1171
1171
 
1172
- Ultimately, normal components are responsible for specifying how
1173
- they're rendered (which is usually handled by Neo.mjs).
1174
-
1175
1172
  How do you specify which main-thread add-ons you want? If you recall the script you used to create the starter
1176
1173
  app, it has a step that asks what add-ons you want. That results in populating the `mainThreadAddons` property
1177
- in `neo-config.json`. We didn't choose Google Maps when we ran the script, but we need it. That means we
1178
- need to edit `neo-config.json` and add it. Google Maps also requires an API key, which is also configured in
1179
- `neo-config.json`.
1174
+ in `neo-config.json`. We didn't choose Google Maps when we ran the script, but we need it, which means we'll
1175
+ need to edit `neo-config.json`. Google Maps also requires an API key, which is also configured there.
1180
1176
 
1181
1177
  The Google Maps component has a few key configs:
1182
1178
 
@@ -1193,6 +1189,20 @@ Marker store records are required to have these properties:
1193
1189
 
1194
1190
  <!-- lab -->
1195
1191
 
1192
+ <details>
1193
+ <summary>Get the code for the custom add-on</summary>
1194
+ At the time this tutorial was written, the Neo.mjs Google Maps addon was about to be updated to
1195
+ accomodate Google's "AdvancedMarker" class. Until that's ready, we're going to use a modified version of the add-on.
1196
+
1197
+ Download and unzip this file, and copy the two source files to the corresponding subdirectories in
1198
+ your workspace's `src` directory. Note that `src` already contains some files, so don't replace the whole
1199
+ directory, but instead, move the files to their individual locations.
1200
+
1201
+ <a href="https://s3.amazonaws.com/mjs.neo.learning.images/zip/src.zip">src.zip</a>
1202
+
1203
+ <img src="https://s3.amazonaws.com/mjs.neo.learning.images/earthquakes/CopyGoogleMapsFiles.png" width="30%%"></img>
1204
+ </details>
1205
+
1196
1206
  <details>
1197
1207
  <summary>Specify the main-thread add-on</summary>
1198
1208
 
@@ -1215,6 +1225,10 @@ Edit `apps/earthquakes/neo-config.json` and add entries for the Google Maps add-
1215
1225
  }
1216
1226
  </pre>
1217
1227
 
1228
+ It's unusual to need to edit `neo-config.json`. The app theme is specified there, and so are main thread add-ons.
1229
+ In our case, we're adding `WS/GoogleMaps` which in turn requires that we specify the map key. The `WS/`
1230
+ prefix tells Neo.mjs that the add-on is in our workspace, rather than an add-on provided by Neo.mjs.
1231
+
1218
1232
  Save and refresh, and you'll see a console log emanating from the plugin.
1219
1233
 
1220
1234
  <img style="width:80%" src="https://s3.amazonaws.com/mjs.neo.learning.images/earthquakes/GoogleMapsLoaded.png"></img>
@@ -1406,3 +1420,16 @@ Save, refresh, and confirm that you see the value logged when you click on a map
1406
1420
 
1407
1421
 
1408
1422
  <!-- /lab -->
1423
+
1424
+ ## Summary
1425
+
1426
+ Congratulations on completing the tutorial!
1427
+
1428
+ The goals was to give you hands-on coding a simple app to let you get a feel for syntax
1429
+ and to introduce some basic Neo.mjs concepts
1430
+
1431
+ - Declarative, abstract code
1432
+ - Class-based coding, and the ability to extend any class, such as `view/earthquakes/Table.mjs`
1433
+ - View models, to share properties and objects, such as the store shared by the table and map
1434
+ - Events, specified via `listeners:{}`
1435
+ - Controllers, to hold event listeners and other procedural logic
@@ -1,3 +1,5 @@
1
+ ## Introduction
2
+
1
3
  All components fire events. For example, form fields fire a `change` event, various
2
4
  focus events, and others. Some other types fire events too, such as `Neo.data.Store`,
3
5
  which fires a `load` event after the store is loaded with data.
@@ -5,34 +7,35 @@ which fires a `load` event after the store is loaded with data.
5
7
  Some terminology related to events is that events are _fired_, and as a result, some
6
8
  event _handler_ &mdash; or _listener_ &mdash; is run.
7
9
 
10
+ ## Listeners
11
+
8
12
  To specify an event handler, use `listeners: {}`, specifying in as many event/handler
9
13
  pairs as you need.
10
14
 
11
15
  The code below shows two text fields, with `listeners` for `change` and `focusEnter`.
12
- (The events for any component are documened in the API docs.)
16
+ (The events for any component are documented in the API docs.)
13
17
 
14
18
  <pre data-neo>
15
- import Base from '../../../../src/container/Base.mjs';
19
+ import Container from '../../../../src/container/Base.mjs';
16
20
  import TextField from '../../../../src/form/field/Text.mjs';
17
- class MainView extends Base {
21
+
22
+ class MainView extends Container {
18
23
  static config = {
19
- className : 'Example.view.MainView',
20
- layout: {ntype:'vbox', align:'start'},
21
- items : [{
22
- module: TextField,
23
- labelText : 'First name',
24
+ className: 'Example.view.MainView',
25
+ layout : {ntype:'vbox', align:'start'},
26
+
27
+ itemDefaults: {
28
+ module : TextField,
24
29
  listeners: {
25
- change: data => Neo.Main.log({value:data.value}),
30
+ change : data => Neo.Main.log({value:data.value}),
26
31
  focusEnter: data => Neo.Main.log({value: `Entering ${data.component.labelText}`})
27
32
  }
28
33
  },
29
- {
30
- module: TextField,
31
- labelText : 'Last name',
32
- listeners: {
33
- change: data => Neo.Main.log({value: data.value}),
34
- focusEnter: data => Neo.Main.log({value: `Entering ${data.component.labelText}`})
35
- }
34
+
35
+ items: [{
36
+ labelText: 'First name'
37
+ }, {
38
+ labelText: 'Last name'
36
39
  }]
37
40
  }
38
41
  }
@@ -42,37 +45,39 @@ Neo.setupClass(MainView);
42
45
  If you run the example, and open the browser's debugger, you'll see the console being logged as you type or give
43
46
  focus to either field.
44
47
 
48
+ ## In-line or separated into a controller
49
+
45
50
  Note that the handlers specify an in-line function. For trivial cases, that might be ok. But normally
46
51
  you'd want better separation of concerns by placing those event handlers in a separate class. Neo.mjs provides
47
52
  that with a _component controller_.
48
53
 
49
54
  A `Neo.controller.Component` is a simple class associated with a component class. As a view is created, an
50
- instance of its associated contoller is automatically created.
55
+ instance of its associated controller is automatically created.
51
56
 
52
57
  <pre data-neo>
53
- import Base from '../../../../src/container/Base.mjs';
54
- import Controller from '../../../../src/controller/Component.mjs';
55
- import TextField from '../../../../src/form/field/Text.mjs';
58
+ import Container from '../../../../src/container/Base.mjs';
59
+ import Controller from '../../../../src/controller/Component.mjs';
60
+ import TextField from '../../../../src/form/field/Text.mjs';
56
61
 
57
62
  class MainViewController extends Controller {
58
63
  static config = {
59
64
  className: 'Example.view.MainViewController'
60
65
  }
61
- onChange(data){
62
- console.log(data.value);
66
+ onChange(data) {
67
+ Neo.Main.log({value: data.value})
63
68
  }
64
69
  }
65
70
  Neo.setupClass(MainViewController);
66
71
 
67
72
 
68
- class MainView extends Base {
73
+ class MainView extends Container {
69
74
  static config = {
70
75
  className : 'Example.view.MainView',
71
76
  controller: MainViewController,
72
- layout: {ntype:'vbox', align:'start'},
73
- items : [{
74
- module: TextField,
75
- labelText : 'Name',
77
+ layout : {ntype:'vbox', align:'start'},
78
+ items : [{
79
+ module : TextField,
80
+ labelText: 'Name',
76
81
  listeners: {
77
82
  change: 'onChange'
78
83
  }
@@ -88,12 +93,16 @@ to make it easier to see the source code for every class being used. But in an
88
93
  actual applications the controller class would be coded in its own source file &mdash; named something
89
94
  like `MainViewController.mjs` &mdash; and that would be imported into the view.)
90
95
 
96
+ ## Neo.core.Observable
97
+
91
98
  The ability to fire events and add listeners is provided by `Neo.core.Observable`, which is mixed into
92
99
  classes that need that ability. All components are observable, `Neo.data.Store` is observable, and some
93
100
  others. `Neo.core.Observable` introduces a few methods and properties, such as `listeners`, which
94
101
  is used in the examples above, `on()` for procedurally adding an event listener, and `fire()`, which is
95
102
  how you fire events in the custom classes you create.
96
103
 
104
+ ## Firing an event when a value changes
105
+
97
106
  Here's example illustrating how `fire()` is used. The code defines a `ToggleButton`
98
107
  class, which is just a button with a `checked` property: the button shows a checked or unchecked
99
108
  checkbox depending on the value of `checked`.
@@ -103,37 +112,40 @@ We'll discuss that at length later, but in a nutshell, config properties ending
103
112
  automatically get lifecycle methods run before the value is assigned, after the value is assigned, and
104
113
  before the value is accessed. We're using the _after_ method to fire a `change` event.
105
114
 
115
+
106
116
  <pre data-neo>
107
- import Base from '../../../../src/container/Base.mjs';
108
- import Button from '../../../../src/button/Base.mjs';
109
- import TextField from '../../../../src/form/field/Text.mjs';
117
+ import Button from '../../../../src/button/Base.mjs';
118
+ import Container from '../../../../src/container/Base.mjs';
110
119
 
111
120
  class ToggleButton extends Button {
112
121
  static config = {
113
122
  className: 'Example.view.ToggleButton',
114
- checked_: false
123
+ checked_ : false
115
124
  }
116
- afterSetChecked(checked){
117
- this.iconCls = checked?'fa fa-square-check':'fa fa-square';
118
- this.fire('change', {component: this, checked}); // This is where our custom event is being fired
125
+ afterSetChecked(checked) {
126
+ this.iconCls = checked ? 'fa fa-square-check' : 'fa fa-square';
127
+
128
+ // This is where our custom event is being fired
129
+ this.fire('change', {component: this, checked})
119
130
  }
120
- onClick(data){
131
+ onClick(data) {
121
132
  super.onClick(data);
122
- this.checked = !this.checked;
133
+ this.checked = !this.checked
123
134
  }
124
135
  }
125
136
  Neo.setupClass(ToggleButton);
126
137
 
127
138
 
128
- class MainView extends Base {
139
+ class MainView extends Container {
129
140
  static config = {
130
- className : 'Example.view.MainView',
131
- layout: {ntype:'vbox', align:'start'},
132
- items : [{
133
- module: ToggleButton,
134
- text: 'Toggle',
141
+ className: 'Example.view.MainView',
142
+ layout : {ntype:'vbox', align:'start'},
143
+ items : [{
144
+ module : ToggleButton,
145
+ text : 'Toggle',
135
146
  listeners: {
136
- change: data => console.log(data.checked) // Here, we're listening to the custom event
147
+ // Here, we're listening to the custom event
148
+ change: data => Neo.Main.log({value: data.checked})
137
149
  }
138
150
  }]
139
151
  }
@@ -1,12 +1,13 @@
1
1
  [Add content on listeners options here]
2
2
 
3
- How are events set up? We don't really care, but in case you're curious: Neo.mjs has a `Neo.core.Observable` class
4
- that can be mixed into any class. It maintains a `listeners` object map that's a key-value pair, where
5
- the key is the event name, and the value is an array of function references. The first time a listener is
6
- added an entry is added to the map using the event name as the key, and the event handler added as the first
7
- item in the associated array. If another listener is added for the same event, a second item is added to the
8
- array. If a new event is added, a new entry is added. Etc. When the event is fired, Neo.mjs looks up the map
9
- entry for the event name, then runs each function in the array, passing whatever data is specified in the
10
- call to `fire()`.
3
+ How are events set up? The details don't really matter, but in case you're curious:
4
+ Neo.mjs has a `Neo.core.Observable` class that can be mixed into any class. It maintains
5
+ a `listeners` object map that's a key-value pair, where the key is the event name, and
6
+ the value is an array of function references. The first time a listener is added, an
7
+ entry is added to the map using the event name as the key, and the event handler added
8
+ as the first item in the associated array. If another listener is added for the same
9
+ event, a second item is added to the array. If a new event is added, a new entry is
10
+ added. Etc. When the event is fired, Neo.mjs looks up the map entry for the event name,
11
+ then runs each function in the array, passing whatever data is specified in the call to `fire()`.
11
12
 
12
13
  <img style="width:80%" src="https://s3.amazonaws.com/mjs.neo.learning.images/gettingStarted/events/ObservableInMemory.png"></img>
@@ -1,3 +1,5 @@
1
+ ## Introduction
2
+
1
3
  Controllers often need to get references to components in order to update
2
4
  the UI or access component properties.
3
5
  There are two common ways of doing that:
@@ -5,11 +7,13 @@ There are two common ways of doing that:
5
7
  - Using the component references passed to the event handler
6
8
  - Tagging a component with a `reference` and using `this.getReference()` in the controller
7
9
 
10
+ ## References are usually passed to event handlers
11
+
8
12
  Here's an example with one button. Clicking on the button will disable it.
9
13
  As you can see, the handler uses the component reference pass in via `data.component`.
10
14
 
11
15
  <pre data-neo>
12
- import Button from '../../../../src/Button/Base.mjs';
16
+ import Button from '../../../../src/button/Base.mjs';
13
17
  import Container from '../../../../src/container/Base.mjs';
14
18
  import Controller from '../../../../src/controller/Component.mjs';
15
19
 
@@ -39,12 +43,14 @@ class MainView extends Container {
39
43
  Neo.setupClass(MainView);
40
44
  </pre>
41
45
 
46
+ ## Using getReference()
47
+
42
48
  But what if we need to get a reference to another component in the view? In that case
43
49
  you tag the component you need with a `reference` config, then use `getReference()` in
44
50
  the controller.
45
51
 
46
52
  <pre data-neo>
47
- import Button from '../../../../src/Button/Base.mjs';
53
+ import Button from '../../../../src/button/Base.mjs';
48
54
  import Container from '../../../../src/container/Base.mjs';
49
55
  import Controller from '../../../../src/controller/Component.mjs';
50
56
 
@@ -53,10 +59,10 @@ class MainViewController extends Controller {
53
59
  className: 'Example.view.MainViewController'
54
60
  }
55
61
  onDisableButtonClick(data){
56
- data.component.disabled = true;
62
+ data.component.disabled = true
57
63
  }
58
64
  onEnableButtonClick(data){
59
- this.getReference('myButton').disabled = false;
65
+ this.getReference('myButton').disabled = false
60
66
  }
61
67
  }
62
68
  Neo.setupClass(MainViewController);
@@ -82,6 +88,7 @@ class MainView extends Container {
82
88
  Neo.setupClass(MainView);
83
89
  </pre>
84
90
 
91
+ ## Getting a reference when debugging
85
92
 
86
93
  There are other ways of getting references, but these are either non-standard or for debugging.
87
94
  For example, components have an `up()` method, and containers have a `down()` method. These look
@@ -98,7 +105,7 @@ The following example gets a reference to the _Learn_ button at the top of this
98
105
  Again &mdash; that use of `Neo.findFirst()` might be handy when debugging, but it should never be used in app logic.
99
106
 
100
107
  <pre data-neo>
101
- import Button from '../../../../src/Button/Base.mjs';
108
+ import Button from '../../../../src/button/Base.mjs';
102
109
  import Container from '../../../../src/container/Base.mjs';
103
110
 
104
111
  class MainView extends Container {
@@ -110,14 +117,14 @@ class MainView extends Container {
110
117
  text : 'Change Learn caption',
111
118
  handler: data=>{
112
119
  const component = Neo.findFirst({text:'Learn'});
113
- component?.set({text: 'Yikes!', ui: 'primary'});
120
+ component?.set({text: 'Yikes!', ui: 'primary'})
114
121
  }
115
122
  }, {
116
123
  module : Button,
117
124
  text : 'Restore Learn caption',
118
125
  handler: data=>{
119
126
  const component = Neo.findFirst({text:'Yikes!'});
120
- component?.set({text: 'Learn', ui: 'ghost'});
127
+ component?.set({text: 'Learn', ui: 'ghost'})
121
128
  }
122
129
  }]
123
130
  }