Pass -express-flash-messages- in an EJS file - express

I've a user controller which has a basic authentication logic. I'm using an ejs view engine . I'm finding trouble accessing these flash messages in my view, i.e. .ejs file. What should be the right approach. I dug through some information and found out that we can pass parameters during a res.redirect. However, I don't want to do that, since it will appear in the URL. Is there a solution to this, something like what pug engine has.
if (!user || !user.authenticate(req.body.password)) {
req.flash('error', 'Invalid email or password!')
res.redirect('/login')
return
}

You could pass your flash messages to your views using res.locals object:
app.get('/login', function(req, res) {
res.render('login', { errorMessage: req.flash('error')[0] });
});
Then in your view:
<% if (errorMessage) { %>
<div class="error">
<p><%= errorMessage %></p> <!-- Invalid email or password! -->
</div>
<% } %>

Related

How can I submit a form on input change with Turbo Streams?

I have a form I want to submit automatically whenever any input field is changed. I am using Turbo Streams, and if I use onchange: "this.form.submit()" it isn't captured by Turbo Streams and Rails uses a standard HTML response. It works fine when clicking the submit button. How can I work around this?
There is a discussion on the hotwire forum, where Mark Godwin figured out why form.submit() isn't working with turbo:
Turbo intercepts form submission events, but weirdly, the JS formElement.submit() method does not trigger the submit event.
And Jacob Daddario figures out that you can use form.requestSubmit() instead:
It turns out that the turbo-stream mechanism listens for form submission events, and for some reason the submit() function does not emit a form submission event. That means that it’ll bring back a normal HTML response. That said, it looks like there’s another method, requestSubmit() which does issue a submit event.
So you can change your code slightly, and use requestSubmit() if a browser supports it, and use submit() if not:
onchange: "this.form.requestSubmit ? this.form.requestSubmit() : this.form.submit()"
Update:
As BenKoshy pointed out, in Turbo 7.1.0, a polyfill was added so you can use form.requestSubmit() without checking for browser support, so you can add this to your input field:
onchange: "this.form.requestSubmit()"
I need to implement this for an app with lots of forms. I wound up using Stimulus. Below is the whole controller:
import { Controller } from "stimulus"
const _ = require("lodash")
export default class extends Controller {
connect() {
let that = this;
that.element.addEventListener('change', _.debounce(that.handleChange, 500))
}
handleChange(event) {
event.preventDefault()
// event.target.name // => "user[answer]"
// event.target.value // => <user input string>
event.target.form.requestSubmit()
}
}
and here it's used in a form with a single text input. NOTE the controller is attached to the form, not to the inputs.
<%= turbo_frame_tag dom_id(form_model) do %>
<%= form_with model: form_model,
format: :turbo_stream,
html: { data: { controller: "buttonless-form" } } do |f| %>
<%= f.hidden_field :question_id, value: question.id %>
<%= f.text_field :answer_value, class: "input shadow wide", placeholder: "Enter your answer here" %>
<% end %>
<div id=<%= "question_#{question.id}_output" %>>
<p> <!-- feedback to the user shows up here via Turbo -->
</div>
<% end %> <!-- end turbo frame -->

Re-using a stimulus action elsewhere on the page?

I am wiring up a slack clone (html/css) and have it so that the reference drawer opens/closes when I click on the x. I am wanting to also open/close it from the navigation area and thought I could just take the same link_to and call it from a different part of the page.
But when I do that, if I'm calling it from within a different target, I get an error
Error invoking action "click->navigation#toggle_reference_drawer"
Error: Missing target element "navigation.referenceDrawer"
How can I use code inside a data-target to trigger a different data-target?
i.e. what I'm trying to get working is
--navigation partial (link_to doesn't work) --
<div data-navigation-target="storyNavLinks">
<div class ="story">
<%= link_to "[x]", "#", data: { action: "click->navigation#hide_reference_drawer" } %>
</div>
</div>
-- application partial (link_to works) --
<div data-navigation-target="referenceDrawer">
<div class='reference box'>
<%= link_to "[x]", "#", data: { action: "click->navigation#hide_reference_drawer" } %>
</div>
</div>
Not sure where I'm going wrong.. I figured as long as the target being referenced is unique and on the page it shouldn't matter where it's being called from?
You have to make sure your data-controller attribute is on an element that wraps both targets. If that is not possible you can always include the controller twice but the targets will only be scoped to each instance so you will need to add them twice as well.

Why is the Post route not accepting the variable value(using express)?

This is my app.js file here I'm creating two simple Get and Post request
var express = require("express");
var bodyParser = require("body-parser");
var app = express();
var todos = ["Water Plants", "Feed Zorro", "Buy Groceries", "Read Books"];
app.use(bodyParser.urlencoded({extended : true}));
app.use(express.static("public"));
app.set("view engine", "ejs");
app.get("/:name/todo", function(req, res){
var name = req.params.name;
res.render("home", {name : name, todos : todos});
});
app.post("/:name/todo", function(req, res){
var name = req.params.name;
var newTodo = req.body.newTodo;
todos.push(newTodo);
res.redirect("/:name/todo");
});
app.listen(3000);
This is my home.ejs file
<% include partials/header %>
<h1>Welcome <%= name %></h1>
<% for(var i = 0; i < todos.length; i++){ %>
<li><%= todos[i] %></li>
<% } %>
<form action="/:name/todo" method="POST">
<input type="text" name="newTodo" placeholder="Add Todo..."><br>
<button>Add Todo</button>
</form>
<% include partials/footer %>
Whenever I go to localhost:3000/Jazz/todo the html header shows "Welcome Jazz" but when I try to make a post request by adding an item to the list, the header then turns to "Welcome :name" but it should be the same "Welcome Jazz". What is causing this abnormal error and what is the solution?
Packages I am using are express, ejs, body-parser.
Please make correction in route. You need to present compiled name there
<form action="/<%= name %>/todo" method="POST">
And submit request via ajax. As page refresh after post request, it does not get data back to display. Therefore you are getting an error

Jade equivalent of <%= %>

I'm trying to implement toastr notifications on my express application using express-toastr (https://github.com/kamaln7/express-toastr). The documentation says that after including the following in the controller:
if (err)
{
req.toastr.error('Invalid credentials.');
} else {
req.toastr.success('Successfully logged in.', "You're in!");
}
we have to include the libraries in the on the views. That is okay. But we also have to include something like this :
<%= req.toastr.render() %>
What is the equivalent of this on jade?
Thanks
Use:
div #{req.toastr.render()}
related post: https://www.filosophy.org/post/34/using_javascript_functions_within_the_jade_templating_language/

How to render js rails 3

I have a vote model with "like", "dislike" actions. I have a route for each of these actions. When I call the actions, I'm returning a json response. My problem is that first, I need to figure out how to send the query to my like/dislike actions. I need to access ruby/rails variables from my javascript (I'm sending an ajax request using jquery's $.getJSON), so that for example I can create the request for the correct item. Help much appreciated.
A popular technique is to attach data to the dom. For example (pseudocode follows):
<% items.each do |item| %>
<div class="like_button" data-item-id="<%= item.id %>">Like</div>
<% end %>
and in the JavaScript:
$(".like_button").on("click", function() {
var item_id = $(this).data('item-id'); // from the dom
// construct Ajax request for item_id
});