DEV Community

Shivashankar
Shivashankar

Posted on

Prompting user confirmation in stimulus-reflex

Introduction

StimulusReflex along with cable_ready is a wonderful option for creating reactive application.

One issue I face is how to prompt a user before deleting a record. This post is about how to deal this one.

Alt Text


Assume we have tasks list as follows and we need to prompt the user to confirm when he/she tries to remove a record.

Title Status Remove
Fix homepage css issue Mark as resolved Remove
Add new banner Mark as resolved Remove
Iphone support Resolved Remove

Step: 1: create scaffold and migrate

$ rails g scaffold tasks title status $ rake db:migrate 

Step: 2 add stimulus_reflex and cable ready gems in Gemfile

gem 'cable_ready' gem "stimulus_reflex", "~> 3.2" 
 $ bundle install 

Step: 3 update app/channels/application_cable/connection.rb

module ApplicationCable class Connection < ActionCable::Connection::Base identified_by :current_user def connect self.current_user = find_verified_user end private def find_verified_user if verified_user = User.find_by(id: cookies.encrypted[:user_id]) verified_user else reject_unauthorized_connection end end end end 

Step: 4 create tasks channel

$ rails g channel Tasks 

Step: 5 update app/channels/tasks_channel.rb

class TasksChannel < ApplicationCable::Channel def subscribed stream_from "tasks" end end 

Step: 6 update app/javascript/channels/tasks_channel.js

import cableReady from 'cable_ready' import consumer from "./consumer" consumer.subscriptions.create("TasksChannel", { received(data) { if (data.cableReady) cableReady.perform(data.operations) } }); 

Step: 7 generate tasks reflex

rails g stimulus_reflex Tasks 

Step: 8 Update app/reflexes/tasks_reflex.rb

class TasksReflex < ApplicationReflex include CableReady::Broadcaster def update id = element.dataset[:id] task = Task.find(id) task.update(status: "resolved") cable_ready["tasks"].text_content( selector: "status-col-#{id}", text: 'Resolved' ) cable_ready.broadcast end def remove(id) task = Task.find(id) task.destroy # in views we have set id for each row # cable_ready["tasks"]- here `tasks` denote channel name cable_ready["tasks"].remove( selector: "row-#{id}" ) cable_ready.broadcast end end 

Step: 9 Update app/javascript/controllers/tasks_controller.js

import ApplicationController from './application_controller' export default class extends ApplicationController { remove(event) { event.preventDefault(); // This is where we are prompting the user for confirmation const ok = confirm("Are you sure to mark the task as 'resolved'?") if(!ok){ return false; }else{ const el = event.currentTarget const id = el.getAttribute("data-id"); this.stimulate("TasksReflex#delete", id) } } } 

Step: 9 Update app/controllers/tasks_controller.rb

 class TasksController < ApplicationController include CableReady::Broadcaster end 

app/views/users/index.html.erb

<table> <thead> <tr> <th>Title</th> <th>Status</th> <th>Remove</th> </tr> </thead> <tbody> <% @tasks.each do |task| %> <!-- unique row id --> <tr id="row-<%= task.id %>"> <td><%= task.title %></td> <td id="status-col-<%= task.id %>"> <!-- directly call StimulusReflex --> <%= link_to 'Mark as resolved', '#', data:{reflex: 'click->TasksReflex#update', id: task.id} %> </td> <td data-controller="tasks"> <!-- Call controller instead of Reflex to show confirmation --> <%= link_to 'Remove', '#', data:{action: "click->tasks#remove", id: task.id} %> </td> </tr> <% end %> </tbody> </table> 

Note: We need to use controller i.e data-action instead of data-reflex in links to show confirmation.

Top comments (1)

Collapse
 
techpeace profile image
Matt Buck

Thanks for the post! I arrived at a slightly different solution.