meteor rerender login form after log in - javascript

I have a Meteor and login form like this:
<template name="index">
<h3>Index Page</h3>
{{#if currentUser}}
You are logged in!<br>
Dashboard
{{else}}
{{> loginForm}}
{{/if}}
</template>
<template name="loginForm">
<div class="container">
<div class="row col-md-offset-2 col-sm-offset-2">
<div class="container col-md-2 col-sm-2">
<h4>Login</h4>
</div>
<div class="container col-md-4 sol-sm-4">
<h4><small>or register</small></h4>
</div>
</div>
<!--div class="row"-->
<form class="form-horizontal" id="formLogin">
<div class="form-group">
<div class="col-md-2 col-sm-2">
<label for="inputEmail" class="control-label pull-right">Email</label>
</div>
<div class="col-md-4 col-sm-4">
<input type="email" class="form-control" id="inputEmail" placeholder="Email">
</div>
</div>
<div class="form-group">
<div class="col-md-2 col-sm-2">
<label for="inputPassword" class="control-label pull-right">Password</label>
</div>
<div class="col-md-4 col-sm-4">
<input type="password" class="form-control" id="inputPassword" placeholder="Password">
</div>
</div>
<!--<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
<label>
<input type="checkbox"> Remember me
</label>
</div>
</div>
</div>-->
<div class="form-group">
<div class="col-md-offset-2 col-sm-offset-2 col-md-10 col-sm-6">
<input type="submit" class="btn btn-default" value="Sign in">
</div>
</div>
</form>
<!--/div-->
</div>
<!-- END loginForm END -->
</template>
Here the JavaScript code for template:
Template.loginForm.events({
"submit #formLogin": function(e, t) {
e.preventDefault();
//console.log("Form login submitted");
var loginForm = $(e.currentTarget),
email = loginForm.find("#inputEmail").val(),
password = loginForm.find("#inputPassword").val();
//console.log("Email:" + email + "\n" + "Password:" + password);
//++++++ Validation
var trimInput = function(val) {
return val.replace(/^\s*|\s*$/g, "");
};
isEmailValid = trimInput(email).length > 5 ? true : false
//console.log(isEmailValid);
isPasswordValid = password.length > 0 ? true : false
//console.log(isPasswordValid);
//------
if (isEmailValid && isPasswordValid) {
Meteor.loginWithPassword(email, password, function(err) {
if (err) {
if (err.message === "User not found [403]") {
console.log("User does not exist.");
} else if (err.message === "Incorrect password [403]") {
console.log("Incorrect password");
} else if (err.message === "Match failed [400]") {
console.log("Match failed");
} else {
console.log(err.message)
}
} else {
return true;
}
});
} else {
console.log("Incorrect data");
};
}
});
After success login user shouldn't see the form. But if I refresh the page login form appear for 1-1,5 seconds and dissapear. How avoid this?

I had the same issue and this is how I solved it.
put:
if (Meteor.userId()) Router.go("main");
return false;
after your Meteor.loginWithPassword call
ie, for iron router and "main" as the template to render after login

When you do a page refresh the server will log in again as you are creating a new session in effect, it will automatically pick up the fact that you were previously logged in and log you in using those details. However for that period it will not have a userId and currentUser is null. It will however have a loggingIn state of true Meteor.loggingIn() which you are not checking for. To avoid confusion, check for the loggingin state and then show a loading screen or spinner to indicate something is happening.
You can create a global loggingIn handlebars helper:
if (Handlebars) {
Handlebars.registerHelper('loggingIn', function () {
return Meteor.loggingIn();
});
}
and then use that to display a loading/spinner template whilst the server is processing the login request after your page refresh:
{{#if currentUser}}
You are logged in!<br>
Dashboard
{{else}}
{{#if loggingIn}}
{{> loading}}
{{else}}
{{> loginForm}}
{{/if}}
{{/if}}
Which should solve the problem of the app presenting the login screen to the user on first page call/refresh and causing confusion, it will also let them know it is doing something whilst it is working away in the background to log them in.
If you still see the login form it should be really really minimal and flash up very quickly before reverting to either login or loading template.

Related

Route broken when sending sign-in form for the second time

I'm trying to create a sign-in form with an MVC structure in express. The workflow is the following:
The user fills the form, when he/she submits it the app makes a request to
'sign-in/submit' to get the data sanitized/validated, if there's no errors, the user is inserted in the DB, otherwise, the form is shown again with the errors.
This is the form:
<form action="sign-in/submit" method="post" class="needs-validation" novalidate>
<div class="container d-flex justify-content-center mb-5">
<div class="col-12 col-xl-6 sign-in-content mt-5">
<div>
<div class="mb-3">
<label for="exampleInputEmail1" class="form-label">Email</label>
<input type="text" class="form-control" id="regEmail" name="regEmail" value="{{{email}}}"
required>
<div class="invalid-feedback">Email is required</div>
{{#each emailErrors}}
<p class="errorMessage">{{this}}</p>
{{/each}}
</div>
<div class="mb-3">
<label for="exampleInputEmail1" class="form-label">Password</label>
<input type="password" class="form-control" id="regPassword" name="regPassword"
value="{{{password}}}" required>
<div class="invalid-feedback">Password is required</div>
{{#each passwordErrors}}
<p class="errorMessage">{{this}}</p>
{{/each}}
</div>
<div class="mb-5">
<label for="exampleInputEmail1" class="form-label">Repeat password</label>
<input type="password" class="form-control" id="regRepeatPassword" name="regRepeatPassword"
value="{{{repeatPassword}}}" required>
<div class="invalid-feedback">Repeat password</div>
{{#each repeatPasswordErrors}}
<p class="errorMessage">{{this}}</p>
{{/each}}
</div>
</div>
</div>
</div>
</form>
The problem is that after showing the errors and resending the form with the right data one more time, I get this error:
Cannot POST /sign-in/sign-in/submit
I think it's due to the fact that when it renders the form for the second time the route is already /sign-in/submit so it stacks the new one on top of that one.
Here's the controller:
const registerUser = (req, res) => {
const errors = validationResult(req);
let formData = req.body;
let registerFeedback = {
//properties
};
if (!errors.isEmpty() || registerFeedback.repeatPasswordErrors.length != 0) {
errors.errors.forEach(err => {
//Error handling
});
//Render the form one more time with the errors
res.render('sign-in', registerFeedback);
} else {
//Insert the user in the database
}
}
Here's the routing for /sign-in/*:
const express = require('express');
const { signInRenderer, registerUser, signInValidator } = require('../controllers/signInController');
const router = express.Router();
router.get('/', signInRenderer);
router.post('/submit', signInValidator, registerUser);
module.exports = router;
I'm using express-validator but that part works fine.
Thank you in advance.

AngularJS 1.6.8: Form data not submitting and so hence unable to save it to localStorage

I have a contact form. On submission, it displays a success message and it should store that data to $localStorage.
But, Form data not is not submitting as I do not see submitted form data in response under network in dev tools and hence I am unable to save it to $localStorage.
below is the code for respective files.
link to plunker
contact.html
<div ngController="contactController as vm">
<div class="heading text-center">
<h1>Contact Us</h1>
</div>
<div>
<form class="needs-validation" id="contactForm" novalidate method="post" name="vm.contactForm" ng-submit="saveform()">
<div class="form-group row">
<label for="validationTooltip01" class="col-sm-2 col-form-label">Name</label>
<div class="input-group">
<input type="text" class="form-control" id="validationTooltipName" placeholder="Name" ng-model="vm.name" required>
<div class="invalid-tooltip">
Please enter your full name.
</div>
</div>
</div>
<div class="form-group row">
<label for="validationTooltipEmail" class="col-sm-2 col-form-label">Email</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text" id="validationTooltipUsernamePrepend">#</span>
</div>
<input type="email" class="form-control" id="validationTooltipEmail" placeholder="Email"
aria-describedby="validationTooltipUsernamePrepend" ng-model="vm.email" required>
<div class="invalid-tooltip">
Please choose a valid email.
</div>
</div>
</div>
<div class="form-group row">
<label for="validationTooltip03" class="col-sm-2 col-form-label">Query</label>
<div class="input-group">
<input type="text" class="form-control" id="validationTooltipQuery" ng-model="vm.query" placeholder="Query" required>
<div class="invalid-tooltip">
Please write your Query.
</div>
</div>
</div>
<div class="btn-group offset-md-5">
<button class="btn btn-primary" type="submit">Submit</button>
<button class="btn btn-default" type="button" id="homebtn" ng-click="navigate ('home')">Home</button>
</div>
</form>
<span data-ng-bind="Message" ng-hide="hideMessage" class="sucessMsg"></span>
</div>
</div
contact.component.js
angular.module('myApp')
.component('contactComponent', {
restrict: 'E',
$scope:{},
templateUrl:'contact/contact.html',
controller: contactController,
controllerAs: 'vm',
factory:'userService',
$rootscope:{}
});
function contactController($scope, $state,userService) {
var vm = this;
vm.saveform = function(){
var name= vm.name;
var email= vm.email;
var query= vm.query;
console.log(name);
console.log(email);
console.log(query);
$scope.hideMessage = false;
$scope.Message = "Your query has been successfully submitted.";
$scope.user = userService;
};
$scope.navigate = function(home){
$state.go(home)
};
};
//localStorage code
function userService(saveform) {
var service = {
model: {
name: '',
email: '',
query:''
},
SaveState: function () {
sessionStorage.userService = angular.toJson(service.model);
},
RestoreState: function () {
service.model = angular.fromJson(sessionStorage.userService);
}
}
$rootScope.$on("savestate", service.SaveState);
$rootScope.$on("restorestate", service.RestoreState);
return service;
$rootScope.$on("$routeChangeStart", function (event, next, current) {
if (sessionStorage.restorestate == "true") {
$rootScope.$broadcast('restorestate'); //let everything know we need to restore state
sessionStorage.restorestate = false;
}
});
//let everthing know that we need to save state now.
window.onbeforeunload = function (event) {
$rootScope.$broadcast('savestate');
};
};
There are no errors in console.

Showing alert after reloading page

I'm beginner just learn how to code, I try to make some notification after submitting form then reload page, will show alert-success bootstrap, this is the code
// Bootstrap alert
bootstrap_alert = function() {}
bootstrap_alert.warning = function(message){
$('#alert_placeholder').html('<div class="alert alert-success alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button><span>'+message+'</span></div>').show(500).delay(3000).hide(500);
}
(function checkIfMsgSent() {
if (typeof localStorage !== 'undefined') {
var isMsgSent = JSON.parse(localStorage.getItem("messageSent")); // JSON.parse because we want a boolean
if (isMsgSent) {
alert('Message has been sent.');
// bootstrap_alert.warning('Message has been sent.');
}
localStorage.removeItem('messageSent');
} else {
// localStorage not defined
alert('Your browser in incompatible for some features in this website');
}
});
$('#sentcontact').on('click', function(){
if (typeof localStorage !== 'undefined') {
localStorage.setItem('messageSent', 'true');
} else {
// localStorage not defined
alert('Your browser in incompatible for some features in this website');
}
window.location.reload();
});
Update Javascript Use by Solution 2
<div class="container">
<div id="alert_placeholder"></div>
</div>
<section class="contact_us">
<div class="container">
<form action="vanilla-form-contact.php" method="post">
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<div class="control-group">
<label for="name" class="label-control">Name:</label>
<input type="text" class="form-control" name="name" id="name" placeholder="Your name..." required>
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<div class="control-group">
<label for="email" class="label-control">Email:</label>
<input type="email" class="form-control" name="email" id="email" placeholder="Your email..." required>
</div>
</div>
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div class="control-group">
<label for="subject" class="label-control">Subject:</label>
<input type="text" class="form-control" name="subject" id="subject" placeholder="Your subject..." required>
</div>
</div>
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div class="control-group">
<label for="message" class="label-control">Message:</label>
<textarea name="message" id="message" cols="30" rows="10" placeholder="Messages..." class="form-control" required></textarea>
</div>
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-12">
<img class="img-responsive" src="img/icon/contact.png" alt="Contact Icon">
<div>
<p class="title_contact">Contact:</p>
<p class="contact_phone"><i class="fa fa-phone-square"></i> +000</p>
<p class="contact_email"><i class="fa fa-envelope"></i> email#email.com</p>
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-12">
<img class="img-responsive" src="img/icon/support.png" alt="Contact Icon">
<div>
<p class="title_contact">Support:</p>
<p class="contact_phone"><i class="fa fa-envelope"></i> email#email.com</p>
<p class="contact_email"></p>
</div>
</div>
</div>
</div>
<button type="submit" class="btn-custom" data-dismiss="alert" id="sentcontact">Send It</button>
</form>
This is my html
An error always show up when page reloaded in contact
It always show up in my page each time I reload page, not after clicking submit button
But, when I run that code, it just showing the bootstrap_alert first then reload the page. How could I make it reload page first then showing up bootstrap_alert?
There are a lot of ways to do it. An easy way to achieve this would be passing through a parameter in the URL and checking it on page load.
// Check the URL parameter on page load
$(function(){
if(getUrlParameter('success') == '1') {
bootstrap_alert.warning('Message has been sent.');
}
});
// Set up the click event
$('#sentcontact').on('click', function(){
if (true){
var nextUrl = window.location.href;
nextUrl += (nextUrl.indexOf('?') === -1 ? '?' : '&') + 'success=1'
window.location = nextUrl;
}
});
// Simple function to read parameters out of the URL
function getUrlParameter(name) {
var url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
Solution 1
Modify href of the window when you programmatically reload, check for the hash fragment (onload) and decide to show the alert.
(function checkIfMsgSent() {
var url = window.location.href;
if ((/#message_sent/).test(url)) {
alert('Message has been sent.');
// bootstrap_alert.warning('Message has been sent.');
}
})();
$('#sentcontact').on('click', function(){
if (true){
window.location = window.location.href + "#message_sent";
window.location.reload();
}
});
Solution 2
Using localStorage, but this won't work if browser doesn't support localStorage (almost all modern browsers do have it).
(function checkIfMsgSent() {
if (typeof localStorage !== 'undefined') {
var isMsgSent = JSON.parse(localStorage.getItem("messageSent")); // JSON.parse because we want a boolean
if (isMsgSent) {
alert('Message has been sent.');
// bootstrap_alert.warning('Message has been sent.');
}
localStorage.removeItem('messageSent');
} else {
// localStorage not defined
alert('Your browser in incompatible for some features in this website');
}
})();
$('#sentcontact').on('click', function(){
if (typeof localStorage !== 'undefined') {
localStorage.setItem('messageSent', 'true');
} else {
// localStorage not defined
alert('Your browser in incompatible for some features in this website');
}
window.location.reload();
});

Sending data to a modal without redirecting in nodejs

I am using passport and flash to manage authentication. I want to send flash messages back to the UI per the documentation. In my scenario in the UI I am using a modal so doing a
res.render('login.ejs', { message: req.flash('loginMessage') });
won't work because you can only render on a page refresh. Therefore how can I send flash dataor any other kind of data to my page when fails to log in for some reason. Regardless of flash data in particular I cannot figure out how to render data to a modal with express.
routes.js
below the res.render never happens on a authentication failure.
//Home Page ===================================
app.get('/', function(req, res) {
res.render('login.ejs', { message: req.flash('loginMessage') });
});
//Login Modal =================================
app.post('/login', passport.authenticate('local-login', {
successRedirect : '/profile',
failureFlash : true
}));
index.ejs (where my modal is)
<div id="openModal" class="modalDialog">
<div>
X
<h2 id="logintitle">Log In</h2>
<% if (message.length>0) { %>
<div class="alert alert-danger">
<%= message %>
</div>
<% } %>
<form class="form-horizontal" action="/login" method="post" id="loginform">
<div class="form-group inner-addon left-addon">
<label class="sr-only" for="login_email">Email</label>
<i class="glyphicon glyphicon-user"></i>
<input type="email" class="form-control" name="email" placeholder="Email Address" />
</div>
<div class="form-group inner-addon left-addon">
<label class="sr-only" for="login_pass">Password</label>
<i class="glyphicon glyphicon-star-empty"></i>
<input type="password" class="form-control" name="password" placeholder="Password" />
</div>
<div id="forgotpass">
Forgot Password?
</div>
<div class="form-group">
<button type="submit" class="btn form-login-button">Log In</button>
</div>
</form>
<div class="strike">
<span>Log in with</span>
</div>
<div id="test" class="test">
<span class="fa fa-facebook"></span> Facebook
<span class="fa fa-google-plus"></span> Google
</div>
</div>
</div>
My understanding is I need to use javascript/ajax to prevent the post for being the redirect but I cannot figure out how to get the flash data to this point:
index.ejs (javascript)
$(function () {
$("#loginform").on("submit", function(e) {
e.preventDefault();
$.ajax({
url: $(this).attr("action"),
type: 'POST',
data: $(this).serialize(),
beforeSend: function () {
},
success: function (data) {
}
});
});
});
EDIT added some code from passport.js
function passport_login(req, email, password, done) {
//doing some validate and found bad password
return done(null, false, req.flash('loginMessage', 'Invalid Password'));
})
So after quite a bit of digging I have found the solution. The key was in recognizing jquery not express is the answer, letting the client handle the redirects and posts/gets. I have only include updates for a local login strategy but they would apply for your signup/social other social profiles as well.
Changes to passport.js (minor)
function passport_login(req, email, password, done) {
//doing some validate and found bad password
return done(null, false, 'Bad Password');
})
Changes to my route (the part I struggled with)
The key things to note here is I am deciding what data I sent through res.send. I could send anything, in this case info is what comes from passport.js ('Bad Password'). If i am happy and able to log in I send a simple little valid:true json.
//Login Modal =================================
app.get('/localLogin', function(req, res, next) {
passport.authenticate('local-login', function(err, user, info) {
if (err) { return next(err); }
//if there is no user in the response send the info back to modal
if (!user) {
return res.send(info);
}
//user was able to login, send true and redirect
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.send({ valid: true });
});
})(req, res, next);
});
Changes to my index.js
Added a div on top the my modal to display messages, remove old <%= message > piece and delete the action and method from the form jQuery will do that for us. (included full modal code to be transparent)
<div id="openModal" class="modalDialog">
<div>
X
<h2 id="logintitle">Log In</h2>
<div id="loginPopup"></div>
<form class="form-horizontal" id="loginform">
<div class="form-group inner-addon left-addon">
<label class="sr-only" for="login_email">Email</label>
<i class="glyphicon glyphicon-user"></i>
<input type="email" class="form-control" name="email" placeholder="Email Address" />
</div>
<div class="form-group inner-addon left-addon">
<label class="sr-only" for="login_pass">Password</label>
<i class="glyphicon glyphicon-star-empty"></i>
<input type="password" class="form-control" name="password" placeholder="Password" />
</div>
<div id="forgotpass">
Forgot Password?
</div>
<div class="form-group">
<button type="submit" class="btn form-login-button">Log In</button>
</div>
</form>
<div class="strike">
<span>Log in with</span>
</div>
<div id="test" class="test">
<span class="fa fa-facebook"></span> Facebook
<span class="fa fa-google-plus"></span> Google
</div>
</div>
</div>
Then I added the following Jquery code the last piece to the puzzle:
$(function(){
$('#loginform').on('submit', function(e) {
e.preventDefault();
var data = $(this).serialize();
$.get('/localLogin', data, function(result) {
if(result.valid == true)
{
window.location.href = '/profile';
}
else
{
$('#loginPopup').html(result);
}
});
});
});
Hope this helps someone, the information for a full end to end solution on how to do this is sparse.

Django JQuery AJAX submit form POST request refreshes the page

I have a login form for which I want the client to send AJAX POST request as below with error handling. In case of validation/authentication errors, I don't the page to be reloaded or refreshed to the url corresponding to POST request Handler(/users/login/) with the JSON string received from login view's response. I tried using event.preventDefault() as suggested by many answer on SO but could not make it work. Any clue as to what is going wrong here? I don't think this to be a Django issue. I know that the onsubmit is triggerred because the window redirects to the POST handler URL /users/login/ with the expected JSON string response - {"error": ["Entered mobile number is not registered"]}
JQuery code
$("#loginform").on('submit', function(event) {
event.preventDefault();
alert("Was preventDefault() called: " + event.isDefaultPrevented());
console.log("form submitted!");
var url = "/users/login/";
$.ajax({
type: "POST",
url:url,
data: $("#loginform").serialize(),
success: function(data)
{
console.log(data);
var result = JSON.stringify(data);
if(result.indexOf('errors')!=-1 ){
console.log(data);
if(data.errors[0] == "Mobile number and password don't match")
{
$('.login-error').text("Mobile number and password don't match");
}
else if(data.errors[0] == "Entered mobile number is not registered")
{
$('.login-error').text("Entered mobile number is not registered");
}
}
else
{
window.open("/users/profile/");
}
//var result = JSON.stringify(data);
// console.log(result);
}
})
});
View Handler
def login(request):
if request.method == 'POST':
mobile_number = request.POST.get('mobile_number', '')
password = request.POST.get('password', '')
data = {}
user_queryset = User.objects.filter(mobile_number=mobile_number)
if len(user_queryset) == 0:
data['error'] = []
data['error'].append("Entered mobile number is not registered")
# return JsonResponse(data)
elif len(user_queryset) == 1:
email = user_queryset[0].email
user = auth.authenticate(email=email, password=password)
if user is not None:
auth.login(request, user)
else:
data['error'] = []
data['error'].append("Mobile number and password don't match")
return JsonResponse(data)
HTML code
<div class="container-fluid bg-primary" id="login">
<div class="row">
<div class="col-lg-3 text-center">
</div>
<div class="col-lg-6 text-center">
<h1> </h1><h3> </h3>
<h2 class="section-heading">Login to your profile</h2>
<hr>
</div>
<div class="col-lg-3 text-center">
</div>
<h2> </h2>
<h2> </h2>
<h2> </h2>
</div>
<div class="col-md-4 col-md-offset-4 ">
<form id='loginform' action='/users/login/' method='post' accept-charset='UTF-8'>
{% csrf_token %}
<fieldset >
<div class="form-group">
<input type="text" name="mobile_number" id="mobile_number" tabindex="1" class="form-control" placeholder="Mobile Number" value="">
</div>
<div class="form-group">
<input type="password" name="password" id="password" tabindex="2" class="form-control" placeholder="Enter Password">
</div>
</fieldset>
<button type="submit" class="btn btn-primary btn-xl btn-block">LOG IN</button><br><br>
<span class="login-error"></span>
<h1> </h1><h1> </h1>
</form>
</div>
</div>
In addition to event.preventDefault();, it might be a good idea to also call event.stopPropagation() in this case.
Use : 'event.preventDefault()' or 'return false' after the ajax call.

Categories

Resources