Please read the question in detail since it is a long one with various edits and extended updates as per the request of other users.
I am trying to send data to php file using angular2. I am doing the angular project in Unix and the var/www/html/
is the php Xampp folder locations for running the php files.
My folder structure is like this:-
var/www/html/
|_(angproject)
|_(phpscript)
| |_login.php
|_(src)
|_(app)
|_(admin)
| |_(login)
| | |_login.component.ts
| |
| |_admin.component.ts
|
|_(_admin_service)
| |_admin.login.ts
|
|_(_animations)
|
|_(front)
|
|_(_models)
| |_admin.model.ts
|
|_app.module.ts
My app.module.ts file is like this:-
import { HttpModule, Http, Response, Headers, RequestOptions} from '@angular/http';
import { HttpClientModule } from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { FormsModule } from '@angular/forms';
import { APP_BASE_HREF } from '@angular/common';
import { CanActivate } from "@angular/router";
import { AppComponent } from './app.component';
import { FrontComponent } from './front/front.component';
import { AdminComponent } from './admin/admin.component';
import { LoginComponent } from './admin/login/login.component';
import { DashboardComponent } from './admin/dashboard/dashboard.component';
import { HeaderComponent } from './admin/header/header.component';
import { FooterComponent } from './admin/footer/footer.component';
import { LeftmenuComponent } from './admin/leftmenu/leftmenu.component';
import { NavbarComponent } from './admin/navbar/navbar.component';
import { ShortcutbarComponent } from './admin/shortcutbar/shortcutbar.component';
import { AdminLoginService } from './_admin_service/admin.login';
const appRoutes: Routes = [
{ path: 'admin',
component: AdminComponent,
children: [
{ path: '', component: LoginComponent},
{ path: 'dashboard', component: DashboardComponent}
]
}
];
@NgModule({
declarations: [
AppComponent,
FrontComponent,
AdminComponent,
LoginComponent,
DashboardComponent,
HeaderComponent,
FooterComponent,
LeftmenuComponent,
NavbarComponent,
ShortcutbarComponent
],
imports: [
HttpModule,
HttpClientModule,
BrowserModule,
BrowserAnimationsModule,
FormsModule,
RouterModule.forRoot(
appRoutes,
{ enableTracing: true } // <-- debugging purposes only
)
],
providers: [{provide: APP_BASE_HREF, useValue : '/' },AdminLoginService],
bootstrap: [AppComponent]
})
export class AppModule { }
My login.component.ts file is this:-
import { Component, OnInit, Input } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { fadeInAnimation } from '../../_animations/index';
import { Admin } from '../../_models/admin.model';
import { AdminLoginService } from '../../_admin_service/admin.login';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css'],
animations: [fadeInAnimation],
host: { '[@fadeInAnimation]': '' },
providers: [AdminLoginService]
})
export class LoginComponent implements OnInit {
loading = false;
returnUrl: string;
responseStatus:Object= [];
status:boolean ;
//@Input() admin:Admin;
model = new Admin('', '', '', 'Emailsss','Passwordsss');
constructor(
private route: ActivatedRoute,
private router: Router,
private _adminLogin: AdminLoginService
){}
submitPost()
{
//console.log("submit Post click happend " + this.model.email)
//console.log(this.model);
this._adminLogin.postLogin(this.model).subscribe(
data => console.log(this.responseStatus = data),
err => console.log(err),
() => console.log('Request Completed')
);
this.status = true;
}
ngOnInit() {
}
}
The service file admin.login.ts file is this:-
import { Http, Response, Headers, RequestOptions} from '@angular/http';
import { HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import 'rxjs/add/operator/map';
import { Admin } from '../_models/admin.model';
@Injectable()
export class AdminLoginService {
http : Http;
actionUrl : string;
admin_login_Url: string;
postData: Admin;
constructor(public _http: Http) {
this.http = _http;
this.admin_login_Url = 'http://localhost/angproject/phpscript/login.php';
}
postLogin(postData:Admin) {
let headers = new Headers();
headers.append("Access-Control-Allow-Origin","*");
headers.append("Access-Control-Allow-Methods","GET, POST");
headers.append("Content-Type","application/json");
let options = new RequestOptions({ headers: headers });
console.log(postData);
this.actionUrl = this.admin_login_Url;
return this.http.post(this.actionUrl, {postData}, options)
.map(res => res.json());
}
}
And ultimately, my login.php file is this:-
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST");
header("Access-Control-Allow-Headers: *");
header("Content-Type: application/json; charset=utf-8");
include('connection.php');
$rawData = file_get_contents("php://input");
$data = json_decode($rawData, true);
$error = array();
if(isset($data['postData']['email']) && !empty($data['postData']['email']))
$email = $data['postData']['email'];
else
$error[] = "Email was not entered";
if(isset($data['postData']['password']) && !empty($data['postData']['password']))
$password = $data['postData']['password'];
else
$error[] = "Password was not entered";
if(empty($error))
{
$runQuery = "SELECT * FROM users WHERE email = '$email' AND password = '$password'";
$result = $conn->query($runQuery);
if ($result->num_rows > 0)
{
$response['status'] = 1;
$response['message'] = "Login successfully";
$response['error'] = 0;
}
else
{
$response['status'] = 0;
$response['message'] = "An error occured while logging in";
$response['error'] = $conn->error;
}
}
else
{
$response['status'] = 0;
$response['message'] = "Parameter missing";
$response['error'] = $error;
}
$respond = json_encode($response);
echo $respond;
exit;
?>
Now here is the problem. When testing in Chrome, clicking the submit button once is firing calling for the php script (Ajax) twice. The first call doesn't send any data and hence it shows validation message in return response. The second call sends the form's data and hence fetching the desired result by matching the data sent.
In case of firefox, I am getting this response:-
How can I solve it?
Note:
Here are the Request Headers of the "first call" in chrome:
Here are the Request Headers of the "second call" in chrome:
EDIT: Dated- 04-04-2018:
As per the suggestions from David, I made subsequent changes in my login.php file:
header("Access-Control-Allow-Origin: http://localhost:4200");
header("Access-Control-Allow-Headers: application/x-www-form-urlencoded");
header("Access-Control-Allow-Methods: POST, GET, OPTIONS");
In the admin.login.ts file, I made the following changes:-
postLogin(postData:Admin) {
let headers = new Headers();
headers.append("Accept", "q=0.8;application/json;q=0.9");
this.actionUrl = this.admin_login_Url;
return this.http.post(this.actionUrl, {postData}, { headers: headers })
.map(res => res.json()).share();
}
}
Question 1: For the above code, I took reference from this site. Yet, I am still getting the error. How can I fix this in Firefox?
In the above code, I added the line headers.append("Accept", "q=0.8;application/json;q=0.9");
to overcome an error shown below:-
How can I overcome this problem?
Question 2:
In Firefox, the console reads:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost/angproject/phpscript/register.php. (Reason: invalid token ‘application/x-www-form-urlencoded’ in CORS header ‘Access-Control-Allow-Headers’).
When checking in Chrome, I can see two calls in the network tab in console. The first call's request type is OPTIONS, while the second call has request type as POST.
In case of Firefox, I am getting only one call with request type OPTIONS. The POST request isn't taking place at all.
How can I fix this?
Having 2 requests is normal, due to CORS implementation (client on localhost:4200
, server on localhost
= different ports).
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Your problem is that you specified some CORS headers in your request
headers.append("Access-Control-Allow-Methods","GET, POST");
headers.append("Access-Control-Allow-Origin","*");
These headers are meant to be added server side, you don't need to send them from angular. They are actually causing the problem.
Remove them and it should work.
More information about Access-Control-Allow-Headers
Access-Control-Allow-Headers
normally accepts a list of comma-separated headers.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
The wildcard (*) value that you have on your PHP code is not supported on all browsers. On Firefox, the wildcard is not implemented yet https://bugzilla.mozilla.org/show_bug.cgi?id=1309358
That's why firefox is bloking your POST, since the preflight (OPTIONS) request kind of fails
You don't need to specify Content-Type
in your list since it's accepted by default
The simple headers, Accept, Accept-Language, Content-Language, Content-Type (but only with a MIME type of its parsed value (ignoring parameters) of either application/x-www-form-urlencoded, multipart/form-data, or text/plain), are always available and don't need to be listed by this header.
Edit: actually, you do need to specify content-type in the list of accepted headers since you are sending application/json
, which is not in the above list