This page is part of a series that describes building a complete todo list application with LiveComponent. Please consider reading it from the beginning.
Below is the full todo list example demonstrating all the usual CRUD operations and how to rerender from the client-side.
1 | <div class="TodoItem"> |
2 | <% if @editing %> |
3 | <%= form_with(model: @todo_item) do |f| %> |
4 | <%= f.text_field :text %> |
5 | <%= f.submit %> |
6 | <% end %> |
7 | <% else %> |
8 | <%= @todo_item.text %> |
9 | <%= button_tag( |
10 | "Edit", |
11 | data: { action: "click->todoitemcomponent#edit" } |
12 | ) %> |
13 | <%= button_to( |
14 | "Delete", |
15 | todo_list_todo_item_path( |
16 | @todo_item.todo_list_id, |
17 | @todo_item
|
18 | ),
|
19 | rerender: :parent, |
20 | method: :delete, |
21 | form: { |
22 | data: { |
23 | turbo: true, |
24 | turbo_stream: true |
25 | }
|
26 | }
|
27 | ) %> |
28 | <% end %> |
29 | </div>
|
1 | <div class="TodoItem"> |
2 | <% if @editing %> |
3 | <%= form_with(model: @todo_item) do |f| %> |
4 | <%= f.text_field :text %> |
5 | <%= f.submit %> |
6 | <% end %> |
7 | <% else %> |
8 | <%= @todo_item.text %> |
9 | <%= button_tag( |
10 | "Edit", |
11 | data: { action: "click->todoitemcomponent#edit" } |
12 | ) %> |
13 | <%= button_to( |
14 | "Delete", |
15 | todo_list_todo_item_path( |
16 | @todo_item.todo_list_id, |
17 | @todo_item
|
18 | ),
|
19 | rerender: :parent, |
20 | method: :delete, |
21 | form: { |
22 | data: { |
23 | turbo: true, |
24 | turbo_stream: true |
25 | }
|
26 | }
|
27 | ) %> |
28 | <% end %> |
29 | </div>
|
1 | class TodoItemComponent < ApplicationComponent |
2 | include LiveComponent::Base |
3 | |
4 | def initialize(todo_item:, editing: false) |
5 | @todo_item = todo_item |
6 | @editing = editing |
7 | end
|
8 | end
|
1 | class TodoItemComponent < ApplicationComponent |
2 | include LiveComponent::Base |
3 | |
4 | def initialize(todo_item:, editing: false) |
5 | @todo_item = todo_item |
6 | @editing = editing |
7 | end
|
8 | end
|
1 | import { live, LiveController } from "@camertron/live-component"; |
2 | |
3 | @live("TodoItemComponent") // this is the Ruby class name |
4 | export class TodoItemComponent extends LiveController { |
5 | edit() { |
6 | this.render((component) => { |
7 | component.props.editing = true; |
8 | });
|
9 | }
|
10 | }
|
1 | import { live, LiveController } from "@camertron/live-component"; |
2 | |
3 | @live("TodoItemComponent") // this is the Ruby class name |
4 | export class TodoItemComponent extends LiveController { |
5 | edit() { |
6 | this.render((component) => { |
7 | component.props.editing = true; |
8 | });
|
9 | }
|
10 | }
|
1 | <h1><%= @todo_list.name %></h1> |
2 | <ul>
|
3 | <% todo_items.each do |todo_item| %> |
4 | <li><%= todo_item %></li> |
5 | <% end %> |
6 | </ul>
|
7 | <%= form_with( |
8 | model: [@todo_list, @todo_list.todo_items.build], |
9 | rerender: :self
|
10 | ) do |f| %> |
11 | <%= f.text_field :text %> |
12 | <%= f.submit "Add todo item" %> |
13 | <% end %> |
1 | <h1><%= @todo_list.name %></h1> |
2 | <ul>
|
3 | <% todo_items.each do |todo_item| %> |
4 | <li><%= todo_item %></li> |
5 | <% end %> |
6 | </ul>
|
7 | <%= form_with( |
8 | model: [@todo_list, @todo_list.todo_items.build], |
9 | rerender: :self
|
10 | ) do |f| %> |
11 | <%= f.text_field :text %> |
12 | <%= f.submit "Add todo item" %> |
13 | <% end %> |
1 | class TodoListComponent < ApplicationComponent |
2 | include LiveComponent::Base |
3 | |
4 | renders_many :todo_items, TodoItemComponent |
5 | |
6 | def initialize(todo_list:) |
7 | @todo_list = todo_list |
8 | end
|
9 | end
|
1 | class TodoListComponent < ApplicationComponent |
2 | include LiveComponent::Base |
3 | |
4 | renders_many :todo_items, TodoItemComponent |
5 | |
6 | def initialize(todo_list:) |
7 | @todo_list = todo_list |
8 | end
|
9 | end
|
1 | Rails.application.routes.draw do |
2 | resources :todo_lists do |
3 | resources :todo_items |
4 | end
|
5 | end
|
1 | Rails.application.routes.draw do |
2 | resources :todo_lists do |
3 | resources :todo_items |
4 | end
|
5 | end
|
1 | # frozen_string_literal: true
|
2 | |
3 | class TodoItemsController < ApplicationController |
4 | def update |
5 | @todo_item = TodoItem.find(params[:id]) |
6 | @todo_item.update(todo_item_params) |
7 | end
|
8 | |
9 | def create |
10 | @todo_list = TodoList.find(params[:todo_list_id]) |
11 | @todo_item = @todo_list.todo_items.create(todo_item_params) |
12 | end
|
13 | |
14 | def destroy |
15 | TodoItem.delete(params[:id]) |
16 | end
|
17 | |
18 | private
|
19 | |
20 | def todo_item_params |
21 | params.require(:todo_item).permit(:text) |
22 | end
|
23 | end
|
1 | # frozen_string_literal: true
|
2 | |
3 | class TodoItemsController < ApplicationController |
4 | def update |
5 | @todo_item = TodoItem.find(params[:id]) |
6 | @todo_item.update(todo_item_params) |
7 | end
|
8 | |
9 | def create |
10 | @todo_list = TodoList.find(params[:todo_list_id]) |
11 | @todo_item = @todo_list.todo_items.create(todo_item_params) |
12 | end
|
13 | |
14 | def destroy |
15 | TodoItem.delete(params[:id]) |
16 | end
|
17 | |
18 | private
|
19 | |
20 | def todo_item_params |
21 | params.require(:todo_item).permit(:text) |
22 | end
|
23 | end
|
1 | class TodoListsController < ApplicationController |
2 | def show |
3 | @todo_list = TodoList |
4 | .includes(:todo_items) |
5 | .find(params[:id]) |
6 | end
|
7 | end
|
1 | class TodoListsController < ApplicationController |
2 | def show |
3 | @todo_list = TodoList |
4 | .includes(:todo_items) |
5 | .find(params[:id]) |
6 | end
|
7 | end
|
1 | class TodoItem < ApplicationRecord |
2 | belongs_to :todo_list |
3 | end
|
1 | class TodoItem < ApplicationRecord |
2 | belongs_to :todo_list |
3 | end
|
1 | class TodoList < ApplicationRecord |
2 | has_many :todo_items |
3 | end
|
1 | class TodoList < ApplicationRecord |
2 | has_many :todo_items |
3 | end
|
1 | <%= live.rerender(todo_list: @todo_list) do |todo_list_component| %> |
2 | <% todo_list_component.with_todo_item(todo_item: @todo_item) %> |
3 | <% end %> |
1 | <%= live.rerender(todo_list: @todo_list) do |todo_list_component| %> |
2 | <% todo_list_component.with_todo_item(todo_item: @todo_item) %> |
3 | <% end %> |
1 | <%= live.rerender do |todo_list_component| %> |
2 | <% todo_list_component.todo_items.reject! do |todo_item_component| %> |
3 | <% todo_item_component.todo_item.id == params[:id].to_i %> |
4 | <% end %> |
5 | <% end %> |
1 | <%= live.rerender do |todo_list_component| %> |
2 | <% todo_list_component.todo_items.reject! do |todo_item_component| %> |
3 | <% todo_item_component.todo_item.id == params[:id].to_i %> |
4 | <% end %> |
5 | <% end %> |
1 | <%= live.rerender(todo_item: @todo_item, editing: false) %> |
1 | <%= live.rerender(todo_item: @todo_item, editing: false) %> |
1 | <%= render(TodoListComponent.new(todo_list: @todo_list)) do |todo_list_component| %> |
2 | <% @todo_list.todo_items.each do |todo_item| %> |
3 | <% todo_list_component.with_todo_item(todo_item: todo_item) %> |
4 | <% end %> |
5 | <% end %> |
1 | <%= render(TodoListComponent.new(todo_list: @todo_list)) do |todo_list_component| %> |
2 | <% @todo_list.todo_items.each do |todo_item| %> |
3 | <% todo_list_component.with_todo_item(todo_item: todo_item) %> |
4 | <% end %> |
5 | <% end %> |