insert product and upload file work separately but not together in Angular 6

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP

insert product and upload file work separately but not together in Angular 6



I am developing my first CRUD test app.



I have a form with typical product name, price... and an input file to upload the product.



I created an event handler method for the change event of the form. Works fine.



I created this uploadFile() method, which works fine.



upload-file-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;





And this service



create-product.service.ts



On this one I have the createProduct() method, which calls the uploadFile() method from the service above and the http.post() from the HTTP service.


createProduct()


http.post()



Problem is, both methods work fine separately, but not together.



I mean, when I make this on this service:


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);



);








It works: file is uploaded and product is correctly inserted... Problem is, on database I want the result["complete_name"] to be stored on the image field, then I can show the image later when I get all the products, instead of the "c:/fakepath/PICTURE.PNG" included on the field by the http.post()


result["complete_name"]


http.post()



For that, I need to capture the response and then change the object productToInsert.imagen with the result["complete_name"]


result["complete_name"]



To do that, I used the http.post() only when the promise response was successful. So, when the image is uploaded, I capture the response result, add it to the object passed as parameter on the post() method, and send it.


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"]);
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);



);





But that doesn´t work. I get a 200 response, but the object in this case seems to be empty (null on all fields), instead of the ones coming from the form.



Here is the form used



create-product-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>



I know, since it is my first app with angular, services and such things are maybe a bit weird used, but I tried:



to avoid services and put them directly in component.ts



Use only a service for create-component-service.ts, put there all methods (uploadFile, eventHandler, createProduct), and using them on component (which I guess is actually the correct way of using the service).



to bind the "this" scope to see if there could be any problem with the scope inside the arrow function.



But nothing works. I don´t know why I can access and correctly use the object and both methods when I use them separately, but I find this problem when using this way together, which is what the teacher told us to do.



In case you need it, I have a github with the backend and the complete angular project, so you can clone them and check them if you want:



https://github.com/Franweb79/SAP-webapp-Angular/tree/forma-victor-front



And this is backend:



https://github.com/Franweb79/PHP-API-REST/tree/forma-victor



A tip that maybe useful for you, is that somewhere I get an error (among others lol), but I must say this error and the others give me no problem to upload File and createproduct on a separate way, so I planned to debug them later.


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









By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Comments

Popular posts from this blog

Executable numpy error

PySpark count values by condition

Trying to Print Gridster Items to PDF without overlapping contents