volt 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Readme.md +397 -9
- data/VERSION +1 -1
- data/lib/volt/cli.rb +2 -2
- metadata +1 -2
- data/docs/GUIDE.md +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df8458b3edc5a01799ef25000fcbc24784a48adb
|
4
|
+
data.tar.gz: df391e8bc1a530609f298fa68b9427ec924a7dfe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50e1892a9eba4e433bd01fd3d7c22ab6153ee6cf0bcf9f46ea301f72d87cb4d9ea20e35431453718b177ee08ae3322386505be8210b48b2d05d489f2e9e25dfb
|
7
|
+
data.tar.gz: d74604adfa3a6b73eb5f61e011fae1d25e1fb623e0248f9b8a1066ee197c0d3d5203c8e562d04081cae91937e53fe1ec22fbf9f5c1aeda0fa2c8aaa81329bbd9
|
data/Readme.md
CHANGED
@@ -24,21 +24,409 @@ Volt has the following goals:
|
|
24
24
|
7. Secure (shouldn't need to be said, but it does)
|
25
25
|
8. Be fast/light
|
26
26
|
9. Understandable code base
|
27
|
-
10.
|
27
|
+
10. Control Upgradeability
|
28
28
|
|
29
|
-
|
29
|
+
# VOLT guide
|
30
30
|
|
31
|
-
|
32
|
-
Everyone wishes that we could predict the scope and required features for each part of our application, but in the real world, things we don't expect to grow large often do and things we think will be large don't end up that way. Volt provides an easy way to promote sections of html and code to provide more
|
31
|
+
This guide will take you through creating a basic web application in Volt. This tutorial assumes a basic knowledge of ruby and web development.
|
33
32
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
To get started, install volt:
|
34
|
+
|
35
|
+
gem install volt
|
36
|
+
|
37
|
+
Then create a new project:
|
38
|
+
|
39
|
+
volt new project_name
|
40
|
+
|
41
|
+
This will setup a basic project. Now lets run the server.
|
42
|
+
|
43
|
+
volt server
|
44
|
+
|
45
|
+
You can access the volt console with:
|
46
|
+
|
47
|
+
volt console
|
48
|
+
|
49
|
+
# Guide Sections
|
50
|
+
|
51
|
+
1. [Rendering](#rendering)
|
52
|
+
1. [Reactive Values](#reactive-values)
|
53
|
+
2. [Bindings](#bindings)
|
54
|
+
1. [Content Binding](#content-binding)
|
55
|
+
2. [If Binding](#if-binding)
|
56
|
+
3. [Each Binding](#each-binding)
|
57
|
+
4. [Attribute Bindings](#attribute-bindings)
|
58
|
+
2. [Models](#models)
|
59
|
+
3. [Components](#components)
|
60
|
+
4. [Controls](#controls)
|
61
|
+
5. [Routes](#routes)
|
62
|
+
1. [Routes file](#routes-file)
|
63
|
+
|
64
|
+
|
65
|
+
# Rendering
|
66
|
+
|
67
|
+
When a user interacts with a web page, typically we want to do two things:
|
68
|
+
|
69
|
+
1. Change application state
|
70
|
+
2. Update the DOM
|
71
|
+
|
72
|
+
For example when a user clicks to add a new todo item to a todo list, we might create a JavaScript object to represent the todo item, then add an item to the list's DOM. A lot of work needs to be done to make sure that the JavaScript object and the DOM always stay in sync.
|
73
|
+
|
74
|
+
Recently the idea of "reactive programming" has been used to simplify maintaining the DOM. The idea is instead of having event handlers that manage a model (or JavaScript object) and manage the DOM, we have event handlers that manage reactive data models. We describe our DOM layer in a declarative way so that it automatically knows how to render our data models.
|
75
|
+
|
76
|
+
## Reactive Value's
|
77
|
+
|
78
|
+
To build bindings, Volt provides the ReactiveValue class. This wraps any object in a reactive interface. To create a ReactiveValue, simply pass the object you want to wrap as the first argument to new.
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
a = ReactiveValue.new("my object")
|
82
|
+
|
83
|
+
# => @"my object"
|
84
|
+
```
|
85
|
+
|
86
|
+
When .inspect is called on a ReactiveValue (like in the console), an @ is placed infront of the value's inspect string, so you know its reactive.
|
87
|
+
|
88
|
+
When you call a method on a ReactiveValue, you get back a new reactive value that depends on the previous one. It remebers how it was created and you can call .cur on it any time to get its current value, which will be computed based off of the first reactive value. (Keep in mind below that + is a method call, the same as a.+(b) in ruby.)
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
a = ReactiveValue.new(1)
|
92
|
+
a.reactive?
|
93
|
+
# => true
|
94
|
+
|
95
|
+
a.cur
|
96
|
+
# => 1
|
97
|
+
|
98
|
+
b = a + 5
|
99
|
+
b.reactive?
|
100
|
+
# => true
|
101
|
+
|
102
|
+
b.cur
|
103
|
+
# => 6
|
104
|
+
|
105
|
+
a.cur = 2
|
106
|
+
b.cur
|
107
|
+
# => 7
|
108
|
+
```
|
109
|
+
|
110
|
+
This provides the backbone for reactive programming. We setup computation/flow graphs instead of doing an actual calcuation. Calling .cur (or .inspect, .to_s, etc..) runs the computation and returns the current value at that time, based on all of its dependencies.
|
111
|
+
|
112
|
+
ReactiveValue's also let you setup listeners and trigger events:
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
a = ReactiveValue.new(0)
|
116
|
+
a.on('changed') { puts "A changed" }
|
117
|
+
a.trigger!('changed')
|
118
|
+
# => A Changed
|
119
|
+
```
|
120
|
+
|
121
|
+
These events propigate to any reactive value's created off of a reactive value.
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
a = ReactiveValue.new(1)
|
125
|
+
b = a + 5
|
126
|
+
b.on('changed') { puts "B changed" }
|
127
|
+
|
128
|
+
a.trigger!('changed')
|
129
|
+
# => B changed
|
130
|
+
```
|
131
|
+
|
132
|
+
This event flow lets us know when an object has changed, so we can update everything that depended on that object.
|
133
|
+
|
134
|
+
Lastly, we can also pass in other reactive value's as arguments to methods on a reactive value. The dependencies will be tracked for both and events will propigate down from both. (Also, note that doing .cur = to update the current value triggers a "changed" event.)
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
a = ReactiveValue.new(1)
|
138
|
+
b = ReactiveValue.new(2)
|
139
|
+
c = a + b
|
140
|
+
|
141
|
+
a.on('changed') { puts "A changed" }
|
142
|
+
b.on('changed') { puts "B changed" }
|
143
|
+
c.on('changed') { puts "C changed" }
|
144
|
+
|
145
|
+
a.cur = 3
|
146
|
+
# => A changed
|
147
|
+
# => C changed
|
148
|
+
|
149
|
+
b.cur = 5
|
150
|
+
# => B changed
|
151
|
+
# => C changed
|
152
|
+
```
|
153
|
+
|
154
|
+
### Truthy Checks: .true?, .false?, .or, and .and
|
155
|
+
|
156
|
+
Because a method on a reactive value always returns another reactive value, and because only nil and false are false in ruby, we need a way to check if a ReactiveValue is truthy in our code. The easiest way to do this is by calling .true? on it. It will return a non-wrapped boolean. .nil? and .false? do as you would expect.
|
157
|
+
|
158
|
+
One common place we use a truthy check is in setting up default values with || (logical or) Volt provides a convience method that does the same thing .or, but works with ReactiveValue's.
|
159
|
+
|
160
|
+
Instead of
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
a || b
|
164
|
+
```
|
165
|
+
|
166
|
+
Simply use:
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
a.or(b)
|
170
|
+
```
|
171
|
+
|
172
|
+
.and works the same way as &&. #and and #or let you maintain the reactivity all of the way through.
|
173
|
+
|
174
|
+
|
175
|
+
### With
|
176
|
+
|
177
|
+
|
178
|
+
|
179
|
+
## Bindings
|
180
|
+
|
181
|
+
Now that you understand the basics of ReactiveValue's, we can discuss bindings. In Volt, you code your views in a handlebar's like template language. Volt provides severial bindings, which handle rendering of something for you. Content bindings are anything inbetween { and }
|
182
|
+
|
183
|
+
### Content binding
|
184
|
+
|
185
|
+
The most basic binding is a content binding:
|
186
|
+
|
187
|
+
<p>{some_method}<p>
|
188
|
+
|
189
|
+
The content binding runs the ruby code between { and }, then renders the return value. If the returned value is a ReactiveValue, it will update the value updated whenever a 'changed' event is called.
|
190
|
+
|
191
|
+
### If binding
|
192
|
+
|
193
|
+
An if binding lets you provide basic flow control.
|
194
|
+
|
195
|
+
{#if _some_check?}
|
196
|
+
<p>render this</p>
|
197
|
+
{/}
|
198
|
+
|
199
|
+
Blocks are closed with a {/}
|
200
|
+
|
201
|
+
When the #if binding is rendered, it will run the ruby code after #if. If the code is true it will render the code below. Again, if the returned value is reactive, it will update as that value changes.
|
202
|
+
|
203
|
+
If bindings can also have #elsif and #else blocks.
|
204
|
+
|
205
|
+
{#if _condition_1?}
|
206
|
+
<p>condition 1 true</p>
|
207
|
+
{#elsif _condition_2?}
|
208
|
+
<p>condition 2 true</p>
|
209
|
+
{#else}
|
210
|
+
<p>neither true</p>
|
211
|
+
{/}
|
212
|
+
|
213
|
+
### Each binding
|
214
|
+
|
215
|
+
For iteration over objects, the each binding is provided.
|
216
|
+
|
217
|
+
{#each _items as item}
|
218
|
+
<p>{item}</p>
|
219
|
+
{/}
|
220
|
+
|
221
|
+
Above, if _items was an array, the block would be rendered for each item, setting 'item' to the value of the array element.
|
222
|
+
|
223
|
+
You can also access the position of the item in the array with the #index method.
|
224
|
+
|
225
|
+
{#each _items as item}
|
226
|
+
<p>{index}. {item}</p>
|
227
|
+
{/}
|
228
|
+
|
229
|
+
For the array: ['one', 'two', 'three'] this would print:
|
230
|
+
|
231
|
+
0. one
|
232
|
+
1. two
|
233
|
+
2. three
|
234
|
+
|
235
|
+
You can do {index + 1} to correct the numbers.
|
236
|
+
|
237
|
+
When items are removed or added to the array, the #each binding automatically and intellegently add or removes the items from/to the dom.
|
238
|
+
|
239
|
+
## Attribute Bindings
|
240
|
+
|
241
|
+
Bindings can also be placed inside of attributes.
|
242
|
+
|
243
|
+
<p class="{#if _is_cool?}cool{/}">Text</p>
|
244
|
+
|
245
|
+
There are some special features provided to make for elements work as "two way bindings"
|
246
|
+
|
247
|
+
<input type="text" value="{_name}" />
|
248
|
+
|
249
|
+
In the example above, if _name changes, the field will update and if the field is updated, _name will be changed.
|
250
|
+
|
251
|
+
<input type="checkbox" checked="{_checked}" />
|
252
|
+
|
253
|
+
If the value of a checked attribute is true, the checkbox will be shown checked. If it is checked/unchecked, the value will be updated to true or false.
|
254
|
+
|
255
|
+
-- TODO: select boxes
|
256
|
+
|
257
|
+
If you have a controller at app/home/controller/index_controller.rb, and a view at app/home/views/index/index.html, all methods called are called on the controller.
|
258
|
+
|
259
|
+
# Models
|
260
|
+
|
261
|
+
Volt's concept of a model is slightly different from many frameworks where a model is the name for the ORM to the database. In Volt a model is a class where you can store data easily. Where that data stored is not the concern of the model, but the class that created the model. Lets first see how to use a model.
|
262
|
+
|
263
|
+
Volt comes with many built-in models, one is called 'page'. If you call #page on a controller, you will get access to the model. Models provided by Volt are automatically wrapped in a ReactiveValue.
|
264
|
+
|
265
|
+
```ruby
|
266
|
+
page._name = 'Ryan'
|
267
|
+
page._name
|
268
|
+
# => @'Ryan'
|
269
|
+
```
|
270
|
+
|
271
|
+
Models act like a hash that you can access with getters and setters that start with an _ Prefixing with an underscore makes sure we don't accidentally try to call a method that doesn't exist and get back nil. There is no need to define which fields a model has, they act similar to a hash, but with a shorter access and assign syntax.
|
272
|
+
|
273
|
+
Models also let you nest data:
|
274
|
+
|
275
|
+
```ruby
|
276
|
+
page._settings._color = 'blue'
|
277
|
+
page._settings._color
|
278
|
+
# => @'blue'
|
279
|
+
|
280
|
+
page._settings
|
281
|
+
# => @#<Model:_settings {:_color=>"blue"}>
|
282
|
+
```
|
283
|
+
|
284
|
+
Nested data is automatically setup when assigned. In this case, page._settings is a model that is part of the page model.
|
285
|
+
|
286
|
+
You can also append to a model if its not defined yet.
|
287
|
+
|
288
|
+
```ruby
|
289
|
+
page._items << 'item 1'
|
290
|
+
page._items
|
291
|
+
# => @#<ArrayModel ["item 1", "item 2"]>
|
292
|
+
|
293
|
+
page._items[0]
|
294
|
+
# => @"item 1"
|
295
|
+
```
|
296
|
+
|
297
|
+
An array model will automatically be setup to contain the items appended.
|
298
|
+
|
299
|
+
Above I mentioned that Volt comes with many different models accessable from a controller. Each stores in a different location.
|
300
|
+
|
301
|
+
| Name | Storage Location |
|
302
|
+
|-----------|---------------------------------------------------------------------------|
|
303
|
+
| page | page provides a temporary store that only lasts for the life of the page. |
|
304
|
+
| store | store syncs the data to the backend database and provides query methods. |
|
305
|
+
| session | values will be stored in a session cookie. |
|
306
|
+
| params | values will be stored in the params and url. Routes can be setup to change how params are shown in the url. (See routes for more info) |
|
307
|
+
| controller| a model for the current controller |
|
308
|
+
|
309
|
+
**more storage locations are planned**
|
310
|
+
|
311
|
+
## Reactive Models
|
312
|
+
|
313
|
+
Because all models provided by Volt are wrapped in a ReactiveValue, you can register listeners on them and be updated when values change. You can also call methods on their values and get updates when the source's change. Bindings also setup listeners. Models should be the main place you store all data in Volt. While you can use ReactiveValue's manually, most of the time you will want to just use something like the page model.
|
38
314
|
|
39
315
|
# Components
|
40
316
|
|
41
317
|
Apps are made up of Components. Each folder under app/ is a component. When you visit a route, it loads all of the files in the component on the front end, so new pages within the component can be rendered on the front end. If a url is visited that routes to a different component, the request will be loaded as a normal page load and all of that components files will be loaded. You can think of components as the "reload boundry" between sections of your app.
|
42
318
|
|
319
|
+
You can also use controls (see below) from one component in another. To do this, you must require the component from the component you wish to use them. This can be done in the ```config/dependencies.rb``` file. Just put
|
320
|
+
|
321
|
+
```ruby
|
322
|
+
component 'component_name'
|
323
|
+
```
|
324
|
+
|
325
|
+
in the file.
|
326
|
+
|
327
|
+
Dependencies act just like require in ruby, but for whole components.
|
328
|
+
|
329
|
+
## Component Generator
|
330
|
+
|
331
|
+
Components can easily be shared as a gem. Volt provides a scaffold for component gems. In a folder (not in a volt project), simply type: volt component {component_name} This will create the files needed for the gem. Note that all volt component gems will be prefixed with volt- so they can easily be found by others.
|
332
|
+
|
333
|
+
While developing, you can use the component by placing the following in your Gemfile:
|
334
|
+
|
335
|
+
gem 'volt-{component_name}', path: '/path/to/folder/with/component'
|
336
|
+
|
337
|
+
Once the gem is ready, you can release it to ruby gems with:
|
338
|
+
|
339
|
+
rake release
|
340
|
+
|
341
|
+
Remove the path: option in the gemfile if you wish to use the rubygems version.
|
342
|
+
|
43
343
|
# Controls
|
44
|
-
|
344
|
+
|
345
|
+
Everyone wishes that we could predict the scope and required features for each part of our application, but in the real world, things we don't expect to grow large often do and things we think will be large don't end up that way. Controls let you quickly setup reusable code/views. The location of the control's code can be moved as it grows without changing the way controls are invoked.
|
346
|
+
|
347
|
+
To render a control, simply use a tag like so:
|
348
|
+
|
349
|
+
```html
|
350
|
+
<:control-name />
|
351
|
+
```
|
352
|
+
|
353
|
+
or
|
354
|
+
|
355
|
+
```html
|
356
|
+
<:control-name></:control-name>
|
357
|
+
```
|
358
|
+
|
359
|
+
To find the control's views and optional controller, Volt will search the following (in order):
|
360
|
+
|
361
|
+
|
362
|
+
| Component | View Folder | View File | Section |
|
363
|
+
|-------------|----------------|--------------|-----------|
|
364
|
+
| | | | :{name} |
|
365
|
+
| | | {name}.html | :body |
|
366
|
+
| | {name} | index.html | :body |
|
367
|
+
| {name} | index | index.html | :body |
|
368
|
+
| gems/{name} | index | index.html | :body |
|
369
|
+
|
370
|
+
**Note that anything with a view folder will also load a controller if the name/folder matches.**
|
371
|
+
|
372
|
+
|
373
|
+
Each part is explained below:
|
374
|
+
|
375
|
+
1. section
|
376
|
+
Views are composed of sections. Sections start with a ```<:SectionName>``` tag and end with ```</:SectionName>``` Volt will look first for a section in the same view.
|
377
|
+
|
378
|
+
2. views
|
379
|
+
Next Volt will look for a view file that with the control name. If found, it will render the body section of that view.
|
380
|
+
|
381
|
+
3. view folder
|
382
|
+
Failing above, Volt will look for a view folder with the control name, and an index.html file within that folder. It will render the :body section of that view. If a controller exists for the view folder, it will make a new instance of that controller and render in that instance.
|
383
|
+
|
384
|
+
4. component
|
385
|
+
Next, all folders under app/ are checked. The view path looked for is {component}/index/index.html with a section of :body.
|
386
|
+
|
387
|
+
5. gems
|
388
|
+
Lastly the app folder of all gems that start with volt are checked. They are checekd for a similar path to component.
|
389
|
+
|
390
|
+
When you create a control, you can also specify multiple parts of the search path in the name. The parts should be seperated by a : Example:
|
391
|
+
|
392
|
+
```html
|
393
|
+
<:blog:comments />
|
394
|
+
```
|
395
|
+
|
396
|
+
The above would search the following:
|
397
|
+
|
398
|
+
| Component | View Folder | View File | Section |
|
399
|
+
|-------------|----------------|--------------|-----------|
|
400
|
+
| | | blog.html | :comments |
|
401
|
+
| | blog | comments.html| :body |
|
402
|
+
| blog | comments | index.html | :body |
|
403
|
+
| gems/blog | comments | index.html | :body |
|
404
|
+
|
405
|
+
|
406
|
+
# Routes
|
407
|
+
|
408
|
+
Routes in Volt are very different from traditional backend frameworks. Since data is synchronized using websockets, routes are mainly used to serialize the state of the application in a pretty way. When a page is first loaded, the url is parsed with the routes and the params model's values are set from the url. Later if the params model is updated, the url is updated based on the routes.
|
409
|
+
|
410
|
+
This means that routes in volt have to go both from url to params and params to url. It should also be noted that if a link is clicked and the controller/view to render the new url is within the current component (or an included component), the page will not be reloaded, the url will be updated with the HTML5 history API, and the params hash will reflect the new url. You can use the changes in params to render different views based on the url.
|
411
|
+
|
412
|
+
## Routes file
|
413
|
+
|
414
|
+
Routes are specified on a per-component basis in the config/routes.rb file. Routes simply map from url to params.
|
415
|
+
|
416
|
+
get "/todos", _controller: 'todos'
|
417
|
+
|
418
|
+
Routes take two arguments, a path, and a params hash. When a new url is loaded and the path is matched on a route, the params will be set to the params provided for that route.
|
419
|
+
|
420
|
+
When the params are changed, the url will be set to the path for the route that's params hash matches.
|
421
|
+
|
422
|
+
**Note: at the moment nested params do not work, but they are a planned feature**
|
423
|
+
|
424
|
+
Route path's can also contain variables similar to bindings.
|
425
|
+
|
426
|
+
get "/todos/{_index}", _controller: 'todos'
|
427
|
+
|
428
|
+
In the case above, if any url matches /todos/*, (where * is anything but a slash), it will be the active route. params._controller would be set to 'todos', and params._index would be set to the value in the path.
|
429
|
+
|
430
|
+
If params._controller is 'todos' and params._index is not nil, the route would be matched.
|
431
|
+
|
432
|
+
Routes are matched top to bottom in a routes file.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.2
|
data/lib/volt/cli.rb
CHANGED
@@ -26,14 +26,14 @@ class CLI < Thor
|
|
26
26
|
Thin::Runner.new(['start']).run!
|
27
27
|
end
|
28
28
|
|
29
|
-
desc "
|
29
|
+
desc "component GEM", "Creates a gem where you can share a component"
|
30
30
|
method_option :bin, :type => :boolean, :default => false, :aliases => '-b', :banner => "Generate a binary for your library."
|
31
31
|
method_option :test, :type => :string, :lazy_default => 'rspec', :aliases => '-t', :banner => "Generate a test directory for your library: 'rspec' is the default, but 'minitest' is also supported."
|
32
32
|
method_option :edit, :type => :string, :aliases => "-e",
|
33
33
|
:lazy_default => [ENV['BUNDLER_EDITOR'], ENV['VISUAL'], ENV['EDITOR']].find{|e| !e.nil? && !e.empty? },
|
34
34
|
:required => false, :banner => "/path/to/your/editor",
|
35
35
|
:desc => "Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)"
|
36
|
-
def
|
36
|
+
def component(name)
|
37
37
|
require 'volt/cli/new_gem'
|
38
38
|
|
39
39
|
NewGem.new(self, name, options)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: volt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Stout
|
@@ -269,7 +269,6 @@ files:
|
|
269
269
|
- app/volt/assets/js/sockjs-0.2.1.min.js
|
270
270
|
- bin/volt
|
271
271
|
- docs/GETTING_STARTED.md
|
272
|
-
- docs/GUIDE.md
|
273
272
|
- lib/volt.rb
|
274
273
|
- lib/volt/benchmark/benchmark.rb
|
275
274
|
- lib/volt/cli.rb
|
data/docs/GUIDE.md
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
# VOLT guide
|
2
|
-
|
3
|
-
This guide will take you through creating a basic web application in Volt. This tutorial assumes a basic knowledge of ruby and web development.
|
4
|
-
|
5
|
-
To get started, install volt:
|
6
|
-
|
7
|
-
gem install volt
|
8
|
-
|
9
|
-
Then create a new project:
|
10
|
-
|
11
|
-
volt new project_name
|
12
|
-
|
13
|
-
This will setup a basic project. Now lets run the server.
|
14
|
-
|
15
|
-
volt server
|
16
|
-
|
17
|
-
|
18
|
-
## Bindings
|
19
|
-
|
20
|
-
When a user interacts with a web page, typically we want to do two things:
|
21
|
-
|
22
|
-
1. Change application state
|
23
|
-
2. Update the DOM
|
24
|
-
|
25
|
-
For example when a user clicks to add a new todo item to a todo list, we might create a JavaScript object to represent the todo item, then add an item to the list's DOM. A lot of work needs to be done to make sure that the JavaScript object and the DOM always stay in sync.
|
26
|
-
|
27
|
-
Recently the idea of "reactive programming" has been used to simplify maintaining the DOM. The idea is instead of having event handlers that manage a model (or JavaScript object) and manage the DOM, we have event handlers that manage reactive data models. We describe our DOM layer in a declaritive way so that it automatically knows how to render our data models.
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
## Components
|
32
|
-
|
33
|
-
Apps are broken up into components. Each folder under app/ represents a component. You can think of components like a single page app. When a page within a component is loaded, all the controllers, models, and views within a component are loaded on the front end. The initial page load will be rendered on the backend for quick loading, then any future updates will be rendered on the front end.
|