Using angular 4 to send form-data - forms

Hi I'm building a WordPress theme and I need to use contact form 7 plugin on it, but I can't figure out the correct way to send the form data to the plugin.
here is my post service:
import {
Injectable
} from '#angular/core';
import {
HttpClient,
HttpHeaders
} from '#angular/common/http';
#Injectable()
export class FormsService {
constructor(private http: HttpClient) {}
postForm(url, form) {
return this.http.post(url, form, {
headers: new HttpHeaders().set('Content-Type', 'multipart/form-data'),
})
}
}
and the component part that use the service:
onSubmit() {
const fd = new FormData();
fd.append('your-name', this.name);
fd.append('your-email', this.email);
fd.append('your-message', this.message);
fd.append('your-subject', this.sumbject);
const url = `/wp-json/contact-form-7/v1/contact-forms/${this.form_id}/feedback`;
this.sendMsg.postForm(url, fd).subscribe(
data => {
console.log(data);
},
err => console.log({
error: err
})
)
this.submitted = true;
}
At this point the server response that the message was submitted ok, but when I go to the WP admin page, non of the field get the values.
But If I use postman with this url and params the form all works as I want.
I also found another solution that works but its not the angular way as I want to be.
the solution
onSubmit() {
const url = `/wp-json/contact-form-7/v1/contact-forms/${this.form_id}/feedback`;
this.submitted = true;
}
sendData(url) {
let XHR = new XMLHttpRequest();
const FD = new FormData();
FD.append('your-name', this.name);
FD.append('your-email', this.email);
FD.append('your-message', this.message);
FD.append('your-subject', this.subject);
// Define what happens on successful data submission
XHR.addEventListener('load', function(event) {
alert('Yeah! Data sent and response loaded.');
});
// Define what happens in case of error
XHR.addEventListener('error', function(event) {
alert('Oups! Something went wrong.');
});
// Set up our request
XHR.open('POST', url);
// Send our FormData object; HTTP headers are set automatically
XHR.send(FD);
}

I found my solution, the problem was on the headers definitions of my service, the correct way is:
postForm(url, body) {
var headers = new HttpHeaders();
headers.append('Content-Type', 'application/form-data');
return this.http.post(url, body, {headers: headers })
}

Related

How to Pass Form Data in Post Request using ionic-native-http in capacitor?

I have used a Validation Form to take the input from users and I have a submit button on which submit() function is being called.
insertuserdata() is a function in service.ts file where api is being called. I am passing form data in the api. File(e.g pdf,doc,docx etc.) can also be passed to the api as multi part form data.
But I am using Ionic-Native-Http to pass multi part form data using capacitor.
I am getting the error as status 415.Please help with this.
submit()
{
this.isSubmitted = true;
if (!this.ionicForm.valid) {
console.log('Please provide all the required values!')
return false;
} else {
console.log(this.ionicForm.value)
}
console.log("this is deptid", this.deptid)
console.log("this is description", this.ionicForm.controls["description"].value)
console.log("this is cid", this.ionicForm.controls["subquery"].value)
console.log("this is location", this.ionicForm.controls["location"].value)
console.log("query",this.ionicForm.controls["query"].value)
console.log("Insert Form Data")
const formData = new FormData();
formData.append('postedby', this.employeeId);
formData.append('description', this.ionicForm.controls["description"].value);
formData.append('location', this.ionicForm.controls["location"].value);
formData.append('deptid', this.deptid);
formData.append('cid', this.ionicForm.controls["subquery"].value);
formData.append('file', this.ionicForm.get('profile').value);
console.log("Insert Api call")
this.c2s.insertuserdata(formData).then((insertdata: any) =>{
console.log("Insert Response",insertdata)
})
insertuserdata(formData) {
let httpOptions = {
headers: new HttpHeaders({
'enctype': 'multipart/form-data;',
'Content-Type': 'application/json'
})
};
this.insert = this.http1.post("https://webapplnapp.tatapower.com/tpc_restfull_service/api/connecttosolve/postQuery", formData, httpOptions);
return this.insert
}

Angular 6 Downloading file from rest api

I have my REST API where I put my pdf file, now I want my angular app to download it on click via my web browser but I got HttpErrorResponse
"Unexpected token % in JSON at position 0"
"SyntaxError: Unexpected token % in JSON at position 0↵ at JSON.parse (
this is my endpoint
#GetMapping("/help/pdf2")
public ResponseEntity<InputStreamResource> getPdf2(){
Resource resource = new ClassPathResource("/pdf-sample.pdf");
long r = 0;
InputStream is=null;
try {
is = resource.getInputStream();
r = resource.contentLength();
} catch (IOException e) {
e.printStackTrace();
}
return ResponseEntity.ok().contentLength(r)
.contentType(MediaType.parseMediaType("application/pdf"))
.body(new InputStreamResource(is));
}
this is my service
getPdf() {
this.authKey = localStorage.getItem('jwt_token');
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/pdf',
'Authorization' : this.authKey,
responseType : 'blob',
Accept : 'application/pdf',
observe : 'response'
})
};
return this.http
.get("http://localhost:9989/api/download/help/pdf2", httpOptions);
}
and invocation
this.downloadService.getPdf()
.subscribe((resultBlob: Blob) => {
var downloadURL = URL.createObjectURL(resultBlob);
window.open(downloadURL);});
I resolved it as follows:
// header.component.ts
this.downloadService.getPdf().subscribe((data) => {
this.blob = new Blob([data], {type: 'application/pdf'});
var downloadURL = window.URL.createObjectURL(data);
var link = document.createElement('a');
link.href = downloadURL;
link.download = "help.pdf";
link.click();
});
//download.service.ts
getPdf() {
const httpOptions = {
responseType: 'blob' as 'json')
};
return this.http.get(`${this.BASE_URL}/help/pdf`, httpOptions);
}
I solved the issue in this way (please note that I have merged multiple solutions found on stack overflow, but I cannot find the references. Feel free to add them in the comments).
In My service I have:
public getPDF(): Observable<Blob> {
//const options = { responseType: 'blob' }; there is no use of this
let uri = '/my/uri';
// this.http refers to HttpClient. Note here that you cannot use the generic get<Blob> as it does not compile: instead you "choose" the appropriate API in this way.
return this.http.get(uri, { responseType: 'blob' });
}
In the component, I have (this is the part merged from multiple answers):
public showPDF(fileName: string): void {
this.myService.getPDF()
.subscribe(x => {
// It is necessary to create a new blob object with mime-type explicitly set
// otherwise only Chrome works like it should
var newBlob = new Blob([x], { type: "application/pdf" });
// IE doesn't allow using a blob object directly as link href
// instead it is necessary to use msSaveOrOpenBlob
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(newBlob, fileName);
return;
}
// For other browsers:
// Create a link pointing to the ObjectURL containing the blob.
const data = window.URL.createObjectURL(newBlob);
var link = document.createElement('a');
link.href = data;
link.download = fileName;
// this is necessary as link.click() does not work on the latest firefox
link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
setTimeout(function () {
// For Firefox it is necessary to delay revoking the ObjectURL
window.URL.revokeObjectURL(data);
link.remove();
}, 100);
});
}
The code above works in IE, Edge, Chrome and Firefox. However, I don't really like it, as my component is pulluted with browser specific stuff which will surely change over time.
For Angular 12+, I came up with something like this:
this.ApiService
.getFileFromApi()
.pipe(take(1))
.subscribe((response) => {
const downloadLink = document.createElement('a');
downloadLink.href = URL.createObjectURL(new Blob([response.body], { type: response.body.type }));
const contentDisposition = response.headers.get('content-disposition');
const fileName = contentDisposition.split(';')[1].split('filename')[1].split('=')[1].trim();
downloadLink.download = fileName;
downloadLink.click();
});
The subscribe is on a simple get() with the Angular HttpClient.
// api-service.ts
getFileFromApi(url: string): Observable<HttpResponse<Blob>> {
return this.httpClient.get<Blob>(this.baseApiUrl + url, { observe: 'response', responseType: 'blob' as 'json'});
}
You can do it with angular directives:
#Directive({
selector: '[downloadInvoice]',
exportAs: 'downloadInvoice',
})
export class DownloadInvoiceDirective implements OnDestroy {
#Input() orderNumber: string;
private destroy$: Subject<void> = new Subject<void>();
_loading = false;
constructor(private ref: ElementRef, private api: Api) {}
#HostListener('click')
onClick(): void {
this._loading = true;
this.api.downloadInvoice(this.orderNumber)
.pipe(
takeUntil(this.destroy$),
map(response => new Blob([response], { type: 'application/pdf' })),
)
.subscribe((pdf: Blob) => {
this.ref.nativeElement.href = window.URL.createObjectURL(pdf);
this.ref.nativeElement.click();
});
}
// your loading custom class
#HostBinding('class.btn-loading') get loading() {
return this._loading;
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
}
In the template:
<a
downloadInvoice
[orderNumber]="order.number"
class="btn-show-invoice"
>
Show invoice
</a>
My answer is based on #Yennefer's, but I wanted to use the file name from the server since I didn't have it in my FE. I used the Content-Disposition header to transmit this, since that is what the browser uses for a direct download.
First, I needed access to the headers from the request (notice the get method options object):
public getFile(): Observable<HttpResponse<Blob>> {
let uri = '/my/uri';
return this.http.get(uri, { responseType: 'blob', observe: 'response' });
}
Next, I needed to extract the file name from the header.
public getFileName(res: HttpResponse<any>): string {
const disposition = res.headers.get('Content-Disposition');
if (!disposition) {
// either the disposition was not sent, or is not accessible
// (see CORS Access-Control-Expose-Headers)
return null;
}
const utf8FilenameRegex = /filename\*=UTF-8''([\w%\-\.]+)(?:; |$)/;
const asciiFilenameRegex = /filename=(["'])(.*?[^\\])\1(?:; |$)/;
let fileName: string = null;
if (utf8FilenameRegex.test(disposition)) {
fileName = decodeURIComponent(utf8FilenameRegex.exec(disposition)[1]);
} else {
const matches = asciiFilenameRegex.exec(disposition);
if (matches != null && matches[2]) {
fileName = matches[2];
}
}
return fileName;
}
This method checks for both ascii and utf-8 encoded file names, prefering utf-8.
Once I have the file name, I can update the download property of the link object (in #Yennifer's answer, that's the lines link.download = 'FileName.ext' and window.navigator.msSaveOrOpenBlob(newBlob, 'FileName.ext');)
A couple of notes on this code:
Content-Disposition is not in the default CORS whitelist, so it may not be accessible from the response object based on the your server's configuration. If this is the case, in the response server, set the header Access-Control-Expose-Headers to include Content-Disposition.
Some browsers will further clean up file names. My version of chrome seems to replace : and " with underscores. I'm sure there are others but that's out of scope.
//Step: 1
//Base Service
this.getPDF() {
return this.http.get(environment.baseUrl + apiUrl, {
responseType: 'blob',
headers: new HttpHeaders({
'Access-Control-Allow-Origin': '*',
'Authorization': localStorage.getItem('AccessToken') || ''
})
});
}
//Step: 2
//downloadService
getReceipt() {
return new Promise((resolve, reject) => {
try {
// {
const apiName = 'js/getReceipt/type/10/id/2';
this.getPDF(apiName).subscribe((data) => {
if (data !== null && data !== undefined) {
resolve(data);
} else {
reject();
}
}, (error) => {
console.log('ERROR STATUS', error.status);
reject(error);
});
} catch (error) {
reject(error);
}
});
}
//Step 3:
//Component
getReceipt().subscribe((respect: any) => {
var downloadURL = window.URL.createObjectURL(data);
var link = document.createElement(‘a’);
link.href = downloadURL;
link.download = “sample.pdf";
link.click();
});
This also works in IE and Chrome, almost the same answer only for other browsers the answer is a bit shorter.
getPdf(url: string): void {
this.invoiceService.getPdf(url).subscribe(response => {
// It is necessary to create a new blob object with mime-type explicitly set
// otherwise only Chrome works like it should
const newBlob = new Blob([(response)], { type: 'application/pdf' });
// IE doesn't allow using a blob object directly as link href
// instead it is necessary to use msSaveOrOpenBlob
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(newBlob);
return;
}
// For other browsers:
// Create a link pointing to the ObjectURL containing the blob.
const downloadURL = URL.createObjectURL(newBlob);
window.open(downloadURL);
});
}

Passport-jwt issue : JWT token is working with postman but not working with UI api call

I have integrated passport-jwt for authentication purpose. It's working like charm but whenever Frontend guy use it from frontend angular 2 its giving Unauthorised 401 . I've tried alot but not getting any clue, it must be a silly mistake though.
my passport strategy file is as
let JwtStrategy = require('passport-jwt').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt;
//let fromHeader = require('passport-jwt').fromHeader
// load up the user model
const User = require('../components/user/model');
const database = require('./database'); // get db config file
const config = require('./config'); // get db config file
module.exports = function(passport) {
//var passportStrategy = function(passport){
let opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeader();
//opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme("JWT");
console.log("opts.jwtFromRequest==",opts.jwtFromRequest);
opts.secretOrKey = config.secret;//config.secret;
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
//console.log("opt==",JSON.stringify(opt));
//console.log("jwt_payload===",jwt_payload);
User.findOne({_id: jwt_payload._doc._id}, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
done(null, user);
} else {
done(null, false);
}
});
}));
};
my route is as
app.get("/api/user/getAll",
passport.authenticate('jwt',{session:false}),
userController.fetchUsers
);
And frontend header append is as follows :
logoutUser(token) {
//const userData = JSON.stringify(userInfo);
var headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Authorization', token); //e.g.token = JWT dasddddasdsda
//headers.append('Authentication', token);
console.log(headers)
return this.http.post('http://localhost:9000/api/user/logout', { headers: headers })
.map((response: Response) =〉 {
return response.json()
})
.catch(this.errorHandler);
}
It would really great if anyone can assist me further to identify the mistake.
Second argument for the post method is payload.
so this code below
this.http.post('http://localhost:9000/api/user/logout', { headers: headers })
has to be
this.http.post('http://localhost:9000/api/user/logout', {}, { headers: headers })

make REST call with typescript

I installed the "sb admin 2" dashboard with html5/angular2.
This sample works with typescript. To instanciate charts, the file charts.compenent.ts defines the class and then defines the charts attributes and data as follows
import { Component, OnInit} from '#angular/core';
#Component({
moduleId: module.id,
selector: 'chart-cmp',
templateUrl: 'chart.component.html'
})
export class ChartComponent implements OnInit {
ngOnInit() {
var container:any = $('#container');
container.highcharts({
chart: {
type: 'area'
},
...................................
In my case, I want to get the date from a restfull service.
Can you help me to do this please??
any input will help
Make sure you have the correct imports,
import {Http, Response, URLSearchParams} from '#angular/http';
This is how to make a get request,
Get Request
saveProfile(model: Profile, isValid: boolean) {
let params: URLSearchParams = new URLSearchParams();
// set params to go to URL
params.set('email', model.email);
params.set('first_name', model.first_name);
return this.http.get('url/path/here/dont/forget/port',
{ search: params })
.map((res: Response) => res.json())
.subscribe((res) => {
console.log(res);
// Map the values in the response to useable variables
this.auth.user.email = res.user.email;
this.auth.user.first_name = res.user.first_name;
});
}
}
Post Request
How to make a post request,This is a popular post request used in the auth0 library. You can find that here
authenticate(username, password) {
let creds = JSON.stringify({ username: username.value, password: password.value });
let headers = new Headers();
headers.append('Content-Type', 'application/json');
this.http.post('http://localhost:3001/sessions/create', creds, {
headers: headers
})
.subscribe(
data => {
this.saveJwt(data.json().id_token);
username.value = null;
password.value = null;
},
err => this.logError(err.json().message),
() => console.log('Authentication Complete')
);
}
These examples will get a response from the server. If you want to do some more technical things like get the new data to update in the view, you will have to create an observable. If I were you I would get this down then when you need to understand observable you can incorporate that.

How to invoke component to update data?

I have a main component with 2 sub-components (update, profile).
On update component, I have a form with several input fields. When I submit a form, profile section information should update after a successful request.
The problem is, profile information doesn't update after a successful request.
So, how to invoke profile component to refresh updated data? I tried to call a service after successful request, but no luck.
By the way, parent service looks like:
#Injectable()
export class AvailabilityService {
constructor(private http: Http) {
}
getProfile() {
return this.http.get(API_URL + '/user/profile')
.map(this.extractData)
.catch(this.handleError);
}
freeOwnersParking(availableDates: AvailableDates) {
let domain = API_URL + '/parking/availability';
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
let body = JSON.stringify(availableDates);
return this.http.put(domain, body, options)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body;
}
private handleError(error: any) {
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
return Observable.throw(errMsg);
}
}
UPDATE
Get profile:
getProfile() {
this.availabilityService.getProfile()
.subscribe(
profile =>this.profile = profile,
error => this.errorMessage = <any>error
);
}
Update profile:
freeOwnersParking() {
this.availabilityService.freeOwnersParking(this.availableDates)
.subscribe(
response => this.availabilityService.getProfile(),
error => this.errorMessage = error
);
}
You need to leverage a shared service between them to notify the profile component.
For example an UpdateProfileService with an observable / subject in it. In this case, the profile component can subscribe on it to be notified.
Here is the service:
#Injectable()
export class UpdateProfileService {
profileUpdated:Subject<boolean> = new Subject();
(...)
updateProfile(profile:any) {
return this.http.put('http://...', profile)
.map(res => {
this.profileUpdated.next(true);
return res.json();
});
}
}
and within the profile component:
#Component({
(...)
})
export class ProfileComponent {
constructor(private service:UpdateProfileService) {
this.service.profileUpdated.subscribe(() => {
// Update bound data for profile
});
}
}