1
-
1
+ fires
2
2
# TodoMVC Tutorial (Rails 5.2.x)
3
3
4
4
### Prerequisites
@@ -437,13 +437,11 @@ Lets change `App` to look like this:
437
437
# app/hyperstack/components/app.rb
438
438
class App < HyperComponent
439
439
include Hyperstack ::Router
440
- render do
441
- SECTION do
442
- Header ()
443
- Route (' /' , exact: true ) { Redirect (' /all' ) }
444
- Route (' /:scope' , mounts: Index )
445
- Footer ()
446
- end
440
+ render(SECTION ) do
441
+ Header ()
442
+ Route (' /' , exact: true ) { Redirect (' /all' ) }
443
+ Route (' /:scope' , mounts: Index )
444
+ Footer ()
447
445
end
448
446
end
449
447
```
@@ -609,16 +607,17 @@ To summarize:
609
607
+ User saves the Todo being edited: editing changes to ` false ` .
610
608
+ User changes focus away (` blur ` ) from the Todo being edited: editing changes to ` false ` .
611
609
612
- In order to accomplish this our ` EditItem ` component is going to communicate to its parent via two application defined events - ` saved ` and ` cancel ` .
610
+ In order to accomplish this our ` EditItem ` component is going to communicate to its parent via two application defined events - ` saved ` and ` cancel ` .
611
+
613
612
Add the following 5 lines to the ` EditItem ` component like this:
614
613
615
614
``` ruby
616
615
# app/hyperstack/components/edit_item.rb
617
616
class EditItem < HyperComponent
618
617
param :todo
619
- triggers :saved # add
620
- triggers :cancel # add
621
- after_mount { DOM [dom_node].focus } # add
618
+ fires :saved # add
619
+ fires :cancel # add
620
+ after_mount { jQ [dom_node].focus } # add
622
621
623
622
render do
624
623
INPUT (defaultValue: @Todo .title)
@@ -630,17 +629,17 @@ class EditItem < HyperComponent
630
629
end
631
630
end
632
631
```
633
- The first two new lines add our custom events.
632
+ The first two new lines add our custom events which will be * fired * by the component .
634
633
635
634
The next new line uses one of several * Lifecycle Callbacks* . In this case we need to move the focus to the ` EditItem ` component after it is mounted.
636
- The ` DOM ` class is Hyperstack's jQuery wrapper, and ` dom_node `
635
+ The ` jQ ` method is Hyperstack's jQuery wrapper, and ` dom_node `
637
636
is the method that returns the actual dom node where this * instance* of the component is mounted.
638
637
This is the ` INPUT ` html element as defined in the render method.
639
638
640
- The ` saved! ` line will trigger the saved event in the parent component.
641
- Notice that the method to trigger a custom event is the name of the event followed by a bang (!).
639
+ The ` saved! ` line will fire the saved event in the parent component.
640
+ Notice that the method to fire a custom event is the name of the event followed by a bang (!).
642
641
643
- Finally we add the ` blur ` event handler and trigger our ` cancel ` event.
642
+ Finally we add the ` blur ` event handler and fire our ` cancel ` event.
644
643
645
644
Now we can update our ` TodoItem ` component to react to three events: ` double_click ` , ` saved ` and ` cancel ` .
646
645
@@ -663,7 +662,7 @@ class TodoItem < HyperComponent
663
662
end
664
663
end
665
664
```
666
- All states in Hyperstack are simply Ruby instance variables (ivars, variables with a leading @). Here we use the ` @editing ` ivar.
665
+ All states in Hyperstack are simply Ruby instance variables (ivars for short which are variables with a leading @). Here we use the ` @editing ` ivar.
667
666
668
667
We have already used a lot of states that are built into the HyperModel and HyperRouter.
669
668
The states of these components are built out collections of instance variables like ` @editing ` .
@@ -748,17 +747,15 @@ Let's start with the `App` component. With styling it will look like this:
748
747
# app/hyperstack/components/app.rb
749
748
class App < HyperComponent
750
749
include Hyperstack ::Router
751
- render do
752
- SECTION (class : ' todo-app' ) do # add class todo-app
753
- Header ()
754
- Route (' /' , exact: true ) { Redirect (' /all' ) }
755
- Route (' /:scope' , mounts: Index )
756
- Footer ()
757
- end
750
+ render(SECTION , class : ' todo-app' ) do # add class todo-app
751
+ Header ()
752
+ Route (' /' , exact: true ) { Redirect (' /all' ) }
753
+ Route (' /:scope' , mounts: Index )
754
+ Footer ()
758
755
end
759
756
end
760
757
```
761
- The ` Footer ` components needs have a ` UL ` added to hold the links nicely,
758
+ The ` Footer ` component needs to have a ` UL ` added to hold the links nicely,
762
759
and we can also use the ` NavLinks ` ` active_class ` param to highlight the link that is currently active:
763
760
764
761
``` ruby
@@ -772,7 +769,7 @@ class Footer < HyperComponent
772
769
LI { NavLink (" /#{ path } " , active_class: :selected ) { path.camelize } }
773
770
end
774
771
render(DIV , class : :footer) do # add class footer
775
- UL (class : :filters) do # wrap links in a UL element with class filers
772
+ UL (class : :filters) do # wrap links in a UL element with class filters
776
773
link_item(:all )
777
774
link_item(:active )
778
775
link_item(:completed )
@@ -796,17 +793,17 @@ class Index < HyperComponent
796
793
end
797
794
```
798
795
For the EditItem component we want the parent to pass any html parameters such as ` class ` along to the INPUT tag.
799
- We do this by adding the special ` others ` param that will collect any extra params, we then pass it along in to the INPUT tag.
796
+ We do this by adding the special ` other ` param that will collect any extra params, we then pass it along in to the INPUT tag.
800
797
Hyperstack will take care of merging all the params together sensibly.
801
798
802
799
``` ruby
803
800
# app/hyperstack/components/edit_item.rb
804
801
class EditItem < HyperComponent
805
802
param :todo
806
- triggers :saved
807
- triggers :cancel
808
- others :etc # can be named anything you want
809
- after_mount { DOM [dom_node].focus }
803
+ fires :saved
804
+ fires :cancel
805
+ other :etc # can be named anything you want
806
+ after_mount { jQ [dom_node].focus }
810
807
render do
811
808
INPUT (@Etc , defaultValue: @Todo .title, key: @Todo )
812
809
.on(:enter ) do |evt |
@@ -864,12 +861,14 @@ This is just a span that we add before the link tags list in the `Footer` compon
864
861
...
865
862
render(DIV , class : :footer) do
866
863
SPAN (class : ' todo-count' ) do
867
- " #{ Todo .active.count} item#{ ' s' if Todo .active.count != 1 } left"
864
+ # pluralize returns the second param (item) properly
865
+ # pluralized depending on the first param's value.
866
+ " #{ pluralize(Todo .active.count, ' item' ) } left"
868
867
end
869
868
UL (class : :filters) do
870
869
...
871
870
```
872
- + ** Add 'placeholder' Text To Edit Item** \
871
+ + ** Add 'placeholder' Text To Edit Item**
873
872
` EditItem ` should display a meaningful placeholder hint if the title is blank:
874
873
875
874
``` ruby
@@ -879,7 +878,7 @@ INPUT(@Etc, placeholder: 'What is left to do today?',
879
878
.on(:enter ) do |evt |
880
879
...
881
880
```
882
- + ** Don't Show the Footer If There are No Todos** \
881
+ + ** Don't Show the Footer If There are No Todos**
883
882
In the ` App ` component add a * guard* so that we won't show the Footer if there are no Todos:
884
883
885
884
``` ruby
@@ -899,7 +898,7 @@ You have built a small but feature rich full stack Todo application in less than
899
898
``` text
900
899
SLOC
901
900
--------------
902
- App: 11
901
+ App: 9
903
902
Header: 8
904
903
Index: 10
905
904
TodoItem: 16
@@ -908,7 +907,7 @@ Footer: 16
908
907
Todo Model: 4
909
908
Rails Route: 4
910
909
--------------
911
- Total: 85
910
+ Total: 83
912
911
```
913
912
914
913
The complete application is shown here:
@@ -917,13 +916,11 @@ The complete application is shown here:
917
916
# app/hyperstack/components/app.rb
918
917
class App < HyperComponent
919
918
include Hyperstack ::Router
920
- render do
921
- SECTION (class : ' todo-app' ) do
922
- Header ()
923
- Route (' /' , exact: true ) { Redirect (' /all' ) }
924
- Route (' /:scope' , mounts: Index )
925
- Footer () unless Todo .count.zero?
926
- end
919
+ render(SECTION , class : ' todo-app' ) do
920
+ Header ()
921
+ Route (' /' , exact: true ) { Redirect (' /all' ) }
922
+ Route (' /:scope' , mounts: Index )
923
+ Footer () unless Todo .count.zero?
927
924
end
928
925
end
929
926
@@ -956,9 +953,7 @@ class Footer < HyperComponent
956
953
LI { NavLink (" /#{ path } " , active_class: :selected ) { path.camelize } }
957
954
end
958
955
render(DIV , class : :footer) do
959
- SPAN (class : ' todo-count' ) do
960
- " #{ Todo .active.count} item#{ ' s' if Todo .active.count != 1 } left"
961
- end
956
+ SPAN (class : ' todo-count' ) { " #{ pluralize(Todo .active.count, ' item' ) } left" }
962
957
UL (class : :filters) do
963
958
link_item(:all )
964
959
link_item(:active )
@@ -987,11 +982,11 @@ end
987
982
988
983
# app/hyperstack/components/edit_item.rb
989
984
class EditItem < HyperComponent
990
- param :todo
991
- triggers :save
992
- triggers :cancel
993
- others :etc
994
- after_mount { DOM [dom_node].focus }
985
+ param :todo
986
+ fires :save
987
+ fires :cancel
988
+ other :etc
989
+ after_mount { jQ [dom_node].focus }
995
990
render do
996
991
INPUT (@Etc , placeholder: ' What is left to do today?' ,
997
992
defaultValue: @Todo .title, key: @Todo )
0 commit comments