File upload in Angular5 - html

I am trying to upload one or more than one files in my web application.
I have tried with the code and error arising from vData.service.ts file
Error: property 'yoursHeadersConfig' does not exist on VDataservice
property 'catchError' does not exist on 'observable'
property 'HandleError' does not exist on 'VDataservice'
Can you let me know how to resolve the issue and provide an idea for multiple file upload in the web application? I have provided entire relevant code for the issue.
Gist links:
ad.component.html: https://gist.github.com/aarivalagan/ac15e8e2c6f77d0687c01a70e18bca6b
ad:component.ts: https://gist.github.com/aarivalagan/a9c1d22c1d6056da624f0968fb6cd59c
vData.service.ts: https://gist.github.com/aarivalagan/8bfbe47ef8cf0dac267374a8f0ef5b0f
code:
ad.component.html
<div class="form-group col-sm-12">
<label for="usr">Choose file to Upload </label>
<input type="file" multiple formControlName="file" class="form-control" id="file" (change)="handleFileInput($event.target.files)" accept=".pdf,.docx" required>
</div>
ad.component.ts
handleFileInput(files: FileList) {
this.fileToUpload = files.item(0);
}
uploadFileToActivity() {
this.fileUploadService.postFile(this.fileToUpload).subscribe(data => {
// do something, if upload success
}, error => {
console.log(error);
});
}
vData.service.ts
postFile(fileToUpload: File): Observable<boolean> {
const endpoint = 'your-destination-url';
const formData: FormData = new FormData();
formData.append('fileKey', fileToUpload, fileToUpload.name);
return this.http
.post(endpoint, formData, { headers: this.yourHeadersConfig })
.map(() => { return true; })
.catchError((e) => this.handleError(e));
}

For catchError use pipe operator
property 'catchError' does not exist on 'observable'
postFile(fileToUpload: File): Observable<boolean> {
const endpoint = 'your-destination-url';
const formData: FormData = new FormData();
formData.append('fileKey', fileToUpload, fileToUpload.name);
return this.http
.post(endpoint, formData, { headers: this.yourHeadersConfig })
.pipe(map(() => { return true; }),
catchError((e) => this.handleError(e)));
}
Error: property 'yoursHeadersConfig' does not exist on VDataservice
property 'HandleError' does not exist on 'VDataservice'
You havent defined these properties in VDataservice, so you can't call those methods using this.
You can try adding below method into VDataservice file:
HandleError(error){
// write your logic to handle error here
}

Related

Angular: Re-render asynchronous data in image tag

I am using Angular to fetch user profile picture from backend(Node.js/Express). Everything is working perfectly except for one thing. The Angular does not re-render the HTML that displays the profile picture incase, the user has updated his picture or if no picture is present and user uploads his first image. As expected, the Angular is rendering the HTML only once and isn't re-rendering again. I don't know how can I wait for asynchronous data in HTML as I am directly targeting an endpoint in HTML instead of TS.
Here's my code:
userProfile.component.html
<div class = "imgClass">
<img class = "img-thumbnail rounded-circle imgclass"
src="http://localhost:3000/api/getProfilePhoto?id={{cookieData}}">
//angular is sending request to the above endpoint to fetch the image only once at the time
application starts or user logs in. How can I send a request again?
<div class="middle">
<div class="text"><button type="button" name="button" (click) = "selectImage()" class = "btn
btn-outline-primary"> <i class="bi bi-plus"></i> </button></div>
<input type="file" id="imgUpload" (change) = "handleImageInput($event.target.files)">
</div>
</div>
userProfile.component.ts
selectImage()
{
document.getElementById('imgUpload').click();
}
handleImageInput(files: FileList)
{
this.imageUpload = files.item(0);
this.uploadImage();
}
uploadImage()
{
const formData = new FormData();
const params = new HttpParams().set('id', sessionStorage.getItem('cookie'));
formData.append("file", this.imageUpload, this.imageUpload.name);
this.http.post('http://localhost:3000/api/updateImage', formData, {params, responseType: "text"})
.subscribe(responseData => {
this.imageChanged = true; //I have tried using this as *ngIf in HTML but it is not working either
}
,error => {
console.log("Image uploading failed" + error.message);
})
}
Does anybody know how can I send the request to an endpoint in HTML once user changes/uploads his first picture?
You need to trigger the image fetch request for each update/upload requests. Or you could adjust the backend to return the image data from the update/upload requests.
Option 1: manually fetch image for each update/upload requests
Use RxJS switchMap operator to switch to image fetch request after the uploading has completed. It'll not be fetched if the uploading failed.
profileImage: any;
selectImage() {
document.getElementById('imgUpload').click();
}
handleImageInput(files: FileList) {
this.imageUpload = files.item(0);
this.uploadImage();
}
uploadImage() {
const formData = new FormData();
const params = new HttpParams().set('id', sessionStorage.getItem('cookie'));
formData.append("file", this.imageUpload, this.imageUpload.name);
this.http.post('http://localhost:3000/api/updateImage', formData, {
params,
responseType: "text"
}).pipe(
tap(null, error => console.log("Image uploading failed" + error.message)),
switchMap(_ => this.http.get(`http://localhost:3000/api/getProfilePhoto?id${this.cookieData}`))
).subscribe(
image => {
this.profileImage = image;
},
error => {
console.log("Image fetching failed" + error.message);
}
);
}
<img class="img-thumbnail rounded-circle imgclass" [src]="profileImage">
Option 2: Return the image from upload/update request
Adjust the backend to return the image data from the Upload POST request.
profileImage: any;
uploadImage() {
const formData = new FormData();
const params = new HttpParams().set('id', sessionStorage.getItem('cookie'));
formData.append("file", this.imageUpload, this.imageUpload.name);
this.http.post('http://localhost:3000/api/updateImage', formData, {
params,
responseType: "text"
}).subscribe(
image => {
this.profileImage = image;
},
error => {
console.log("Image uploading failed" + error.message);
}
);
}
<img class="img-thumbnail rounded-circle imgclass" [src]="profileImage">
As a sidenote, using document.getElementById() in Angular will search the whole DOM, not just the individual component. In relatively complex apps, it might lead to performance issues. Instead try to use an event handler or if it's not possible, use Angular ViewChild with a template reference parameter to get an element from the current component's DOM.
if the webservice resolving the image url returns an Observable, you can make the call from typescript like below
imageData$: Observable<number>;
getImage(id): Observable<string> {
this.imageData$=http.get(url?id=<some_id>);
return this.imageData$
}
and the adding async pipe on it
<img class = "img-thumbnail rounded-circle imgclass" [src]="imageData$ | async">
Basically The async pipe subscribes to an Observable or Promise and
returns the latest value it has emitted. When a new value is emitted,
the async pipe marks the component to be checked for changes. When the
component gets destroyed, the async pipe unsubscribes automatically to
avoid potential memory leaks.

React setState cannot assign fileList instead assigns string of first fileName

To begin with, I'm making a simple social media application. I'm trying to submit a form which has text, images, and videos. My frontend where the form is submitted is made with React and server is ran with node.js mounted on nginx. I was trying to append the inputted files into FormData with code below:
handleSubmit = function (e) {
e.preventDefault();
const formData = new FormData();
formData.append("textBody", this.state.textBody)
for (let i = 0; i < this.state.imgInput.length; i++) {
formData.append("imgInput", this.state.imgInput.files[i], "img"+i.toString())
fetch("mywebsite.com/api/submitArticle", {
body: formData,
method: "POST",
credentials: 'include',
}).then((response) => console.log(response))
return false;
}.bind(this)
handleChange = function (e) {
e.preventDefault();
if (e.target.name === 'imgInput') {
this.setState({
imgInput: e.target.files,
showSpan: false
})
}
}.bind(this)
<form onSubmit={this.handleSubmit}>
<textarea id='textBody' name='textBody' onFocus={removeSpan} onBlur={checkSpanOn} onChange={this.handleChange}/>
<input type="file" id="imgInput" name="imgInput" accept="image/*" ref={this.imgRef} multiple={true} onChange={this.handleChange}/>
<input type="submit" id="submitButton" name="submitButton" formEncType="multipart/form-data" />
</form>
But React gave me this error upon submitting the form:
TypeError: Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'.
at "formData.append("imgInput", this.state.imgInput.files[i], "img"+i.toString())".
So when I console logged what e.target.files before setState in handleChange, I got normal FileList with all the image files listed. But when I console loggedd this.state.imgInput after setState in handleChange, I got String of C://fakepath/filename, not fileList. (Initially state.imgInput was null. When I saw other examples and codes, e.target.files was fileList so I'm puzzled elsewhere I made mistake.
I was spending half my day on this problem and I'm 5 sec before fainting so any advice would be appreciated :) Thank you for reading.
yes this happening because the event is gone you need to store the event.target in variable + the files will be in imgInput not imgInput.files so here it is:
handleSubmit = e => {
e.preventDefault();
const formData = new FormData();
formData.append("textBody", this.state.textBody);
for (let i = 0; i < this.state.imgInput.length; i++) {
formData.append("imgInput", this.state.imgInput[i], "img" + i.toString());
fetch("mywebsite.com/api/submitArticle", {
body: formData,
method: "POST",
credentials: "include"
}).then(response => console.log(response));
}
};
handleChange = e => {
e.preventDefault();
const target = e.target;
if (target.name === "imgInput") {
this.setState(current => ({
...current,
imgInput: target.files,
showSpan: false
}));
}
};

How to upload PDF file to server using angular 6

I generate HTML content to export PDF file using JsPDF library. Now, i need how to pass exported PDF file to server using angular 6. Thanks in advance
Here is my way to do it.
//HTML code
<input type="file" name="File Upload" id="txtFileUpload" accept=".csv"
(change)="changeListener($event)" />
//Component.ts
You have to import StaffService here:
changeListener($event: any) {
this.data = $event.target.files;
this.postFile(this.data);
}
postFile(inputValue: any): void {
this.file = inputValue[0];
this.staffService.uploadCSV(this.file).subscribe(response => {
//Do your next redirection or operation here
}, error =>{});
}
//StaffService.ts
public uploadCSV(file): Observable<any> {
const formdata = new FormData();
formdata.append('files', file);
return this.http.post(environment.apiUrlIp + this.urls.uploadCSVUrl, formdata, {
reportProgress: true,
responseType: 'json'
});
}
Let me know if you find any issue to integrate this code. Happy to help.

Posting a json data to my database with axios (using my backend api)

I have a very strange issue. I've got a backend api to import a json data to my mongodb.
On the screen I have a upload button to upload a file and I used react-dropzone for that. For example think that I have a file like "db.json" and in this file there is a json like as follows
{
"datapointtypes":[
{"id":"Wall plug","features":[{"providesRequires":"provides","id":"Binary switch"},{"providesRequires":"requires","id":"Binary sensor","min":"1","max":"2"}],"parameters":[{"id":"Communication type","type":"Communication type"}],"functions":[{"id":"Electricity"},{"id":"Switch"}]},
{"id":"Door sensor","features":[{"providesRequires":"provides","id":"Binary sensor"}],"parameters":[{"id":"Communication type","type":"Communication type"}],"functions":[{"id":"Door"},{"id":"Sensor"}]}
],
"datatypes":[
{"id":"Communication type","type":"enum","values":[{"id":"Zwave"},{"id":"Zigbee"}]},
{"id":"Zigbee network address","type":"decimal","min":1,"max":65336,"res":1},
{"id":"Serial port","type":"string"}
],
"features":[
{"id":"Zwave receiver","exposedtype":"Zwave command","functions":[{"id":"Communication"}]},
{"id":"Zigbee receiver","exposedtype":"Zigbee command","functions":[{"id":"Communication"}]},
{"id":"Binary switch","exposedtype":"On off state","functions":[{"id":"Actuator"}]},
{"id":"Binary sensor","exposedtype":"On off state","functions":[{"id":"Sensor"}]}
],
"servicetypes":[
{"id":"Room controller","datapointtype":"Room controller","DelayActive":false,"DelayValue":""},
{"id":"Xiaomi door sensor","datapointtype":"Door sensor","parameters":[{"id":"Zigbee network address","type":"Zigbee network address"},{"id":"Zigbee node id","type":"Zigbee node id"}],"parametervalues":[{"id":"Communication type","value":"Zigbee"}]}
],
"systems":[
{"id":"system 2","services":[{"serviceType":"Room controller","id":"servis 1"}],"serviceRelations":[{"serviceName":"servis 1","featureName":"Binary sensor"}],"parametervalues":[{"id":"Delay","paramName":"Delay","serviceType":"Room controller","value":"binary"}]},
{"id":"system 3","services":[{"serviceType":"Room controller","id":"servis 1"}],"serviceRelations":[{"serviceName":"servis 1","featureName":"Binary sensor"}],"katid":"7"}
]
}
The problem is this. If the browser console is open then my code is running succesfully and I can import the json data to my mongodb. But if browser console is closed I'm getting the "SyntaxError: Unexpected end of JSON input" error.
This is the function that I'm using on the import button
class FileUpload extends Component {
state = {
warning: ""
}
uploadFile = (files, rejectedFiles) => {
files.forEach(file => {
const reader = new FileReader();
reader.readAsBinaryString(file);
let fileContent = reader.result;
axios.post('http://localhost:3001/backendUrl', JSON.parse(fileContent),
{
headers: {
"Content-Type": "application/json"
}
})
.then(response => {
this.setState({warning: "Succeed"})
})
.catch(err => {
console.log(err)
});
});
}
render() {
return (
<div>
<Dropzone className="ignore" onDrop={this.uploadFile}>{this.props.children}
</Dropzone>
{this.state.warning ? <label style={{color: 'red'}}>{this.state.warning}</label> : null}
</div>
)
}
}
What is that I am doing something wrong or what causes this?
Can you help me?
Thank you
FileReader reads files asynchronously so you have to use a callback to access the results
I would use readAsText instead of readAsBinaryString in case there are non ascii characters in the JSON
Finally, JSON.parse converts a JSON string to an object(or whatever type it would be). fileContent is already JSON so leave it as is.
const reader = new FileReader();
reader.onlooad = (e) => {
let fileContent = this.result;
axios.post('http://localhost:3001/backendUrl', fileContent,
{
headers: {
"Content-Type": "application/json"
}
})
.then(response => {
this.setState({warning: "Succeed"})
})
.catch(err => {
console.log(err)
});
}
reader.readAsText(file);

error in uploading the image from angular to nodejs

My Html file is -
<form method="post" [formGroup]="orderForm" enctype="multipart/form-data" (ngSubmit)="OnSubmit(orderForm.value)" >
<div class="form-group">
<label for="image">Select Branch Image</label>
<input type="file" formControlName="branchImg" (change)="onFileChange($event)" class="form-control-file" id="image">
</div>
</form>
and my .ts file is -
public orderForm: FormGroup;
onFileChange(event) {
const reader = new FileReader();
if (event.target.files && event.target.files.length) {
const [file] = event.target.files;
reader.readAsDataURL(file);
reader.onload = () => {
this.orderForm.patchValue({
branchImg: reader.result
});
};
}
}
ngOnInit() {
this.orderForm = this.formBuilder.group({
branchImg: [null, Validators.required]
});
}
and then submit the form.
I am supposed to get the image address and the upload that address in cloudinary
But when I am consoling the body in my nodejs app
it gives something like this-
branchImg: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/7QCEUGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAGccAigAYkZCTUQwMTAwMGE4MjBkMDAwMD and so on.
I don't think that it is the images address. Can anyone tell me that what is this? and how to get that image's address which I will upload to cloudinary
As the Eric suggest -
my app.js code is
router.post('/branch',(req,res) =>{
const body = req.body;
const base64Data = body.branchImg.replace(/^data:image\/png;base64,/, "");
console.log(base64Data);
fs.writeFile("out.jpg", base64Data, 'base64', function(err,result) {
console.log(result);
});
});
it gives result as undefined
That basically is a base64 encoding of the image data. What you need to do after you get that is write that to a file, and then upload it to cloudinary
//this will write the base64 data as a jpg file to your local disk
require("fs").writeFile("out.jpg", base64Data, 'base64', function(err) {
//after you write it to disk, use the callback space here to upload said file
//to your cloudinary endpoint
});