插入产品和上传文件分开工作,但在 Angular 6 中不能一起工作
insert product and upload file work separately but not together in Angular 6
我正在开发我的第一个 CRUD 测试应用程序。
我有一个表格,其中包含典型的产品名称、价格...和一个用于上传产品的输入文件。
我为表单的更改事件创建了一个事件处理程序方法。工作正常。
我创建了这个 uploadFile() 方法,它工作正常。
上传文件-service.ts
import {Injectable, Input} from '@angular/core';
import {Http, Response, Headers, RequestOptions} from '@angular/http';
import {Router, ActivatedRoute,Params} from '@angular/router';
import {map} from 'rxjs/operators';
import {_GLOBAL} from './global.service';
import {Observable} from 'rxjs';
import {Producto} from '../models/Producto.model';
@Injectable()
export class UploadFileService
{
public url:string;
public filesToUpload:Array<File>;
constructor()
{
this.url=_GLOBAL.url;//this has the URL of the REST service
this.filesToUpload=[];
}
uploadFile(url:string, params:Array<string>,filesToUpload:Array<File>)
{
return new Promise((resolve, reject)=>{
var formData:any= new FormData();
var asyncRequest=new XMLHttpRequest();
for(var i=0; i<filesToUpload.length;++i)
{
formData.append('filesUploaded[]',filesToUpload[i],filesToUpload[i].name);
}
asyncRequest.onreadystatechange=function(){
if(asyncRequest.readyState==4){
if(asyncRequest.status==200){
resolve(JSON.parse(asyncRequest.response));
}else{
reject(asyncRequest.response);
}
}
}
asyncRequest.open('POST',url,true);
asyncRequest.send(formData);
});
}
fileChangeEvent(ElementObjectReferenceWhichTriggersEvent:any)// in this case, the input type="file"
{
this.filesToUpload=<Array<File>>ElementObjectReferenceWhichTriggersEvent.target.files;//captura los archivos mandados en el input
console.log(ElementObjectReferenceWhichTriggersEvent.target);
console.log(ElementObjectReferenceWhichTriggersEvent.target.files[0]);
console.log(this.filesToUpload);
// return this.filesToUpload;
}
}
还有这个服务
创建产品。service.ts
在这个上我有 createProduct()
方法,它从上面的服务调用 uploadFile() 方法,从 HTTP 服务调用 http.post()
。
问题是,这两种方法单独使用都很好,但一起使用就不行了。
我是说,当我在这个服务上做这个的时候:
import {Injectable} from '@angular/core';
import {Http, Response, Headers, RequestOptions} from '@angular/http';
import {Router, ActivatedRoute,Params} from '@angular/router';
import {map} from 'rxjs/operators';
import {_GLOBAL} from './global.service';
import {Observable} from 'rxjs';
import {Producto} from '../models/Producto.model';
import {UploadFileService} from './upload-file.service';
@Injectable()
export class CreateProductService{
public url:string;
public errorMessage:string;
public productToInsert:Producto;
public imageData:string;
constructor(
private _http:Http,
private _route:ActivatedRoute,
private _router:Router,
private _uploadFile:UploadFileService
)
{
this.url=_GLOBAL.url;
this.errorMessage="";
this.productToInsert=new Producto("","","","");
}//end constructor
ngOnInit()
{
}
createProduct()
{
let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
let options = new RequestOptions({ headers: headers }
this._uploadFile.uploadFile(`${this.url}/upload-file`,[],this._uploadFile.filesToUpload).then(
(result)=>{
console.log(result["complete_name"]);
},
(error)=>
{
console.log(error);
}
);
//file is successfully uploaded, then I insert the product:
this._http.post(`${this.url}/crear-producto`,this.productToInsert,options).pipe(
map(
(res)=>{
console.log ("res del callback del map" + res);
return res.json();
},(err)=>{
return err;
}
)
) .subscribe(
(response)=>
{
console.log(response);
this._router.navigate(['all-products']);
},
(error)=>
{
console.log(error);
}
);
}
}
有效:文件已上传,产品已正确插入...问题是,在数据库中,我希望 result["complete_name"]
存储在图像字段中,然后我可以稍后显示图像所有产品,而不是 http.post()
字段中包含的“c:/fakepath/PICTURE.PNG”
为此,我需要捕获响应,然后将对象 productToInsert.imagen 更改为 result["complete_name"]
为此,我仅在承诺响应成功时才使用 http.post()
。因此,当上传图像时,我捕获响应结果,将其添加到作为参数传递给 post() 方法的对象,然后发送它。
import {Injectable} from '@angular/core';
import {Http, Response, Headers, RequestOptions} from '@angular/http';
import {Router, ActivatedRoute,Params} from '@angular/router';
import {map} from 'rxjs/operators';
import {_GLOBAL} from './global.service';
import {Observable} from 'rxjs';
import {Producto} from '../models/Producto.model';
import {UploadFileService} from './upload-file.service';
@Injectable()
export class CreateProductService{
public url:string;
public errorMessage:string;
public productToInsert:Producto;
public imageData:string;
constructor(
private _http:Http,
private _route:ActivatedRoute,
private _router:Router,
private _uploadFile:UploadFileService
)
{
this.url=_GLOBAL.url;
this.errorMessage="";
this.productToInsert=new Producto("","","","");
}//end constructor
ngOnInit()
{
}
createProduct()
{
let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
let options = new RequestOptions({ headers: headers });
this._uploadFile.uploadFile(`${this.url}/upload-file`,[],this._uploadFile.filesToUpload).then(
(result)=>{
console.log(result["complete_name"]);
this.productToInsert.imagen=result["complete_name"];
this._http.post(`${this.url}/crear-producto`,this.productToInsert,options).pipe(
map(
(res)=>{
return res.json();
},(err)=>{
return err;
}
)).subscribe(
(response)=>
{
console.log( response);
this._router.navigate(['all-products']);
},
(error)=>
{
console.log(+error);
}
);
},
(error)=>{
console.log(error);
}
);
}
}
但这不起作用。我收到 200 响应,但本例中的对象似乎是空的(所有字段均为空),而不是来自表单的对象。
这是使用的表格
创建产品-component.html
<form #formCreateProduct="ngForm" (ngSubmit)="_createProduct.createProduct(); formCreateProduct.reset()" class="col-lg-6" id="form-crear-producto-id">
<div class="form-group">
<label for="nombreLabel"> Name of the new product:
<span *ngIf="!nombre.valid && nombre.touched && _createProduct.productToInsert.nombre.length != 0" class="label label-danger">Minimun 3 characters please</span>
</label>
<input type="text" class="form-control" name="name" #nombre="ngModel" pattern =".{3,}"[(ngModel)]="_createProduct.productToInsert.nombre" required /> <br/>
</div>
<div class="form-group">
<label for="priceLabel">Price ( € ): (please decimals with a dot. Ex:29.5)
<span *ngIf="!precio.valid && precio.touched && _createProduct.productToInsert.precio.length != 0" class="label label-danger">Price is not valid. At least one number please, and only numbers</span>
</label>
<input type="text" class="form-control" name="price" #precio="ngModel" pattern="[0-9.]+" [(ngModel)]="_createProduct.productToInsert.precio" required /> <br/>
</div>
<div class="form-group">
<label for="imageLabel">Image:</label>
<!--file doesnt suport the ngmodel-->
<input type="file" class="form-control" name="imagen" (change)="_uploadFile.fileChangeEvent($event)" [(ngModel)]="_createProduct.productToInsert.imagen" required /> <br/>
</div>
<div class="form-group">
<label for="descriptionLabel">Description:</label>
<div [ngClass]="{'TopLength': _createProduct.productToInsert.descripcion.length==300}">{{_createProduct.productToInsert.descripcion.length}}/300</div>
<textarea name="description" class="form-control" maxlength="300" #descripcion="ngModel" [(ngModel)]="_createProduct.productToInsert.descripcion" cols="40" rows="3" ></textarea> <br/>
</div>
<input type="submit" value={{title}} [disabled]="formCreateProduct.invalid" class ="btn btn-lg btn-success" /> <br/>
</form>
我知道,因为这是我第一个使用 angular 的应用程序,所以服务和类似的东西使用起来可能有点奇怪,但我试过了:
避开服务,直接放在component.ts
只为创建组件使用一个服务service.ts,把所有方法(uploadFile、eventHandler、createProduct)放在那里,然后在组件上使用它们(我猜这实际上是正确的使用服务的方式)。
绑定“this”范围,看看箭头函数内部的范围是否有问题。
但没有任何效果。我不知道为什么单独使用时可以访问和正确使用对象和两种方法,但是我发现这种方式一起使用时会出现问题,这是老师让我们做的。
一个可能对你有用的提示是,我在某个地方遇到了一个错误(以及其他错误,哈哈),但我必须说这个错误和其他错误让我以单独的方式上传文件和创建产品没有问题,所以我打算稍后调试它们。
Uncaught (in promise): SecurityError: The operation is insecure. ./node_modules/@angular/platform-browser/fesm5/platform-browser.js/DefaultDomRenderer2.prototype.setProperty@http://localhost:4200/vendor.js:56793:9 ./node_modules/@angular/core/fesm5/core.js/DebugRenderer2.prototype.setProperty@http://localhost:4200/vendor.js:42592:9 ./node_modules/@angular/forms/fesm5/forms.js/DefaultValueAccessor.prototype.writeValue@http://localhost:4200/vendor.js:48231:9 setUpModelChangePipeline/<@http://localhost:4200/vendor.js:49205:9 ./node_modules/@angular/forms/fesm5/forms.js/FormControl.prototype.setValue/<@http://localhost:4200/vendor.js:50262:65 ./node_modules/@angular/forms/fesm5/forms.js/FormControl.prototype.setValue@http://localhost:4200/vendor.js:50262:13 ./node_modules/@angular/forms/fesm5/forms.js/NgModel.prototype._updateValue/<@http://localhost:4200/vendor.js:51617:46 ./node_modules/zone.js/dist/zone.js/</ZoneDelegate.prototype.invoke@http://localhost:4200/polyfills.js:2710:17 onInvoke@http://localhost:4200/vendor.js:35055:24 ./node_modules/zone.js/dist/zone.js/</ZoneDelegate.prototype.invoke@http://localhost:4200/polyfills.js:2709:17 ./node_modules/zone.js/dist/zone.js/</Zone.prototype.run@http://localhost:4200/polyfills.js:2460:24 scheduleResolveOrReject/<@http://localhost:4200/polyfills.js:3194:29 ./node_modules/zone.js/dist/zone.js/</ZoneDelegate.prototype.invokeTask@http://localhost:4200/polyfills.js:2743:17 onInvokeTask@http://localhost:4200/vendor.js:35046:24 ./node_modules/zone.js/dist/zone.js/</ZoneDelegate.prototype.invokeTask@http://localhost:4200/polyfills.js:2742:17 ./node_modules/zone.js/dist/zone.js/</Zone.prototype.runTask@http://localhost:4200/polyfills.js:2510:28 drainMicroTaskQueue@http://localhost:4200/polyfills.js:2917:25 ./node_modules/zone.js/dist/zone.js/</ZoneTask.invokeTask@http://localhost:4200/polyfills.js:2822:21 invokeTask@http://localhost:4200/polyfills.js:3862:9 globalZoneAwareCallback@http://localhost:4200/polyfills.js:3888:17
我解决了。这是一个虚拟的东西:
问题是,在我的组件中,从以前的版本开始,我的形式是:
<form #formCreateProduct="ngForm" (ngSubmit)="_createProduct.createProduct();formCreateProduct.reset()" class="col-lg-6" id="form-crear-producto-id">
reset() 方法在我实际发送之前将所有表单值设置为 null。删除了这个方法(在新版本上我做了一个重定向,所以我不需要它),问题就解决了。 2 天...:O
我正在开发我的第一个 CRUD 测试应用程序。
我有一个表格,其中包含典型的产品名称、价格...和一个用于上传产品的输入文件。
我为表单的更改事件创建了一个事件处理程序方法。工作正常。
我创建了这个 uploadFile() 方法,它工作正常。
上传文件-service.ts
import {Injectable, Input} from '@angular/core';
import {Http, Response, Headers, RequestOptions} from '@angular/http';
import {Router, ActivatedRoute,Params} from '@angular/router';
import {map} from 'rxjs/operators';
import {_GLOBAL} from './global.service';
import {Observable} from 'rxjs';
import {Producto} from '../models/Producto.model';
@Injectable()
export class UploadFileService
{
public url:string;
public filesToUpload:Array<File>;
constructor()
{
this.url=_GLOBAL.url;//this has the URL of the REST service
this.filesToUpload=[];
}
uploadFile(url:string, params:Array<string>,filesToUpload:Array<File>)
{
return new Promise((resolve, reject)=>{
var formData:any= new FormData();
var asyncRequest=new XMLHttpRequest();
for(var i=0; i<filesToUpload.length;++i)
{
formData.append('filesUploaded[]',filesToUpload[i],filesToUpload[i].name);
}
asyncRequest.onreadystatechange=function(){
if(asyncRequest.readyState==4){
if(asyncRequest.status==200){
resolve(JSON.parse(asyncRequest.response));
}else{
reject(asyncRequest.response);
}
}
}
asyncRequest.open('POST',url,true);
asyncRequest.send(formData);
});
}
fileChangeEvent(ElementObjectReferenceWhichTriggersEvent:any)// in this case, the input type="file"
{
this.filesToUpload=<Array<File>>ElementObjectReferenceWhichTriggersEvent.target.files;//captura los archivos mandados en el input
console.log(ElementObjectReferenceWhichTriggersEvent.target);
console.log(ElementObjectReferenceWhichTriggersEvent.target.files[0]);
console.log(this.filesToUpload);
// return this.filesToUpload;
}
}
还有这个服务
创建产品。service.ts
在这个上我有 createProduct()
方法,它从上面的服务调用 uploadFile() 方法,从 HTTP 服务调用 http.post()
。
问题是,这两种方法单独使用都很好,但一起使用就不行了。
我是说,当我在这个服务上做这个的时候:
import {Injectable} from '@angular/core';
import {Http, Response, Headers, RequestOptions} from '@angular/http';
import {Router, ActivatedRoute,Params} from '@angular/router';
import {map} from 'rxjs/operators';
import {_GLOBAL} from './global.service';
import {Observable} from 'rxjs';
import {Producto} from '../models/Producto.model';
import {UploadFileService} from './upload-file.service';
@Injectable()
export class CreateProductService{
public url:string;
public errorMessage:string;
public productToInsert:Producto;
public imageData:string;
constructor(
private _http:Http,
private _route:ActivatedRoute,
private _router:Router,
private _uploadFile:UploadFileService
)
{
this.url=_GLOBAL.url;
this.errorMessage="";
this.productToInsert=new Producto("","","","");
}//end constructor
ngOnInit()
{
}
createProduct()
{
let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
let options = new RequestOptions({ headers: headers }
this._uploadFile.uploadFile(`${this.url}/upload-file`,[],this._uploadFile.filesToUpload).then(
(result)=>{
console.log(result["complete_name"]);
},
(error)=>
{
console.log(error);
}
);
//file is successfully uploaded, then I insert the product:
this._http.post(`${this.url}/crear-producto`,this.productToInsert,options).pipe(
map(
(res)=>{
console.log ("res del callback del map" + res);
return res.json();
},(err)=>{
return err;
}
)
) .subscribe(
(response)=>
{
console.log(response);
this._router.navigate(['all-products']);
},
(error)=>
{
console.log(error);
}
);
}
}
有效:文件已上传,产品已正确插入...问题是,在数据库中,我希望 result["complete_name"]
存储在图像字段中,然后我可以稍后显示图像所有产品,而不是 http.post()
为此,我需要捕获响应,然后将对象 productToInsert.imagen 更改为 result["complete_name"]
为此,我仅在承诺响应成功时才使用 http.post()
。因此,当上传图像时,我捕获响应结果,将其添加到作为参数传递给 post() 方法的对象,然后发送它。
import {Injectable} from '@angular/core';
import {Http, Response, Headers, RequestOptions} from '@angular/http';
import {Router, ActivatedRoute,Params} from '@angular/router';
import {map} from 'rxjs/operators';
import {_GLOBAL} from './global.service';
import {Observable} from 'rxjs';
import {Producto} from '../models/Producto.model';
import {UploadFileService} from './upload-file.service';
@Injectable()
export class CreateProductService{
public url:string;
public errorMessage:string;
public productToInsert:Producto;
public imageData:string;
constructor(
private _http:Http,
private _route:ActivatedRoute,
private _router:Router,
private _uploadFile:UploadFileService
)
{
this.url=_GLOBAL.url;
this.errorMessage="";
this.productToInsert=new Producto("","","","");
}//end constructor
ngOnInit()
{
}
createProduct()
{
let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
let options = new RequestOptions({ headers: headers });
this._uploadFile.uploadFile(`${this.url}/upload-file`,[],this._uploadFile.filesToUpload).then(
(result)=>{
console.log(result["complete_name"]);
this.productToInsert.imagen=result["complete_name"];
this._http.post(`${this.url}/crear-producto`,this.productToInsert,options).pipe(
map(
(res)=>{
return res.json();
},(err)=>{
return err;
}
)).subscribe(
(response)=>
{
console.log( response);
this._router.navigate(['all-products']);
},
(error)=>
{
console.log(+error);
}
);
},
(error)=>{
console.log(error);
}
);
}
}
但这不起作用。我收到 200 响应,但本例中的对象似乎是空的(所有字段均为空),而不是来自表单的对象。
这是使用的表格
创建产品-component.html
<form #formCreateProduct="ngForm" (ngSubmit)="_createProduct.createProduct(); formCreateProduct.reset()" class="col-lg-6" id="form-crear-producto-id">
<div class="form-group">
<label for="nombreLabel"> Name of the new product:
<span *ngIf="!nombre.valid && nombre.touched && _createProduct.productToInsert.nombre.length != 0" class="label label-danger">Minimun 3 characters please</span>
</label>
<input type="text" class="form-control" name="name" #nombre="ngModel" pattern =".{3,}"[(ngModel)]="_createProduct.productToInsert.nombre" required /> <br/>
</div>
<div class="form-group">
<label for="priceLabel">Price ( € ): (please decimals with a dot. Ex:29.5)
<span *ngIf="!precio.valid && precio.touched && _createProduct.productToInsert.precio.length != 0" class="label label-danger">Price is not valid. At least one number please, and only numbers</span>
</label>
<input type="text" class="form-control" name="price" #precio="ngModel" pattern="[0-9.]+" [(ngModel)]="_createProduct.productToInsert.precio" required /> <br/>
</div>
<div class="form-group">
<label for="imageLabel">Image:</label>
<!--file doesnt suport the ngmodel-->
<input type="file" class="form-control" name="imagen" (change)="_uploadFile.fileChangeEvent($event)" [(ngModel)]="_createProduct.productToInsert.imagen" required /> <br/>
</div>
<div class="form-group">
<label for="descriptionLabel">Description:</label>
<div [ngClass]="{'TopLength': _createProduct.productToInsert.descripcion.length==300}">{{_createProduct.productToInsert.descripcion.length}}/300</div>
<textarea name="description" class="form-control" maxlength="300" #descripcion="ngModel" [(ngModel)]="_createProduct.productToInsert.descripcion" cols="40" rows="3" ></textarea> <br/>
</div>
<input type="submit" value={{title}} [disabled]="formCreateProduct.invalid" class ="btn btn-lg btn-success" /> <br/>
</form>
我知道,因为这是我第一个使用 angular 的应用程序,所以服务和类似的东西使用起来可能有点奇怪,但我试过了:
避开服务,直接放在component.ts
只为创建组件使用一个服务service.ts,把所有方法(uploadFile、eventHandler、createProduct)放在那里,然后在组件上使用它们(我猜这实际上是正确的使用服务的方式)。
绑定“this”范围,看看箭头函数内部的范围是否有问题。
但没有任何效果。我不知道为什么单独使用时可以访问和正确使用对象和两种方法,但是我发现这种方式一起使用时会出现问题,这是老师让我们做的。
一个可能对你有用的提示是,我在某个地方遇到了一个错误(以及其他错误,哈哈),但我必须说这个错误和其他错误让我以单独的方式上传文件和创建产品没有问题,所以我打算稍后调试它们。
Uncaught (in promise): SecurityError: The operation is insecure. ./node_modules/@angular/platform-browser/fesm5/platform-browser.js/DefaultDomRenderer2.prototype.setProperty@http://localhost:4200/vendor.js:56793:9 ./node_modules/@angular/core/fesm5/core.js/DebugRenderer2.prototype.setProperty@http://localhost:4200/vendor.js:42592:9 ./node_modules/@angular/forms/fesm5/forms.js/DefaultValueAccessor.prototype.writeValue@http://localhost:4200/vendor.js:48231:9 setUpModelChangePipeline/<@http://localhost:4200/vendor.js:49205:9 ./node_modules/@angular/forms/fesm5/forms.js/FormControl.prototype.setValue/<@http://localhost:4200/vendor.js:50262:65 ./node_modules/@angular/forms/fesm5/forms.js/FormControl.prototype.setValue@http://localhost:4200/vendor.js:50262:13 ./node_modules/@angular/forms/fesm5/forms.js/NgModel.prototype._updateValue/<@http://localhost:4200/vendor.js:51617:46 ./node_modules/zone.js/dist/zone.js/</ZoneDelegate.prototype.invoke@http://localhost:4200/polyfills.js:2710:17 onInvoke@http://localhost:4200/vendor.js:35055:24 ./node_modules/zone.js/dist/zone.js/</ZoneDelegate.prototype.invoke@http://localhost:4200/polyfills.js:2709:17 ./node_modules/zone.js/dist/zone.js/</Zone.prototype.run@http://localhost:4200/polyfills.js:2460:24 scheduleResolveOrReject/<@http://localhost:4200/polyfills.js:3194:29 ./node_modules/zone.js/dist/zone.js/</ZoneDelegate.prototype.invokeTask@http://localhost:4200/polyfills.js:2743:17 onInvokeTask@http://localhost:4200/vendor.js:35046:24 ./node_modules/zone.js/dist/zone.js/</ZoneDelegate.prototype.invokeTask@http://localhost:4200/polyfills.js:2742:17 ./node_modules/zone.js/dist/zone.js/</Zone.prototype.runTask@http://localhost:4200/polyfills.js:2510:28 drainMicroTaskQueue@http://localhost:4200/polyfills.js:2917:25 ./node_modules/zone.js/dist/zone.js/</ZoneTask.invokeTask@http://localhost:4200/polyfills.js:2822:21 invokeTask@http://localhost:4200/polyfills.js:3862:9 globalZoneAwareCallback@http://localhost:4200/polyfills.js:3888:17
我解决了。这是一个虚拟的东西:
问题是,在我的组件中,从以前的版本开始,我的形式是:
<form #formCreateProduct="ngForm" (ngSubmit)="_createProduct.createProduct();formCreateProduct.reset()" class="col-lg-6" id="form-crear-producto-id">
reset() 方法在我实际发送之前将所有表单值设置为 null。删除了这个方法(在新版本上我做了一个重定向,所以我不需要它),问题就解决了。 2 天...:O