neo.mjs 6.10.10 → 6.10.11

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 (79) hide show
  1. package/apps/ServiceWorker.mjs +2 -2
  2. package/apps/portal/view/learn/ContentTreeList.mjs +24 -12
  3. package/apps/portal/view/learn/LivePreview.mjs +28 -11
  4. package/buildScripts/createAppMinimal.mjs +391 -0
  5. package/examples/ServiceWorker.mjs +2 -2
  6. package/examples/button/base/neo-config.json +2 -1
  7. package/examples/list/chip/neo-config.json +1 -2
  8. package/package.json +72 -70
  9. package/resources/data/deck/learnneo/data/theBeatles.json +22 -0
  10. package/resources/data/deck/learnneo/p/2023-10-14T19-25-08-153Z.md +29 -20
  11. package/resources/data/deck/learnneo/p/ComponentModels.md +116 -1
  12. package/resources/data/deck/learnneo/p/Config.md +157 -0
  13. package/resources/data/deck/learnneo/p/DescribingTheUI.md +67 -1
  14. package/resources/data/deck/learnneo/p/Earthquakes.md +214 -0
  15. package/resources/data/deck/learnneo/p/Events.md +142 -1
  16. package/resources/data/deck/learnneo/p/Extending.md +116 -1
  17. package/resources/data/deck/learnneo/p/References.md +126 -0
  18. package/resources/data/deck/learnneo/p/TestLivePreview.md +28 -6
  19. package/resources/data/deck/learnneo/t.json +5 -6
  20. package/resources/data/deck/training/p/2022-12-27T21-55-30-948Z.md +1 -1
  21. package/resources/data/deck/training/p/2022-12-27T22-23-55-083Z.md +1 -1
  22. package/resources/data/deck/training/p/2022-12-29T16-00-13-223Z.md +1 -1
  23. package/resources/data/deck/training/p/2022-12-29T18-34-25-826Z.md +1 -1
  24. package/resources/data/deck/training/p/2022-12-29T18-36-56-893Z.md +1 -1
  25. package/resources/data/deck/training/p/2022-12-31T18-43-56-338Z.md +1 -1
  26. package/resources/data/deck/training/p/2022-12-31T18-51-50-682Z.md +1 -1
  27. package/resources/data/deck/training/p/2022-12-31T18-54-04-176Z.md +1 -1
  28. package/resources/data/deck/training/p/2023-01-01T17-49-18-429Z.md +1 -1
  29. package/resources/data/deck/training/p/2023-01-01T21-23-17-716Z.md +1 -1
  30. package/resources/data/deck/training/p/2023-01-06T23-21-31-685Z.md +1 -1
  31. package/resources/data/deck/training/p/2023-01-06T23-34-13-897Z.md +2 -2
  32. package/resources/data/deck/training/p/2023-01-06T23-46-36-687Z.md +1 -1
  33. package/resources/data/deck/training/p/2023-01-08T01-24-21-088Z.md +1 -1
  34. package/resources/data/deck/training/p/2023-01-08T02-11-26-333Z.md +2 -2
  35. package/resources/data/deck/training/p/2023-01-14T00-40-27-784Z.md +2 -2
  36. package/resources/data/deck/training/p/2023-07-31T00-37-21-927Z.md +2 -2
  37. package/resources/data/deck/training/p/2023-10-14T19-25-08-153Z.md +3 -3
  38. package/resources/scss/src/apps/newwebsite/Viewport.scss +32 -0
  39. package/resources/scss/src/apps/portal/learn/ContentView.scss +20 -4
  40. package/resources/scss/src/apps/portal/learn/LivePreview.scss +8 -0
  41. package/resources/scss/src/component/Base.scss +13 -4
  42. package/resources/scss/src/form/field/Select.scss +2 -5
  43. package/resources/scss/src/form/field/Text.scss +0 -1
  44. package/resources/scss/src/list/Base.scss +47 -2
  45. package/resources/scss/src/list/Chip.scss +10 -4
  46. package/resources/scss/theme-dark/list/Base.scss +11 -10
  47. package/resources/scss/theme-light/list/Base.scss +11 -10
  48. package/resources/scss/theme-neo-light/design-tokens/Components.scss +3 -0
  49. package/resources/scss/theme-neo-light/list/Base.scss +1 -0
  50. package/src/DefaultConfig.mjs +3 -3
  51. package/src/component/Base.mjs +7 -0
  52. package/src/container/Base.mjs +6 -12
  53. package/src/core/Base.mjs +5 -2
  54. package/src/data/Model.mjs +7 -0
  55. package/src/data/RecordFactory.mjs +5 -4
  56. package/src/form/field/Base.mjs +11 -0
  57. package/src/form/field/Picker.mjs +0 -1
  58. package/src/form/field/Select.mjs +208 -257
  59. package/src/form/field/Text.mjs +3 -3
  60. package/src/form/field/trigger/Base.mjs +5 -6
  61. package/src/layout/Flexbox.mjs +23 -31
  62. package/src/layout/HBox.mjs +1 -1
  63. package/src/layout/VBox.mjs +1 -1
  64. package/src/list/Base.mjs +64 -31
  65. package/src/main/DomAccess.mjs +55 -28
  66. package/src/main/DomEvents.mjs +2 -1
  67. package/src/main/DomUtils.mjs +66 -0
  68. package/src/main/addon/Navigator.mjs +332 -0
  69. package/src/manager/DomEvent.mjs +2 -1
  70. package/src/selection/ListModel.mjs +46 -82
  71. package/src/selection/Model.mjs +56 -33
  72. package/src/util/Array.mjs +5 -2
  73. package/src/util/Function.mjs +31 -0
  74. package/src/util/String.mjs +9 -0
  75. package/src/vdom/Helper.mjs +1 -2
  76. package/test/components/app.mjs +4 -3
  77. package/test/components/files/component/ChipList.mjs +125 -0
  78. package/test/components/files/form/field/Select.mjs +177 -2
  79. package/test/components/siesta.js +34 -1
@@ -0,0 +1,214 @@
1
+ ##Introduction
2
+
3
+ In this topic you'll create an application that fetches data on earthquakes in Iceland,
4
+ and show the information in two views: a table, and a map.
5
+
6
+ You'll do this in a series of labs:
7
+
8
+ 1. Generate a workspace
9
+ 1. Generate a starter app
10
+ 1. Learn some debugging tricks
11
+ 1. Generate the earthquakes starter app
12
+ 1. Refactor a config into its own class
13
+ 1. Add a map
14
+ 1. Listen to events
15
+ 1. Make the app multi-window
16
+
17
+ ##Advice
18
+
19
+ A word of advice: Keep a high-level perspective, especially early on. Throughout this
20
+ tutorial, and others, We'll have plenty of time to get into the code, and we'll do
21
+ most things multiple times.
22
+
23
+ ##Lab. Generate a workspace
24
+
25
+ In this lab, you'll generate a Neo.mjs workspace and run the starter app.
26
+
27
+ <!-- lab -->
28
+ <details>
29
+ <summary>Use the command-line to generate the workspace</summary>
30
+
31
+ Use a terminal window to navigate to some parent folder,
32
+ then run
33
+
34
+ npx neo-app@latest
35
+
36
+ You'll be propted for a workspace name, starter app name, etc &mdash; accept the default for everything.
37
+ As the command finishes it starts a server and opens a browser window.
38
+ </details>
39
+
40
+ <details>
41
+ <summary>Inspect the workspace</summary>
42
+
43
+ The workspace contains a local copy of the API docs, an `apps` directory (where your apps are found),
44
+ and some other directories.
45
+ </details>
46
+
47
+ <details>
48
+ <summary>Start the server</summary>
49
+ From the root of the `workspace` start the server via `npm run server-start`. That starts a server
50
+ at port 8080 and opens a new browser window.
51
+
52
+ <img src="https://s3.amazonaws.com/mjs.neo.learning.images/earthquakes/StartServer.png" style="width:80%"/>
53
+
54
+ </details>
55
+
56
+
57
+ <details>
58
+ <summary>Run the starter app</summary>
59
+
60
+ By default, an app named `myapp` was created. You can run it by entering the `apps` directory and
61
+ clicking `myapp`. It's a folder containing an `index.html` along with the source code for the app.
62
+
63
+ <img src="https://s3.amazonaws.com/mjs.neo.learning.images/earthquakes/RunTheStarterApp.png" style="width:80%"/>
64
+
65
+ </details>
66
+
67
+ <!-- /lab -->
68
+
69
+
70
+ ##Anatomy
71
+
72
+ The purpose of the lab was to generate a workspace, but as long as we're here let's take a look
73
+ at the `workspace/apps/myapp` directory.
74
+
75
+ - `view/MainContainer.mjs`
76
+ - `app.mjs`
77
+ - `index.html`
78
+ - `neo-config.json`
79
+
80
+ Application source is in `.mjs` files. These are standard _modular JavaScript_ files
81
+ with `import` and `export` statements, and class definitions. Neo.mjs apps have one class
82
+ definition per `.mjs` source file.
83
+
84
+ The index file contains a script tag that runs `MicroLoader.mjs`, which is a simple
85
+ file that launches the app based on information found in `neo-config.json`.
86
+
87
+ Don't worry about the file contents for now: we'll do that in the next lab.
88
+
89
+ ##Flow of Execution
90
+
91
+ <img src="https://s3.amazonaws.com/mjs.neo.learning.images/FlowOfExecution.jpg" style="width:50%"/>
92
+
93
+ As you can see, `MicroLoader.mjs` runs `Main.mjs`, which in turn spawns the three web-wokers used by Neo.mjs:
94
+
95
+ - `neomjs-data-worker` handles Ajax calls and sockets
96
+ - `neomjs-vdom-worker` keeps track of the view (and applies delta updates to the main thread)
97
+ - `neomjs-app-worker` is where app logic is run
98
+
99
+ Neo.mjs apps run in multiple webworkers, and each webworker is run in a separate parallel thread.
100
+ Parallel processing &mdash; along wih the efficient way the `neomjs-vdom-worker` applies delta updates &mdash; is why Neo.mjs applications run so fast.
101
+
102
+ ##Commonly-used Scripts
103
+
104
+ If you look in the `package.json` script block you'll see several scripts used for generating applications and classes,
105
+ doing builds, and starting a server. We'll use several of them throughout the tutorials.
106
+
107
+ - create-app &mdash; creates a simple demo app
108
+ - create-app-minimal &mdash; creates a application shell with no content
109
+ - server-start &mdash; starts a server with webroot set to the workspace
110
+ - build-all &mdash; builds minimized versions of your apps
111
+ - build-themes &mdash; creates app .css from .scss files found in `resources/scss`
112
+ - watch-themes &mdash; creates app .css as you save changes to any app
113
+
114
+
115
+ ##Lab. Create the earthquakes starter app
116
+
117
+ <!-- lab -->
118
+
119
+ In this lab you'll create a starter app and add a single component.
120
+
121
+ <details>
122
+
123
+ <summary>Use the command-line to create a starter app</summary>
124
+
125
+ Use a terminal window to navigate to the workspace and run the following script. Use "Earthquakes"
126
+ as the app name, and <b>when prompted for "Main thread add-ons" choose GoogleMaps</b> (using arrow
127
+ keys and the space bar to toggle add-on options). Use defaults for everything else.
128
+
129
+ npm run generate-app-minimal
130
+
131
+ After the script runs yous should see these files in the `app/earthquakes` directory.
132
+
133
+ `view/MainContainer.mjs`
134
+ - `app.mjs`
135
+ - `index.html`
136
+ - `neo-config.json`
137
+
138
+ If you look in `neo-config.json` you should see this content. Note the `mainThreadAddons` block
139
+ &mdash; it specifies the default add-ons, as well as the GoogleMaps add-on you specified.
140
+ <pre>
141
+ {
142
+ "appPath": "../../apps/myapp/app.mjs",
143
+ "basePath": "../../",
144
+ "environment": "development",
145
+ "mainPath": "../node_modules/neo.mjs/src/Main.mjs",
146
+ "workerBasePath": "../../node_modules/neo.mjs/src/worker/",
147
+ "themes": [
148
+ "neo-theme-neo-light"
149
+ ]
150
+ }
151
+ </pre>
152
+
153
+ When the script finishes you should see
154
+
155
+ You'll be propted for a workspace name, starter app name, etc &mdash; accept the default for everything.
156
+ As the command finishes it starts a server and opens a browser window.
157
+ </details>
158
+
159
+ <details>
160
+ <summary>Look at the main view source</summary>
161
+
162
+ </details>
163
+
164
+ <details>
165
+ <summary>Add a component</summary>
166
+
167
+ </details>
168
+
169
+
170
+ <details>
171
+ <summary>Start the server</summary>
172
+
173
+ </details>
174
+
175
+ <!-- /lab -->
176
+
177
+ ##Introduction to Debugging
178
+
179
+ ##Lab. Debugging
180
+
181
+ In this lab you'll get a little debugging practice by getting component references, changing properties,
182
+ and runing methods.
183
+
184
+ <!-- lab -->
185
+
186
+ <details>
187
+ <summary>Inspect the workspace</summary>
188
+
189
+ The workspace contains a local copy of the API docs, an `apps` directory (where your apps are found),
190
+ and some other directories.
191
+ </details>
192
+
193
+ <details>
194
+ <summary>Start the server</summary>
195
+ From the root of the `workspace` start the server via `npm run server-start`. That starts a server
196
+ at port 8080 and opens a new browser window.
197
+
198
+ <img src="https://s3.amazonaws.com/mjs.neo.learning.images/earthquakes/StartServer.png" style="width:80%"/>
199
+
200
+ </details>
201
+
202
+
203
+ <details>
204
+ <summary>Run the starter app</summary>
205
+
206
+ By default, an app named `myapp` was created. You can run it by entering the `apps` directory and
207
+ clicking `myapp`. It's a folder containing an `index.html` along with the source code for the app.
208
+
209
+ <img src="https://s3.amazonaws.com/mjs.neo.learning.images/earthquakes/RunTheStarterApp.png" style="width:80%"/>
210
+
211
+
212
+ </details>
213
+
214
+ <!-- /lab -->
@@ -1 +1,142 @@
1
- ### todo: Events
1
+ All components fire events. For example, form fields fire a `change` event, various
2
+ focus events, and others. Some other types fire events too, such as `Neo.data.Store`,
3
+ which fires a `load` event after the store is loaded with data.
4
+
5
+ Some terminology related to events is that events are _fired_, and as a result, some
6
+ event _handler_ &mdash; or _listener_ &mdash; is run.
7
+
8
+ To specify an event handler, use `listeners: {}`, specifying in as many event/handler
9
+ pairs as you need.
10
+
11
+ 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.)
13
+
14
+ <pre data-neo>
15
+ import Base from '../../../../src/container/Base.mjs';
16
+ import TextField from '../../../../src/form/field/Text.mjs';
17
+ class MainView extends Base {
18
+ static config = {
19
+ className : 'Example.view.MainView',
20
+ layout: {ntype:'vbox', align:'start'},
21
+ items : [{
22
+ module: TextField,
23
+ labelText : 'First name',
24
+ listeners: {
25
+ change: data=>console.log(data.value), // There are other properties, like oldValue
26
+ focusEnter: data=>console.log(`Entering ${data.component.labelText}`)
27
+ }
28
+ },
29
+ {
30
+ module: TextField,
31
+ labelText : 'Last name',
32
+ listeners: {
33
+ change: data=>console.log(data.value), // There are other properties, like oldValue
34
+ focusEnter: data=>console.log(`Entering ${data.component.labelText}`)
35
+ }
36
+ }]
37
+ }
38
+ }
39
+ Neo.applyClassConfig(MainView);
40
+ </pre>
41
+
42
+ If you run the example, and open the browser's debugger, you'll see the console being logged as you type or give
43
+ focus to either field.
44
+
45
+ Note that the handlers specify an in-line function. For trivial cases, that might be ok. But normally
46
+ you'd want better separation of concerns by placing those event handlers in a separate class. Neo.mjs provides
47
+ that with a _component controller_.
48
+
49
+ 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.
51
+
52
+ <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';
56
+
57
+ class MainViewController extends Controller {
58
+ static config = {
59
+ className: 'Example.view.MainViewController'
60
+ }
61
+ onChange(data){
62
+ console.log(data.value);
63
+ }
64
+ }
65
+ Neo.applyClassConfig(MainViewController);
66
+
67
+
68
+ class MainView extends Base {
69
+ static config = {
70
+ className : 'Example.view.MainView',
71
+ controller: MainViewController,
72
+ layout: {ntype:'vbox', align:'start'},
73
+ items : [{
74
+ module: TextField,
75
+ labelText : 'Name',
76
+ listeners: {
77
+ change: 'onChange'
78
+ }
79
+ }]
80
+ }
81
+ }
82
+ Neo.applyClassConfig(MainView);
83
+ </pre>
84
+
85
+ (It's important to keep in mind that in Neo.mjs, all class definitions are coded in their own
86
+ source file: one class per file. In the examples we're putting all the relevant classes together
87
+ to make it easier to see the source code for every class being used. But in an
88
+ actual applications the controller class would be coded in its own source file &mdash; named something
89
+ like `MainViewController.mjs` &mdash; and that would be imported into the view.)
90
+
91
+ The ability to fire events and add listeners is provided by `Neo.core.Observable`, which is mixed into
92
+ classes that need that ability. All components are observable, `Neo.data.Store` is observable, and some
93
+ others. `Neo.core.Observable` introduces a few methods and properties, such as `listeners`, which
94
+ is used in the examples above, `on()` for procedurally adding an event listener, and `fire()`, which is
95
+ how you fire events in the custom classes you create.
96
+
97
+ Here's example illustrating how `fire()` is used. The code defines a `ToggleButton`
98
+ class, which is just a button with a `checked` property: the button shows a checked or unchecked
99
+ checkbox depending on the value of `checked`.
100
+
101
+ The code uses a special Neo.mjs feature you haven't seen yet &mdash; the use of an underscore property.
102
+ We'll discuss that at length later, but in a nutshell, config properties ending in an underscore
103
+ automatically get lifecycle methods run before the value is assigned, after the value is assigned, and
104
+ before the value is accessed. We're using the _after_ method to fire a `change` event.
105
+
106
+ <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';
110
+
111
+ class ToggleButton extends Button {
112
+ static config = {
113
+ className: 'Example.view.ToggleButton',
114
+ checked_: false
115
+ }
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
119
+ }
120
+ onClick(data){
121
+ super.onClick(data);
122
+ this.checked = !this.checked;
123
+ }
124
+ }
125
+ Neo.applyClassConfig(ToggleButton);
126
+
127
+
128
+ class MainView extends Base {
129
+ static config = {
130
+ className : 'Example.view.MainView',
131
+ layout: {ntype:'vbox', align:'start'},
132
+ items : [{
133
+ module: ToggleButton,
134
+ text: 'Toggle',
135
+ listeners: {
136
+ change: data => console.log(data.checked) // Here, we're listening to the custom event
137
+ }
138
+ }]
139
+ }
140
+ }
141
+ Neo.applyClassConfig(MainView);
142
+ </pre>
@@ -1 +1,116 @@
1
- ### todo: Extending Components
1
+ In theory, a Neo.mjs app could be defined in a single `.mjs` source file. But that would be very hard to
2
+ maintain, and any reusable configs would have to be duplicated. Instead, each of your views and reusable
3
+ widgets will be defined as its own class. The result is simpler views which are inherently reusable and easier
4
+ to test.
5
+
6
+ Consider this code. It's a panel with a header and a table. The table has a store.
7
+
8
+ <pre data-neo>
9
+ import Base from '../../../../src/container/Panel.mjs';
10
+ import Button from '../../../../src/button/Base.mjs';
11
+ import Table from '../../../../src/table/Container.mjs';
12
+
13
+ class MainView extends Base {
14
+ static config = {
15
+ className : 'Example.view.MainView',
16
+ headers: [{
17
+ dock: 'top',
18
+ items: [{
19
+ module: Button,
20
+ text: 'She loves me...',
21
+ handler: () => Neo.Main.alert({message: 'Yeah, yeah yeah!'})
22
+ }]
23
+ }],
24
+ items : [{
25
+ module: Table,
26
+ store: {
27
+ autoLoad: true,
28
+ url: '../../resources/data/deck/learnneo/data/theBeatles.json',
29
+ model: {
30
+ fields: [{name: 'first'}, {name: 'last'}, {name: 'dob', type: 'date'}]
31
+ }
32
+ },
33
+ columns: [{
34
+ text: 'First',
35
+ dataField: 'first',
36
+ }, {
37
+ text: 'Last',
38
+ dataField: 'last',
39
+ }]
40
+ }]
41
+ }
42
+ }
43
+ Neo.applyClassConfig(MainView);
44
+ </pre>
45
+
46
+ If you wanted, any of the configs can be refactored into their own class. Here, the button, store, and table
47
+ have been refactored into their own classes, and the main view is using them. The main view is simpler and
48
+ more abstract, and each class can be reused, tested, and maintained independently.
49
+
50
+ <pre data-neo>
51
+ import Base from '../../../../src/container/Panel.mjs';
52
+ import Button from '../../../../src/button/Base.mjs';
53
+ import Table from '../../../../src/table/Container.mjs';
54
+ import Store from '../../../../src/data/Store.mjs';
55
+
56
+ class BeatlesButton extends Button {
57
+ static config = {
58
+ className: 'Example.view.BeatlesButton',
59
+ text: 'She loves me...',
60
+ handler: () => Neo.Main.alert({message: 'Yeah, yeah yeah!'})
61
+ }
62
+ }
63
+ Neo.applyClassConfig(BeatlesButton);
64
+
65
+ class BeatlesStore extends Store {
66
+ static config = {
67
+ className: 'Example.view.BeatlesStore',
68
+ autoLoad: true,
69
+ url: '../../resources/data/deck/learnneo/data/theBeatles.json',
70
+ model: {
71
+ fields: [{name: 'first'}, {name: 'last'}, {name: 'dob', type: 'date'}]
72
+ }
73
+ }
74
+ }
75
+ Neo.applyClassConfig(BeatlesStore);
76
+
77
+ class BeatlesTable extends Table {
78
+ static config = {
79
+ className: 'Example.view.BeatlesTable',
80
+ columns: [{
81
+ text: 'First',
82
+ dataField: 'first',
83
+ }, {
84
+ text: 'Last',
85
+ dataField: 'last',
86
+ }]
87
+ }
88
+ }
89
+ Neo.applyClassConfig(BeatlesTable);
90
+
91
+ class MainView extends Base {
92
+ static config = {
93
+ className : 'Example.view.MainView',
94
+ headers: [{
95
+ dock: 'top',
96
+ items: [{
97
+ module: BeatlesButton,
98
+ }]
99
+ }],
100
+ items : [{
101
+ module: BeatlesTable,
102
+ store: {
103
+ module: BeatlesStore
104
+ },
105
+ }]
106
+ }
107
+ }
108
+ Neo.applyClassConfig(MainView);
109
+ </pre>
110
+
111
+ There are several use-cases for creating your own classes:
112
+
113
+ - For reuse
114
+ - To isolate complexity
115
+ - To add events or methods to the new class
116
+ - To test the component independently
@@ -0,0 +1,126 @@
1
+ Controllers often need to get references to components in order to update
2
+ the UI or access component properties.
3
+ There are two common ways of doing that:
4
+
5
+ - Using the component references passed to the event handler
6
+ - Tagging a component with a `reference` and using `this.getReference()` in the controller
7
+
8
+ Here's an example with one button. Clicking on the button will disable it.
9
+ As you can see, the handler uses the component reference pass in via `data.component`.
10
+
11
+ <pre data-neo>
12
+ import Base from '../../../../src/container/Base.mjs';
13
+ import Controller from '../../../../src/controller/Component.mjs';
14
+ import Button from '../../../../src/Button/Base.mjs';
15
+
16
+ class MainViewController extends Controller {
17
+ static config = {
18
+ className: 'Example.view.MainViewController'
19
+ }
20
+ onDisableButtonClick(data){
21
+ data.component.disabled = true;
22
+ }
23
+ }
24
+ Neo.applyClassConfig(MainViewController);
25
+
26
+
27
+ class MainView extends Base {
28
+ static config = {
29
+ className : 'Example.view.MainView',
30
+ controller: MainViewController,
31
+ layout: {ntype:'vbox', align:'start'},
32
+ items : [{
33
+ module: Button,
34
+ text: 'Disable this button',
35
+ handler: 'onDisableButtonClick'
36
+ }]
37
+ }
38
+ }
39
+ Neo.applyClassConfig(MainView);
40
+ </pre>
41
+
42
+ But what if we need to get a reference to another component in the view? In that case
43
+ you tag the component you need with a `reference` config, then use `getReference()` in
44
+ the controller.
45
+
46
+ <pre data-neo>
47
+ import Base from '../../../../src/container/Base.mjs';
48
+ import Controller from '../../../../src/controller/Component.mjs';
49
+ import Button from '../../../../src/Button/Base.mjs';
50
+
51
+ class MainViewController extends Controller {
52
+ static config = {
53
+ className: 'Example.view.MainViewController'
54
+ }
55
+ onDisableButtonClick(data){
56
+ data.component.disabled = true;
57
+ }
58
+ onEnableButtonClick(data){
59
+ this.getReference('myButton').disabled = false;
60
+ }
61
+ }
62
+ Neo.applyClassConfig(MainViewController);
63
+
64
+
65
+ class MainView extends Base {
66
+ static config = {
67
+ className : 'Example.view.MainView',
68
+ controller: MainViewController,
69
+ layout: {ntype:'vbox', align:'start'},
70
+ items : [{
71
+ module: Button,
72
+ reference: 'myButton',
73
+ text: 'Disable this button',
74
+ handler: 'onDisableButtonClick'
75
+ }, {
76
+ module: Button,
77
+ text: 'Enable the other button',
78
+ handler: 'onEnableButtonClick'
79
+ }]
80
+ }
81
+ }
82
+ Neo.applyClassConfig(MainView);
83
+ </pre>
84
+
85
+
86
+ There are other ways of getting references, but these are either non-standard or for debugging.
87
+ For example, components have an `up()` method, and containers have a `down()` method. These look
88
+ up or down the containment hierarchy to find the specified component. Using these methods is poor technique
89
+ becuse it violates principles of encapsulation and limiting scope.
90
+
91
+ There are also debugging methods, such as `Neo.findFirst()` which will find any component matching
92
+ the search param.
93
+
94
+ When you're debugging it's pretty handy to be able to inspect or interact with any component in the app.
95
+ But app logic should never use `Neo.findFirst()` and very rarely use `up()` or `down()`.
96
+
97
+ The following example gets a reference to the _Learn_ button at the top of this site, and changes its `text`.
98
+ Again &mdash; that use of `Neo.findFirst()` might be handy when debugging, but it should never be used in app logic.
99
+
100
+ <pre data-neo>
101
+ import Base from '../../../../src/container/Base.mjs';
102
+ import Button from '../../../../src/Button/Base.mjs';
103
+
104
+ class MainView extends Base {
105
+ static config = {
106
+ className : 'Example.view.MainView',
107
+ layout: {ntype:'vbox', align:'start'},
108
+ items : [{
109
+ module: Button,
110
+ text: 'Change Learn caption',
111
+ handler: data=>{
112
+ const component = Neo.findFirst({text:'Learn'});
113
+ if (component) component.text = 'Yikes!';
114
+ }
115
+ }, {
116
+ module: Button,
117
+ text: 'Restore Learn caption',
118
+ handler: data=>{
119
+ const component = Neo.findFirst({text:'Yikes!'});
120
+ if (component) component.text = 'Learn';
121
+ }
122
+ }]
123
+ }
124
+ }
125
+ Neo.applyClassConfig(MainView);
126
+ </pre>
@@ -1,10 +1,32 @@
1
+ To code a live preview, enclose the code in a `pre` tag with the `data-neo` attribute.
1
2
 
2
- sdfiousodfi
3
-
4
- <pre data-neo>
5
- let a = 1;
6
- </pre>
3
+ <pre>&lt;pre data-neo>
4
+ &lt;/pre>
7
5
 
6
+ Imports are relative to the portal app running within the framework. That means
7
+ Neo.mjs imports should be coded to go up four levels, then look into the `src`
8
+ directory. For example, to import _container_, use `import Base from '../../../../src/container/Base.mjs`
8
9
 
10
+ You can define as many classes you need, such as component models and controllers, but the the _last_
11
+ class being defined is assumed to be the view being rendered. In other words, if the final class definition is a component, it's rendered.
9
12
 
10
- slfiksdf
13
+ <pre data-neo>
14
+ import Base from '../../../../src/container/Base.mjs';
15
+ import Button from '../../../../src/button/Base.mjs';
16
+ import Split from '../../../../src/button/Split.mjs';
17
+ class Bar extends Base {
18
+ static config = {
19
+ ntype: 'demoFoo',
20
+ className: 'Foo.Bar',
21
+ layout: {ntype: 'hbox'},
22
+ items: [{
23
+ module: Button,
24
+ text: 'Button One'
25
+ },{
26
+ module: Button,
27
+ text: 'Button Two'
28
+ }]
29
+ }
30
+ }
31
+ Neo.applyClassConfig(Bar);
32
+ </pre>
@@ -5,14 +5,13 @@
5
5
  {"name": "Workspaces and Applications", "parentId": "GettingStarted", "isLeaf": true, "id": "2023-10-14T19-25-08-153Z"},
6
6
  {"name": "Describing a View", "parentId": "GettingStarted", "isLeaf": true, "id": "DescribingTheUI"},
7
7
  {"name": "Events", "parentId": "GettingStarted", "isLeaf": true, "id": "Events"},
8
- {"name": "Updating View State", "parentId": "GettingStarted", "isLeaf": true, "id": "ComponentState"},
9
- {"name": "Extending Components", "parentId": "GettingStarted", "isLeaf": true, "id": "Extending"},
10
- {"name": "Adding Properties", "parentId": "GettingStarted", "isLeaf": true, "id": "AddingProperties"},
11
- {"name": "Component Models and Binding", "parentId": "GettingStarted", "isLeaf": true, "id": "ComponentModels"},
12
- {"name": "What about HTML tags?", "parentId": "GettingStarted", "isLeaf": true, "id": "WhatAboutHTML"},
8
+ {"name": "Component References", "parentId": "GettingStarted", "isLeaf": true, "id": "References"},
9
+ {"name": "Extending Classes", "parentId": "GettingStarted", "isLeaf": true, "id": "Extending"},
10
+ {"name": "Config", "parentId": "GettingStarted", "isLeaf": true, "id": "Config"},
11
+ {"name": "Shared Bindable Data", "parentId": "GettingStarted", "isLeaf": true, "id": "ComponentModels"},
13
12
  {"name": "Tutorials", "parentId": null, "isLeaf": false, "expanded": false, "id": "Tutorials"},
14
13
  {"name": "Rock Scissors Paper", "parentId": "Tutorials", "isLeaf": true, "expanded": false, "id": "RSP"},
15
- {"name": "Earthquakes", "parentId": "Tutorials", "isLeaf": false, "expanded": false, "id": "Earthquakes"},
14
+ {"name": "Earthquakes", "parentId": "Tutorials", "isLeaf": true, "expanded": false, "id": "Earthquakes"},
16
15
  {"name": "Cookbook", "parentId": null, "isLeaf": false, "expanded": false, "id": "InDepth"},
17
16
  {"name": "Config", "parentId": "InDepth", "isLeaf": false, "id": "Config"},
18
17
  {"name": "Instance Lifecycle", "parentId": "InDepth", "isLeaf": false, "id": "InstanceLifecycle"},
@@ -1 +1 @@
1
- <img height="540" src="resources/images/FlowOfExecution.jpg"></img>
1
+ <img height="540" src="https://s3.amazonaws.com/mjs.neo.learning.images/FlowOfExecution.jpg"></img>
@@ -1 +1 @@
1
- <img height="580" src="resources/images/intro/InitialTable.png"/>
1
+ <img height="580" src="https://s3.amazonaws.com/mjs.neo.learning.images/intro/InitialTable.png"/>
@@ -4,4 +4,4 @@ Let's do a little code inspection using
4
4
 
5
5
  Look in the API docs to find the `ntype`.
6
6
 
7
- <img height="300" src="resources/images/intro/FindingNtype.png"/>
7
+ <img height="300" src="https://s3.amazonaws.com/mjs.neo.learning.images/intro/FindingNtype.png"/>