Not able to accept response from $.ajax api Post request - javascript

I am trying to call a rest api from my login page on click of a button. I am using $.ajax to do so. The POST request gets sent and 200 code is also showing on backend. But in my browser network tab it shows failed. I don't know what is wrong. I am trying to print the response in the console when response comes from api, but nothing get printed. That means api is getting the POST req, it is generating a token for me and sending it to me but my client side is failing to get the response. Here is my code and essential screenshots. P.S. I don't get any error in console.
import React, {Component} from 'react'
import {Router, Route, browserHistory, IndexRoute} from "react-router"
require("./login.css")
import valueLink from 'valuelink'
import $ from 'jquery'
export default class LogInComponent extends Component {
handleLoginButtonClick() {
var settings = {
"async": true,
"crossDomain": true,
"url": "https://******appspot.com/auth/login/",
"method": "POST",
"credentials": 'include',
"headers": {
"content-type": "application/x-www-form-urlencoded",
},
"data": {
"password": "****",
"username": "****"
}
}
$.ajax(settings).done(function () {
alert("success");
});
}
render(){
return (
<div className="LoginPage">
<div className="login-page">
<div className="form">
<form className="login-form">
<input id="username" type="username" placeholder="username"/>
<input id="password" type="password" placeholder="password"/>
<button onClick={this.handleLoginButtonClick}>login</button>
<p className="message">Not registered? Request Username and Password</p>
</form>
</div>
</div>
</div>
);
}
}
This is my network tab
This is when I click :3000... from initiator column. The highlighted line is where it takes me.

Your button submits the form when clicked because the default type for the button element is submit. This happens even when you give it your own click handler. The form submit basically just reloads your page since the form lacks the action-attribute, so it reloads during your ajax request, which cancels it (as you can see from your network tab). You have several ways to solve this.
You can add type="button" to the button element:
<button type="button" onClick={this.handleLoginButtonClick}>login</button>
You can cancel the default native event handling in the onClick handler:
handleLoginButtonClick(event) {
event.preventDefault();
...
}
You can use an onSubmit handler on the form element, instead of an onClick handler on the button:
<form className="login-form" onSubmit={this.handleLoginFormSubmit}>
...
</form>
with
handleLoginFormSubmit(event){
event.preventDefault(); // Stop form from submitting
...
}

Related

How prevent reload after post request?

I am trying to make a post request to the server and do something with the response. Things seem to work on the server-side. The problem is that the page reloads upon completion of the response and I cannot do anything with the response.
The common suggestions are using button or preventDefault. These suggestions do not solve the problem: as you can see below, the input type is button (not submit) and preventDefault() on the event does not work.
Does anyone have an idea about what I am missing?
<form id="modelCodeForm">
<label for="codehere"></label>
<div id="modelAreaDiv">
<textarea id="modelArea" cols="60" rows="20">
stuff
</textarea>
<br>
<input id="submitUserModel" type="button" value="run on server">
</div>
</form>
function initializeUserModel(){
let model = document.getElementById("modelArea").value;
fetch('http://localhost:8080/', {
method: 'post',
headers: {'Content-Type': 'text/plain'},
body: model
})
.then(response => response.json())
.then(data => {
console.log(data);
}).then(console.log("received!"))
}
I got to the bottom of this. It turns out that the problem was due to VS Live Server which was detecting a change in the folder and hot-loading the app. The change was due to the backend, in the same folder, saving a log. Really silly thing to miss...
If you want to trigger your function when the form is submitted then you can use the "onsubmit" event listener available on HTML forms.
So you would do onsubmit="initializeUserModel(event)". You pass it the event object so you can call event.preventDefault() in the function and stop the page from reloading.
Change your input to type="submit" (or make it a button of type="submit") or the form submission won't be triggered.
<form id="modelCodeForm" onsubmit="initializeUserModel(event)">
<label for="codehere"></label>
<div id="modelAreaDiv">
<textarea id="modelArea" cols="60" rows="20">Stuff</textarea>
<br />
<input id="submitUserModel" type="submit" value="run on server" />
</div>
</form>
function initializeUserModel(event) {
event.preventDefault();
let model = document.getElementById("modelArea").value;
fetch("http://localhost:8080/", {
method: "post",
headers: { "Content-Type": "text/plain" },
body: model,
})
.then((response) => response.json())
.then((data) => {
console.log(data);
})
.then(console.log("received!"));
}

Fetching API data with active login

I'm using backend functions on my website to gather data from a separate website.
I can access the data easily with something like...
fetch( DataURL, {"method": "get"} )
.then( httpResponse => httpResponse.json() )
.then( json => { console.log(json); } )
However, there is additional data fields in the json data that aren't visible unless you are logged in.
I'm trying to use a POST fetch to complete the login form, and then send the GET to retrieve the API data afterwards. Have been unsuccessful so far.
fetch( LoginURL, {
"method": "post",
"body": "Username=myusername&Password=mypassword",
"headers": {"Content-Type": "application/x-www-form-urlencoded"}
})
.then( fetch( DataURL, {"method": "get"} )
.then( httpResponse => httpResponse.json() )
.then( json => { console.log(json); })
})
I'm basing the body data on what I see in the form in their source code. Not completely sure if I'm doing that right.
This is a phpBB style website that needs to be logged into.
<form action="./ucp.php?mode=login" method="post" id="navloginform" name="loginform">
<div class="form-group">
<input type="text" placeholder="Username" name="username" size="10" class="form-control" title="Username"/>
</div>
<div class="form-group">
<input type="password" placeholder="Password" name="password" size="10" class="form-control" title="Password"/>
</div>
<div class="form-group">
<div class="checkbox">
<label for="autologin-navbar"><input type="checkbox" name="autologin" id="autologin-navbar" tabindex="4" /> Remember me</label>
</div>
</div>
<input type="hidden" name="redirect" value="./ucp.php?mode=login" />
<button type="submit" name="login" class="btn btn-primary btn-block"><i class="fa fa-sign-in fa-fw" aria-hidden="true"></i> Login</button>
</form>
I'm very clearly doing something wrong.
I think my main issues I'm struggling with are:
Is my guess at how to use their form data correct?
How do I verify the login even worked to begin with?
Do I need to do something special to maintain the login before sending a second fetch?
Just going to share how I got mine working, though may be different for other cases.
--
Go to the website you're trying to login to, and open up your browser development tools.
Select the 'Network' tab, and login.
Find the network entry from your login, and go to the 'Headers' tab. Near the bottom of the entry will show which headers were used. Not all of these are critical. Something like below:
When using your fetch call, create the same headers as needed in the body.
const LoginURL = 'www.ExampleWebpageLogin.com./ucp.php?mode=login';
let form = new FormData();
form.append('username', 'MyUsername');
form.append('password', 'MyPassword');
form.append('login', 'Login');
var headers = { 'method': 'post',
'body': form,
'credentials': 'include'}
await fetch( LoginURL, headers)
.then( loginResponse => {
console.log(loginResponse);
})
In my case, the loginResponse included 2 critical cookies.
user_id - This cookie value remained =1 when not logged in, and was set to my user id once successful.
sid - Most likely session ID, which they use to preserve login session.
For both the login post and future GET requests, 'credentials' are required.

Axios request in Vue.js method working when launched from "mounted()" but not when launched from html <form>

When I authenticate to Laravel Passport backend with Nuxt.js like below, it works and I get a token:
mounted() {
this.axiosGetToken()
}
But, if I run the method with a button in a form, like this:
<form #submit="axiosGetToken()">
<button type="submit">Axios login</button>
</form>
Then, I get the status (canceled) for the Laravel page in the Network tab of my browser developer's tool.
The method looks like this:
axiosGetToken() {
const url = 'http://laravel.test/oauth/token'
const params = {
client_id: 2,
client_secret: 'S0gpcgfIDgbvIHCL3jIhSICAiTsTUMOR0k5mdaCi',
grant_type: 'password',
username: 'me#home.com',
password: '1qaz#WSX'
}
const headers = {
}
this.$axios
.post(url, params, headers)
.then(response => {
// eslint-disable-next-line
console.log(response)
})
.catch(response => {
// eslint-disable-next-line
console.log(response)
})
},
What's wrong with this form ?
You should add prevent modifier :
<form #submit.prevent="axiosGetToken()">
<button type="submit">Axios login</button>
</form>
by default the submit event try to reload the page and searching an action from the back-end in order to run it, so the prevent modifier will prevent the action and allows the running of the js event handler.
As mentioned above, if you use a form with a button of type="submit", when pressing that button, it will use the default client behavior and send a request to the form action URL, adding a prevent will stop that behavior.
Although it is a valid answer, I would suggest adding a #click="axiosGetToken()" on the button.
<form>
<button type="button" #click="axiosGetToken()">Axios login</button>
</form>

Login components in vuejs

I've built a login component with the below code for users to log in the backend is flask and is using flask_login.
const LoginScreen = {
template: `
<div>
<h1>Sign In</h1>
<form id="loginform" class="pure-form">
<fieldset>
<input type="text" name="email" placeholder="email" v-model="logindetails.email"/>
<input type="password" name="password" placeholder="password" v-model="logindetails.password"/>
<button class="pure-button pure-button-primary" v-on:click="login">Login</button>
</fieldset>
</form>
</div>
`,
data: function () {
return {
logindetails:{}
}
},
methods: {
login: function(){
axios.post('/login/',
this.logindetails,
{
headers: {
'Content-type': 'application/json',
'Accept': 'application/json',
'X-CSRF-TOKEN': document.querySelector('#csrftoken').getAttribute('content')
}
}
).then(response => { this.logindetails = {};
this.$router.push({path: '/'});
}
)
.catch(function (error) {
console.log(error);
});
}
}
};
It seems to work correctly (though there are times when it asks me to log in again for seemingly no reason), however the component is putting the submitted form details into the querystring of the url ( example ).
Would anyone be able to tell me what I am doing wrong or, if I am doing this totally incorrectly, point me in the direction of a codebase/guide that is doing logins correctly?
Many thanks in advance.
Take a look at Vue v-on event modifiers to modify the default element behavior.
In your case you can do:
<button #click.prevent="login">Login</button>
Or in the form tag (ensure your submit button is type "submit"):
<form #submit.prevent="login">
with regards to the component is putting the submitted form details into the querystring of the url, the reason is that clicking on the button also trigger submit on the form.
HTML form submits form values to the server.
But normally in JS frameworks like Vue or React, form values are submited through ajax, without any page refresh. So using <form> has not much value here.
2 things you could do in this case
Remove <form> element. it should still works corectly
handle the form submit event.
For e.g.
<form #submit="handleSubmit($event)">
methods: {
handleSubmit:(e) =>{
e.preventDefault();
}
}

How do I call inputs and buttons in my EmberJS acceptance tests?

This is maddening, as there is little to no help on google/the internet for this. https://guides.emberjs.com/v2.4.0/testing/acceptance/ is also not very helpful, even though it tries. I am basically learning this from scratch. I know a modest amount of HTML, handlebars, and javascript, but emphasis on the modest.
Here is my template, much of it is copied code from my architect's design who doesn't have time to help me :
<form {{action "login" on="submit"}} class="col-md-4 col-md-offset-4">
{{#if loginFailed}}
<div class="alert">Invalid username or password.</div>
{{/if}}
<div class="form-group">
<label for="inputEmail">Email address</label>
{{input value=username type="email" class="form-control" id="inputEmail1" placeholder="Email"}}
</div>
<div class="form-group">
<label for="inputPassword">Password</label>
{{input value=password type="password" class="form-control" id="inputPassword" placeholder="Password"}}
</div>
<button type="submit" class="btn btn-default" disabled={{isProcessing}}>Log in!</button>
</form>
Note the application runs correctly (I'm able to generate a login screen which connects to my local database, and I am able to log in correctly when the credentials are correct and not login when they aren't).
There is also a large .js file for the route which has an ajax call and corresponding promise from it, which I can sort of understand, but bottom line, it works :
import Ember from 'ember';
import ajax from 'ic-ajax';
export default Ember.Route.extend({
loginFailed: false,
isProcessing: false,
beforeModel: function(){
this.store.unloadAll('security-setting');
this.store.unloadAll('org');
var user = this.modelFor('application').user;
user.setProperties({email: '', auth: ''});
},
actions: {
login: function() {
this.setProperties({
loginFailed: false,
isProcessing: true
});
var _this = this;
ajax({
url: _this.modelFor('application').url + '/signin.json/',
type: 'post',
data: {session: {email: this.controller.get("username"), password: this.controller.get("password")}},
}).then(
function(result) {
// proprietary stuff, it all works
},
function(error){
alert(error.jqXHR.responseText);
this.set('isProcessing', false);
_this.set("loginFailed", true);
}
);
},
},
reset: function() {
this.set('isProcessing', false);
this.controller.set('password', '');
this.controller.set('username', '');
}
});
Here is the acceptance test I am trying to write :
import Ember from 'ember';
import { module, test } from 'qunit';
import startApp from 'ember-super-user/tests/helpers/start-app';
module('Acceptance | login', {
beforeEach: function() {
this.application = startApp();
},
afterEach: function() {
Ember.run(this.application, 'destroy');
}
});
test('visiting /login and fail a login attempt', function(assert) {
visit('/login');
fillIn('input.username', 'insert-username-here');
fillIn('input.password', 'insert-password-here');
click('button.submit');
// I know this assert is wrong but I haven't even gotten this far yet so I'm // not thinking about it; basically what happens is a popup appears and says // wrong-username-or-password-etc
andThen(function() {
assert.equal(currentURL(), '/login');
});
});
Execution dies on the fillIn lines of code. I really don't know what to do here, I've tried all combinations of 'input.username', 'input.inputEmail1', 'input.inputEmail'... I'm just not sure what I'm supposed to do, at all. I'm also pretty sure that 'button.submit' will not just magically work either. Then, I know I'll be even more lost when I try to fill in the andThen promise to acknowledge the fact that a popup appeared saying wrong-password-etc.
Please help; thanks very much for your time.
EDIT: I have been able to fix the fillIn parts of the test, but the click (probably the click, anyway, as the error messages are unclear as to which line is the problem) is producing some errors that I am unable to diagnose. Error messages appear in the output of the QUnit test suites that don't make sense to me --
TypeError: Cannot read property 'set' of undefined# 4286 ms
Expected:
true
Result:
false
Diff:
trufalse
at http://localhost:7357/assets/test-support.js:3592:13
at exports.default._emberTestingAdaptersAdapter.default.extend.exception (http://localhost:7357/assets/vendor.js:52460:7)
at onerrorDefault (http://localhost:7357/assets/vendor.js:43162:24)
at Object.exports.default.trigger (http://localhost:7357/assets/vendor.js:67346:11)
at Promise._onerror (http://localhost:7357/assets/vendor.js:68312:22)
at publishRejection (http://localhost:7357/assets/vendor.js:66619:15)
EDIT 2: The latest change for changing 'button' to 'submit' still doesn't work. Current error message :
Error: Element input[type='submit'] not found.# 166 ms
Expected:
true
Result:
false
Diff:
trufalse
Source:
at http://localhost:7357/assets/test-support.js:3592:13
at exports.default._emberTestingAdaptersAdapter.default.extend.exception (http://localhost:7357/assets/vendor.js:52460:7)
at onerrorDefault (http://localhost:7357/assets/vendor.js:43162:24)
at Object.exports.default.trigger (http://localhost:7357/assets/vendor.js:67346:11)
at Promise._onerror (http://localhost:7357/assets/vendor.js:68312:22)
at publishRejection (http://localhost:7357/assets/vendor.js:66619:15)
Your selector for each input is wrong. Since you gave each one an id, you can do this:
fillIn('#inputEmail1', 'insert-username-here');
fillIn('#inputPassword', 'insert-password-here');
Remember that you are using CSS selectors for the first argument of fillIn, IDs use # prefix and classes use ..
For the submit button, you did not add a class or ID, but if it is the only submit button on the page you can target it like this:
click('button[type="submit"]');
The fillIn and click functions takes in css selectors. so for example, clicking on the submit would look like,
click("input[type='submit']");

Categories

Resources