1- # TodoMVC Tutorial
1+ todo # TodoMVC Tutorial
22
33* Based on Ruby on Rails 5.2.x*
44
@@ -30,25 +30,44 @@ You will write less than 100 lines of code, and the tutorial should take about 1
3030
3131Basic knowledge of Ruby is needed, knowledge of Ruby on Rails is helpful.
3232
33-
3433### Chapter 1: Setting Things Up
3534
3635First you need to create a new project for this tutorial.
3736``` shell
38- rails new todo-demo --skip-test --template=https://rawgit.com/hyperstack-org/hyperstack/edge/install/rails-webpacker.rb
37+ rails new todo-demo --skip-test
3938```
40- This command will create a new Rails project and run the template file to set up Hyperstack within this project .
39+ This command will create a new Rails project.
4140
4241** Caution:** * you can name the app anything you want, we recommend todo-demo, but whatever you do DON'T call it todo,
4342as this name will be needed later!*
4443
45- ** Note:** * if you like you can read the contents of the template file by pasting the
46- [ url] ( https://rawgit.com/hyperstack-org/hyperstack/edge/install/rails-webpacker.rb ) (the part after ` --template= ` ) in a browser.
47- It shows how a Hyperstack Rails project differs from a plain Rails project.*
44+ Now
4845``` shell
4946cd todo-demo
5047```
51- Will change the working directory to your new todo rails project.
48+ which will change the working directory to your new todo rails project.
49+
50+ Now run
51+ ``` shell
52+ bundle add ' rails-hyperstack' --version " ~> 1.0.alpha1.0"
53+ ```
54+
55+ which will install the ` rails-hyperstack ` 'gem' into the system.
56+
57+ Once the gem is installed run
58+ ``` shell
59+ bundle exec rails hyperstack:install
60+ ```
61+
62+ to complete the hyperstack installation.
63+
64+ Finally find the ` config/initializers/hyperstack.rb ` file, and make sure that this line is ** not** commented out:
65+
66+ ``` ruby
67+ Hyperstack .import ' hyperstack/component/jquery' , client_only: true
68+ ```
69+
70+ > Ignore any comments saying that it should be commented out, this is a typo in the current installer
5271
5372#### Start the Rails app
5473
@@ -67,7 +86,7 @@ Hyperstack will need a moment to start and pre-compile with the first request.
6786#### Make a Simple Change
6887
6988Bring up your favorite editor on the ` todo-demo ` directory. You will see folders like ` app ` , ` bin ` , ` config ` and ` db ` .
70- These have all been preinitialized by Rails and the Hyperstack template you used to build the app .
89+ These have all been preinitialized by Rails and Hyperstack gems .
7190
7291Now find the ` app/hyperstack/components/app.rb ` file. It looks like this:
7392
@@ -143,7 +162,7 @@ t.boolean :completed, null: false, default: false
143162...
144163```
145164For details on 'why' see [ this blog post.] ( https://robots.thoughtbot.com/avoid-the-threestate-boolean-problem )
146- Basically this insures ` completed ` is treated as a true boolean, and will avoid having to check between ` false ` and ` null ` later on.
165+ Basically this insures ` completed ` is treated as a real boolean, and will avoid having to check between ` false ` and ` null ` later on.
147166
148167Now run:
149168``` shell
@@ -222,7 +241,7 @@ After saving you will see the following error displayed:
222241in App (created by Hyperstack::Internal::Component::TopLevelRailsComponent)
223242in Hyperstack::Internal::Component::TopLevelRailsComponent**
224243
225- because have not defined the three subcomponents. Lets define them now:
244+ because we have not defined the three subcomponents. Lets define them now:
226245
227246Add three new ruby files to the ` app/hyperstack/components ` folder:
228247
@@ -281,7 +300,7 @@ To display each Todo we will create a TodoItem component that takes a parameter:
281300class TodoItem < HyperComponent
282301 param :todo
283302 render(LI ) do
284- @Todo .title
303+ todo .title
285304 end
286305end
287306```
@@ -318,8 +337,7 @@ As you can see components can take parameters (or props in react.js terminology.
318337> * Rails uses the terminology params (short for parameters) which have a similar purpose to React props,
319338 so to make the transition more natural for Rails programmers Hyperstack uses params, rather than props.*
320339
321- Params are declared using the ` param ` macro and are accessed via Ruby * instance variables* .
322- Notice that the instance variable name is * CamelCased* so that it is easily distinguished from other instance variables.
340+ Params are declared using the ` param ` macro which creates an * accessor* method of the same name within the component.
323341
324342Our ` Index ` component * mounts* a new ` TodoItem ` with each ` Todo ` record and passes the ` Todo ` to the ` TodoItem ` component as the parameter.
325343
@@ -344,8 +362,8 @@ First add an `INPUT` html tag to your TodoItem component like this:
344362class TodoItem < HyperComponent
345363 param :todo
346364 render(LI ) do
347- INPUT (type: :checkbox , checked: @Todo .completed)
348- @Todo .title
365+ INPUT (type: :checkbox , checked: todo .completed)
366+ todo .title
349367 end
350368end
351369```
@@ -365,9 +383,9 @@ To make our checkbox input change its own state, we will add an `event handler`
365383class TodoItem < HyperComponent
366384 param :todo
367385 render(LI ) do
368- INPUT (type: :checkbox , checked: @Todo .completed)
369- .on(:change ) { @Todo .update(completed: ! @Todo .completed) }
370- @Todo .title
386+ INPUT (type: :checkbox , checked: todo .completed)
387+ .on(:change ) { todo .update(completed: ! todo .completed) }
388+ todo .title
371389 end
372390end
373391```
@@ -386,10 +404,10 @@ We will finish up by adding a *delete* link at the end of the Todo item:
386404class TodoItem < HyperComponent
387405 param :todo
388406 render(LI ) do
389- INPUT (type: :checkbox , checked: @Todo .completed)
390- .on(:change ) { @Todo .update(completed: ! @Todo .completed) }
391- SPAN { @Todo .title } # See note below...
392- A { ' -X-' }.on(:click ) { @Todo .destroy }
407+ INPUT (type: :checkbox , checked: todo .completed)
408+ .on(:change ) { todo .update(completed: ! todo .completed) }
409+ SPAN { todo .title } # See note below...
410+ A { ' -X-' }.on(:click ) { todo .destroy }
393411 end
394412end
395413```
@@ -574,27 +592,27 @@ Add a new component like this:
574592class EditItem < HyperComponent
575593 param :todo
576594 render do
577- INPUT (defaultValue: @Todo .title)
595+ INPUT (defaultValue: todo .title)
578596 .on(:enter ) do |evt |
579- @Todo .update(title: evt.target.value)
597+ todo .update(title: evt.target.value)
580598 end
581599 end
582600end
583601```
584602Before we use this component let's understand how it works.
585603+ It receives a ` todo ` param which will be edited by the user;
586604+ The ` title ` of the todo is displayed as the initial value of the input;
587- + When the user types the enter key the ` @Todo ` is updated.
605+ + When the user types the enter key the ` todo ` is updated.
588606
589607Now update the ` TodoItem ` component replacing
590608
591609``` ruby
592- SPAN { @Todo .title }
610+ SPAN { todo .title }
593611```
594612with
595613
596614``` ruby
597- EditItem (todo: @Todo )
615+ EditItem (todo: todo )
598616```
599617Try it out by changing the text of some our your Todos followed by the enter key. Then refresh the page to see that the Todos have changed.
600618
@@ -624,9 +642,9 @@ class EditItem < HyperComponent
624642 after_mount { jQ[dom_node].focus } # add
625643
626644 render do
627- INPUT (defaultValue: @Todo .title)
645+ INPUT (defaultValue: todo .title)
628646 .on(:enter ) do |evt |
629- @Todo .update(title: evt.target.value)
647+ todo .update(title: evt.target.value)
630648 saved! # add
631649 end
632650 .on(:blur ) { cancel! } # add
@@ -653,15 +671,15 @@ class TodoItem < HyperComponent
653671 param :todo
654672 render(LI ) do
655673 if @editing
656- EditItem (todo: @Todo )
674+ EditItem (todo: todo )
657675 .on(:saved , :cancel ) { mutate @editing = false }
658676 else
659- INPUT (type: :checkbox , checked: @Todo .completed)
660- .on(:change ) { @Todo .update(completed: ! @Todo .completed) }
661- LABEL { @Todo .title }
677+ INPUT (type: :checkbox , checked: todo .completed)
678+ .on(:change ) { todo .update(completed: ! todo .completed) }
679+ LABEL { todo .title }
662680 .on(:double_click ) { mutate @editing = true }
663681 A { ' -X-' }
664- .on(:click ) { @Todo .destroy }
682+ .on(:click ) { todo .destroy }
665683 end
666684 end
667685end
@@ -724,12 +742,12 @@ new Todo records, but even though they are changing React *does not* update the
724742React has a special param called ` key ` . React uses this to uniquely identify mounted components. It's used to keep track of lists of components,
725743in this case it can also be used to indicate that the component needs to be remounted when the value of ` key ` is changed.
726744
727- All objects in Hyperstack respond to the ` to_key ` method which will return a suitable unique key id, so all we have to do is pass ` @Todo ` as the key param,
728- this will insure that as ` @Todo ` changes, we will re-initialize the ` INPUT ` tag.
745+ All objects in Hyperstack respond to the ` to_key ` method which will return a suitable unique key id, so all we have to do is pass ` todo ` as the key param,
746+ this will insure that as ` todo ` changes, we will re-initialize the ` INPUT ` tag.
729747
730748``` ruby
731749...
732- INPUT (defaultValue: @Todo .title, key: @Todo ) # add the special key param
750+ INPUT (defaultValue: todo .title, key: todo ) # add the special key param
733751...
734752```
735753
@@ -809,9 +827,9 @@ class EditItem < HyperComponent
809827 other :etc # can be named anything you want
810828 after_mount { jQ[dom_node].focus }
811829 render do
812- INPUT (@Etc , defaultValue: @Todo .title, key: @Todo )
830+ INPUT (etc , defaultValue: todo .title, key: todo )
813831 .on(:enter ) do |evt |
814- @Todo .update(title: evt.target.value)
832+ todo .update(title: evt.target.value)
815833 saved!
816834 end
817835 .on(:blur ) { cancel! }
@@ -826,15 +844,15 @@ class TodoItem < HyperComponent
826844 param :todo
827845 render(LI , class : ' todo-item' ) do # add the todo-item class
828846 if @editing
829- EditItem (class : :edit, todo: @Todo ) # add the edit class
847+ EditItem (class : :edit, todo: todo ) # add the edit class
830848 .on(:saved , :cancel ) { mutate @editing = false }
831849 else
832- INPUT (type: :checkbox , class : :toggle, checked: @Todo .completed) # add the toggle class
833- .on(:change ) { @Todo .update(completed: ! @Todo .completed) }
834- LABEL { @Todo .title }
850+ INPUT (type: :checkbox , class : :toggle, checked: todo .completed) # add the toggle class
851+ .on(:change ) { todo .update(completed: ! todo .completed) }
852+ LABEL { todo .title }
835853 .on(:double_click ) { mutate @editing = true }
836854 A (class : :destroy) # add the destroy class and remove the -X- placeholder
837- .on(:click ) { @Todo .destroy }
855+ .on(:click ) { todo .destroy }
838856 end
839857 end
840858end
@@ -877,8 +895,8 @@ render(DIV, class: :footer) do
877895
878896``` ruby
879897...
880- INPUT (@Etc , placeholder: ' What is left to do today?' ,
881- defaultValue: @Todo .title, key: @Todo )
898+ INPUT (etc , placeholder: ' What is left to do today?' ,
899+ defaultValue: todo .title, key: todo )
882900.on(:enter ) do |evt |
883901...
884902```
@@ -971,15 +989,15 @@ class TodoItem < HyperComponent
971989 param :todo
972990 render(LI , class : ' todo-item' ) do
973991 if @editing
974- EditItem (class : :edit, todo: @Todo )
992+ EditItem (class : :edit, todo: todo )
975993 .on(:saved , :cancel ) { mutate @editing = false }
976994 else
977- INPUT (type: :checkbox , class : :toggle, checked: @Todo .completed)
978- .on(:change ) { @Todo .update(completed: ! @Todo .completed) }
979- LABEL { @Todo .title }
995+ INPUT (type: :checkbox , class : :toggle, checked: todo .completed)
996+ .on(:change ) { todo .update(completed: ! todo .completed) }
997+ LABEL { todo .title }
980998 .on(:double_click ) { mutate @editing = true }
981999 A (class : :destroy)
982- .on(:click ) { @Todo .destroy }
1000+ .on(:click ) { todo .destroy }
9831001 end
9841002 end
9851003end
@@ -992,10 +1010,10 @@ class EditItem < HyperComponent
9921010 other :etc
9931011 after_mount { jQ[dom_node].focus }
9941012 render do
995- INPUT (@Etc , placeholder: ' What is left to do today?' ,
996- defaultValue: @Todo .title, key: @Todo )
1013+ INPUT (etc , placeholder: ' What is left to do today?' ,
1014+ defaultValue: todo .title, key: todo )
9971015 .on(:enter ) do |evt |
998- @Todo .update(title: evt.target.value)
1016+ todo .update(title: evt.target.value)
9991017 saved!
10001018 end
10011019 .on(:blur ) { cancel! }
0 commit comments