Я пытаюсь объединить Angular 6 CRUD. Мой метод addCoins, кажется, добавляет запись дважды.
addCoin(name, price) {
const obj = {
name: name,
price: price
};
const uri = 'http://localhost/ng6crud/api/post-coins/' + name + '/' + price;
this
.http
.post(uri, obj)
.subscribe(res =>
console.log('Done'));
}
Я создал простой PHP api, который находится в каталоге ng6crud. Ниже приведен код для api/post-coins / - Если я использую postman для отправки в API, тогда он только вставляет данные один раз.
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');
$path = ltrim($_SERVER['REQUEST_URI'], '/'); // Trim leading slash(es)
$elements = explode('/', $path); // Split path on slashes
global $name, $price;
if(!empty($elements[3]))
{
$name = $elements[3];
}
if(!empty($elements[4]))
{
$price = $elements[4];
}
global $server;
$server = "localhost";
global $user;
$user = "someU";
global $pwd;
// $pwd = "someP"; // production
$pwd = "someP"; // local
global $db;
$db = "someDb";
//open connection to mysql db
$connection = mysqli_connect($server,$user,$pwd,$db) or die("Error " . mysqli_error($connection));
//fetch table rows from mysql db
$sql = "INSERT into coins (name, price) VALUES('" . $name . "','" . $price . "')";
// echo $sql;
// die();
if ($connection->query($sql) === TRUE) {
// echo "Record updated successfully";
} else {
// echo "Error updating record: " . $connection->error;
}
$connection->close();
?>
Комбинация файла.htaccess и тега "" в файле httpd-vhosts.conf позволяет api/post-coins/принимать два параметра для "name" и "price", которые должны быть включены в инструкцию sql insert - для пример api/post-coins/rupple/1.00 вставляет строку в db.
Ниже приведен файл.htaccess:
IndexIgnore * # prevent directory listing
Order deny,allow
Allow from *
# ------------------------------------------
# Rewrite so that php extentions are not shown
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ index.php%{REQUEST_URI} [QSA,L]
Ниже приведен тег Location в теге "" в файле httpd-vhosts.conf:
<Location /post-coins>
ForceType appllication/x-http-php
</Location>
Еще раз, если я использую почтальона для отправки в api/post-coins/rupple/1.00, тогда только одна запись будет в db. При использовании услуги в пределах Углового 6 он дважды вставляет данные. Я попытался удалить.subscribe, но потом ничего не вставлено, и я попытался удалить два параметра в конце URL-адреса, но это результаты - две пустые записи.
заранее спасибо
Чтобы ответить на вопрос @Vikas относительно того, как я реализую, следующим является create.component.html:
<div class="panel panel-primary">
<div class="panel-heading">
{{ title }}
</div>
<div class="panel-body">
<form [formGroup]="angForm" novalidate>
<div class="form-group">
<label class="col-md-4">Coin Name</label>
<input type="text" class="form-control" formControlName="name" #name />
</div>
<div *ngIf="angForm.controls['name'].invalid && (angForm.controls['name'].dirty || angForm.controls['name'].touched)" class="alert alert-danger">
<div *ngIf="angForm.controls['name'].errors.required">
Name is required.
</div>
</div>
<div class="form-group">
<label class="col-md-4">Coin Price</label>
<input type="text" class="form-control" formControlName="price" #price/>
</div>
<div *ngIf="angForm.controls['price'].invalid && (angForm.controls['price'].dirty || angForm.controls['price'].touched)" class="alert alert-danger">
<div *ngIf="angForm.controls['price'].errors.required">
Price is required.
</div>
</div>
<div class="form-group">
<button (click)="addCoin(name.value, price.value)" [disabled]="angForm.pristine || angForm.invalid" class="btn btn-primary">Add</button>
</div>
</form>
</div>
</div>
Файл creat.component.ts:
import { Component, OnInit } from '@angular/core';
import { CoinService } from '../../service/coin.service';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
@Component({
selector: 'app-create',
templateUrl: './create.component.html',
styleUrls: ['./create.component.css']
})
export class CreateComponent implements OnInit {
title = 'Add Coin';
angForm: FormGroup;
constructor(private coinservice: CoinService, private fb: FormBuilder) {
this.createForm();
}
createForm() {
this.angForm = this.fb.group({
name: ['', Validators.required ],
price: ['', Validators.required ]
});
}
addCoin(name, price) {
this.coinservice.addCoin(name, price);
}
ngOnInit() {
}
}
И coin.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable()
export class CoinService {
result: any;
constructor(private http: HttpClient) {}
addCoin(name, price) {
const obj = {
name: name,
price: price
};
const uri = 'http://localhost/ng5crud/api/post-coins/' + name + '/' + price;
this
.http
.post(uri, obj)
.subscribe(res =>
console.log('Done'));
}
getCoins() {
const uri = 'http://localhost/ng5crud/api/get-coins/';
return this
.http
.get(uri);
}
editCoin(id) {
const uri = 'http://localhost/ng5crud/api/get-coins-id/' + id;
return this
.http
.get(uri);
}
updateCoin(name, price, id) {
const uri = 'http://localhost/ng5crud/api/put-coins/' + id;
const obj = {
name: name,
price: price
};
this
.http
.post(uri, obj)
.subscribe(res => console.log('Done'));
}
deleteCoin(id) {
const uri = 'http://localhost/ng5crud/api/delete-coins/' + id;
return this
.http
.get(uri);
}
}
И routerConfig.ts
import { Routes } from '@angular/router';
import { CreateComponent } from './components/create/create.component';
import { EditComponent } from './components/edit/edit.component';
import { IndexComponent } from './components/index/index.component';
import { DeleteComponent } from './components/delete/delete.component';
export const appRoutes: Routes = [
{ path: 'create',
component: CreateComponent
},
{
path: 'edit/:id',
component: EditComponent
},
{ path: 'index',
component: IndexComponent
},
{ path: 'delete/:id',
component: DeleteComponent
}
];
@Debojyoti, я только что видел ваш ответ. Я закончил создание следующего, которое ничего не вернуло, но я взглянул на сетевую панель - см. Снимок экрана ниже:
import { HttpErrorResponse } from '@angular/common/http';
import { throwError } from 'rxjs';
import { catchError} from 'rxjs/operators';
addCoin(name, price) {
const obj = {
name: name,
price: price
};
const uri = 'http://localhost/ng5crud/api/post-coins/' + name + '/' + price;
this
.http
.post(uri, obj)
.pipe(
catchError(this.handleError) // then handle the error
)
.subscribe(res =>
console.log('Done'));
}
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.error(
'Backend returned code ${error.status}, ' +
'body was: ${error.error}');
}
// return an observable with a user-facing error message
return throwError(
'Something happened; please try again later.');
};
Я понял это, и я благодарю каждого из вас за то, что помог мне повторить это снова и снова.
Поскольку мой PHP API для всех интенсивных целей "GET":
const uri = 'http://localhost/ng5crud/api/post-coins/' + name + '/' + price;
Тогда вызов функции "POST" приведет к отключению API дважды - см. Прикрепленный снимок экрана ниже:
const obj = {
name: name,
price: price
};
const uri = 'http://localhost/ng5crud/api/post-coins/' + name + '/' + price;
this
.http
.post(uri, obj)
Таким образом, я изменил его на функцию "GET", и он работает отлично, только с одной записью
addCoin(name, price) {
const obj = {
name: name,
price: price
};
const uri = 'http://localhost/ng5crud/api/post-coins/' + name + '/' + price;
this
.http
.get(uri)
.pipe(
catchError(this.handleError), // then handle the error
map(res => {
console.log(res);
})
)
.subscribe(res =>
console.log('Done'));
}
В этом путешествии я обнаружил (qaru.site/questions/15861178/...), что карта импортируется по-разному в Angular 6 и используется по-разному в методе.get
Вместо импорта с
import 'rxjs/add/operator/map';
Вы используете следующее:
import { map } from 'rxjs/operators';
Вместо.get(). Map()
this
.http
.get(uri)
.map(res => {console.log(res)});
Вы используете карту, внутри.pipe
this
.http
.get(uri)
.pipe(
catchError(this.handleError), // then handle the error
map(res => {
console.log(res);
})
)
Все вместе, это моя новая рабочая монета.service.ts:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { HttpErrorResponse } from '@angular/common/http';
import { throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { map } from 'rxjs/operators';
@Injectable()
export class CoinService {
constructor(private http: HttpClient) {}
addCoin(name, price) {
const obj = {
name: name,
price: price
};
const uri = 'http://localhost/ng5crud/api/post-coins/' + name + '/' + price;
this
.http
.get(uri)
.pipe(
catchError(this.handleError), // then handle the error
map(res => {
console.log(res);
})
)
.subscribe(res =>
console.log('Done'));
}
getCoins() {
const uri = 'http://localhost/ng5crud/api/get-coins/';
return this
.http
.get(uri)
.pipe(
catchError(this.handleError), // then handle the error
map(res => {
console.log(res);
})
);
}
editCoin(id) {
const uri = 'http://localhost/ng5crud/api/get-coins-id/' + id;
return this
.http
.get(uri)
.pipe(
catchError(this.handleError), // then handle the error
map(res => {
console.log(res);
})
);
}
updateCoin(name, price, id) {
const uri = 'http://localhost/ng5crud/api/put-coins/' + id;
const obj = {
name: name,
price: price
};
this
.http
.post(uri, id)
.pipe(
catchError(this.handleError), // then handle the error
map(res => {
console.log(res);
})
)
.subscribe(res => console.log('Done'));
}
deleteCoin(id) {
const uri = 'http://localhost/ng5crud/api/delete-coins/' + id;
return this
.http
.get(uri)
.pipe(
catchError(this.handleError), // then handle the error
map(res => {
console.log(res);
})
);
}
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.error(
'Backend returned code ${error.status}, ' +
'body was: ${error.error}');
}
// return an observable with a user-facing error message
return throwError(
'Something happened; please try again later.');
}
}
Серьезно, спасибо вам за вашу помощь. Это возвращает меня к началу девяностых, когда программисты были хороши, и мы помогали друг другу.
Сделать php не принимать первый запрос на предварительный рейс (ОПЦИИ)
Просто измените свой PHP-код, как
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');
if ($_SERVER['REQUEST_METHOD'] != "OPTIONS") {
$path = ltrim($_SERVER['REQUEST_URI'], '/'); // Trim leading slash(es)
$elements = explode('/', $path); // Split path on slashes
global $name, $price;
if (!empty($elements[3])) {
$name = $elements[3];
}
if (!empty($elements[4])) {
$price = $elements[4];
}
global $server;
$server = "localhost";
global $user;
$user = "someU";
global $pwd;
// $pwd = "someP"; // production
$pwd = "someP"; // local
global $db;
$db = "someDb";
//open connection to mysql db
$connection = mysqli_connect($server, $user, $pwd, $db) or die("Error " . mysqli_error($connection));
//fetch table rows from mysql db
$sql = "INSERT into coins (name, price) VALUES('" . $name . "','" . $price . "')";
// echo $sql;
// die();
if ($connection->query($sql) === TRUE) {
// echo "Record updated successfully";
} else {
// echo "Error updating record: " . $connection->error;
}
}
$connection->close();
?>
Похоже, что приложение PHP и приложение Angular работают на отдельной комбинации протокола (http/https), домена и порта. Я вижу, что заголовки CORS были добавлены в PHP-код.
Это заставляет меня думать, что сделано 2 запроса, чтобы проверить, разрешен ли запрос в соответствии с запросом CORS (OPTIONS
) и обычным запросом POST
. Следовательно, запись вставляется дважды. Вы можете обнаружить метод запроса и вернуть заголовки CORS и установить тело ответа как ничто в соответствии с запросом CORS OPTIONS
и вставить запрос POST
аналогичный следующему (не проверен).
<?php
if ($_SERVER['method'] === 'OPTIONS') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');
header("HTTP/1.1 200 OK");
exit;
}
if ($_SERVER['method'] === 'POST') {
header("HTTP/1.1 200 OK");
$path = ltrim($_SERVER['REQUEST_URI'], '/'); // Trim leading slash(es)
$elements = explode('/', $path); // Split path on slashes
global $name, $price;
if (!empty($elements[3])) {
$name = $elements[3];
}
if (!empty($elements[4])) {
$price = $elements[4];
}
global $server;
$server = "localhost";
global $user;
$user = "someU";
global $pwd;
// $pwd = "someP"; // production
$pwd = "someP"; // local
global $db;
$db = "someDb";
//open connection to mysql db
$connection = mysqli_connect($server, $user, $pwd, $db) or die("Error " . mysqli_error($connection));
//fetch table rows from mysql db
$sql = "INSERT into coins (name, price) VALUES('" . $name . "','" . $price . "')";
// echo $sql;
// die();
if ($connection->query($sql) === true) {
// echo "Record updated successfully";
} else {
// echo "Error updating record: " . $connection->error;
}
$connection->close();
exit;
}
header("HTTP/1.1 404 Not Found");
exit;
?>