I have a signu form, here is the code for it (if you have any improvements ideas, they are welcome !)
import {Controller} from 'stimulus';
export default class extends Controller {
static targets = [
'name', 'nameLabel', 'nameError',
'email', 'emailLabel', 'emailError',
'password', 'passwordLabel', 'passwordError',
'passwordConfirmation', 'passwordConfirmationLabel', 'passwordConfirmationError',
'form']
get validName() {
return this.nameTarget.checkValidity();
}
showNameValidation() {
if (this.validName) {
this.nameLabelTarget.classList.remove('hidden');
this.nameErrorTarget.classList.add('hidden');
} else {
this.nameLabelTarget.classList.add('hidden');
this.nameErrorTarget.classList.remove('hidden');
this.nameErrorTarget.innerHTML = 'name is required';
}
}
get validEmail() {
return this.emailTarget.checkValidity();
}
showEmailValidation() {
if (this.validEmail) {
this.emailLabelTarget.classList.remove('hidden');
this.emailErrorTarget.classList.add('hidden');
} else {
this.emailLabelTarget.classList.add('hidden');
this.emailErrorTarget.classList.remove('hidden');
this.emailErrorTarget.innerHTML = 'invalid email';
}
}
get validPassword() {
return this.passwordTarget.checkValidity();
}
showPasswordValidation() {
if (this.validPassword) {
this.passwordLabelTarget.classList.remove('hidden');
this.passwordErrorTarget.classList.add('hidden');
} else {
this.passwordLabelTarget.classList.add('hidden');
this.passwordErrorTarget.classList.remove('hidden');
this.passwordErrorTarget.innerHTML = 'Minimum password length is 6 characters';
}
}
get validPasswordConfirmation() {
return this.passwordConfirmationTarget.checkValidity() &&
this.passwordConfirmationTarget.value === this.passwordTarget.value;
}
showPasswordConfirmationValidation() {
if (this.validPasswordConfirmation) {
this.passwordConfirmationLabelTarget.classList.remove('hidden');
this.passwordConfirmationErrorTarget.classList.add('hidden');
} else {
this.passwordConfirmationLabelTarget.classList.add('hidden');
this.passwordConfirmationErrorTarget.classList.remove('hidden');
this.passwordConfirmationErrorTarget.innerHTML = 'Does not match password';
}
}
get valid() {
return this.validName &&
this.validEmail &&
this.validPassword &&
this.validPasswordConfirmation;
}
showValidations() {
this.showNameValidation();
this.showEmailValidation();
this.showPasswordValidation();
this.showPasswordConfirmationValidation();
}
submit(event) {
event.preventDefault();
this.emailTarget.value = this.emailTarget.value.trim().toLowerCase();
this.showValidations();
if (this.valid) this.formTarget.submit();
}
}
<%=
form_for @changeset,
registration_path(@conn, :create),
[
{:as, :registration},
{:class, "form-validate login-form"},
{:"data-controller", "signup-form"},
{:"data-target", "signup-form.form"}
],
fn f -> %>
<div class="panel panel-body border-white no-panel-shadow">
<div class="content-divider text-muted form-group"><span>Sign up</span></div>
<div class="form-group has-feedback has-feedback-right">
<label data-target="signup-form.nameLabel">
Name: <span class="text-danger">*</span>
</label>
<label
class="text-danger-700 pull-right"
data-target="signup-form.nameError"
>
<%= error_tag f, :name %>
</label>
<%=
text_input f,
:name,
[
{:class, "form-control"},
{:"data-target", "signup-form.name"},
{:required, true},
{:autofocus, true},
{:"data-action", "input->signup-form#showNameValidation"}
]
%>
<div class="form-control-feedback" style="display: none;">
<i class="icon-cross2 text-danger-700"></i>
</div>
</div>
<div class="form-group has-feedback has-feedback-right">
<label data-target="signup-form.emailLabel">
Email: <span class="text-danger">*</span>
</label>
<label
class="text-danger-700 pull-right"
data-target="signup-form.emailError"
>
<%= error_tag f, :email %>
</label>
<%=
email_input f,
:email,
[
{:class, "form-control"},
{:"data-target", "signup-form.email"},
{:required, true},
{:"required pattern", ~S'^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+$' },
{:"data-action", "input->signup-form#showEmailValidation"}
]
%>
</div>
<div class="form-group has-feedback has-feedback-right">
<label data-target="signup-form.passwordLabel">
Password: <span class="text-danger">*</span>
</label>
<label
class="text-danger-700 pull-right"
data-target="signup-form.passwordError"
>
<%= error_tag f, :password %>
</label>
<%=
password_input f,
:password,
[
{:class, "form-control"},
{:"data-target", "signup-form.password"},
{:required, true},
{:minlength, "6"},
{:"data-action", "input->signup-form#showPasswordValidation"}
]
%>
</div>
<div class="form-group has-feedback has-feedback-right">
<label data-target="signup-form.passwordConfirmationLabel">
Confirm password: <span class="text-danger">*</span>
</label>
<label
class="text-danger-700 pull-right"
data-target="signup-form.passwordConfirmationError"
>
<%= error_tag f, :password_confirmation %>
</label>
<%=
password_input f,
:password_confirmation,
[
{:class, "form-control"},
{:"data-target", "signup-form.passwordConfirmation"},
{:required, true},
{:"data-action", "input->signup-form#showPasswordConfirmationValidation"}
]
%>
</div>
<div class="form-group login-options">
<div class="row">
<div class="col-sm-6">
<label class="checkbox-inline">
<input type="checkbox" id="remember" class="styled" name="remember" checked="checked">
Remember
</label>
</div>
<div class="col-sm-6 text-right">
<a href="/passwords/new">Forgot password?</a>
</div>
</div>
</div>
<div class="form-group">
<%=
submit dgettext("coherence", "Sign up"),
[
{:class, "btn btn-primary btn-block"},
{:"data-action", "click->signup-form#submit"}
]
%>
</div>
<div class="content-divider text-muted form-group"><span>Already signed up?</span></div>
<a href="/sessions/new" class="btn btn-default btn-block content-group">Login</a>
<span class="help-block text-center no-margin">By continuing, you're confirming that you've read our <a href="#">Terms & Conditions</a> and <a href="#">Cookie Policy</a></span>
</div>
<% end %>
The html part is in a templating language, so you’ll have to convert that to html, but it’s pretty straightforward. Let me know if anything doesn’t make sense