First of all, I am very new to Angular2 (or any other version actually) and I have followed several tutorials to get me started but I'm now in a dead end and I don't know how to proceed.
Here is the background: I am accessing a third party web API through a POST request (I did that in a service) and it returns HTML markup of the control I need to render on my page, so I made a component of it. It works fine (I had to create a custom pipe to work around the DOM sanitization though).
And here's my issue: in the markup I'm receiving from the web API there's JavaScript stuff to initialize the control that is supposed to execute as soon as it is on the page (it does in every other language I used this control in, PHP, Java, JavaScript, ASP.NET, etc) but for some reason, using Angular2 I can see the script in the DOM, properly inserted at the end of the markup but it does not execute so my control does not work.
Here is my component code:
import { Component, OnInit, ViewEncapsulation } from '#angular/core';
import { MyService } from './my.service'
#Component({
selector: 'mycontrol',
template: `<div style="width:1200px; height:1000px;" [innerHtml]="htmlContent | keepHtml"></div>`,
styleUrls: ['app/control-min.css'],
encapsulation: ViewEncapsulation.None
})
export class MyComponent implements OnInit {
htmlContent: any;
constructor(private myService: MyService) {
}
ngOnInit(): void {
this.myService.getControlMarkup().subscribe(
response => this.htmlContent = response["HtmlContent"],
error => this.htmlContent = <any>error
);
}
}
And here is my service code:
import { Injectable } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';
#Injectable()
export class MyService {
headers: Headers;
options: RequestOptions;
constructor(private http: Http) {
this.headers = new Headers({ 'Content-Type': 'application/json' });
this.options = new RequestOptions({ headers: this.headers });
}
getControlMarkup() {
let controlConfig = {
SessionId: "mySessionId",
ControlId: "MyControl1"
};
let body = JSON.stringify(controlConfig);
return this.http
.post('http://localhost:62968/api/GetControl', body, this.options)
.map(this.extractData)
.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';
console.error(errMsg);
return Observable.throw(errMsg);
}
}
Any idea how I can make this work?
Related
I want to display the ngx-wheel using api but I'm having trouble displaying the data.
Here my Service :
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class RestServices {
restEndpoint:string = 'https://gorest.co.in/public/v2/users'
constructor(
private httpClient: HttpClient
) { }
async getServiceId() {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
}
return this.httpClient.get<any[]>(this.restEndpoint, httpOptions)
}
Here my Component :
private subscription: Subscription | undefined;
items: any = []
ngOnInit(): void {
this.subscription = this._restService.getServices()
.subscribe((res:any)=>{
let item = res
this.items = item.map((v:any) => ({
text: v.name,
id: v.id,
textFillStyle: "white",
textFontSize: "16"
}));
})
}
ngOnDestroy(): void {
this.subscription?.unsubscribe()
}
Here for html
<ngx-wheel #wheel [width]='350' [height]='350' [spinDuration]='8' [disableSpinOnClick]='true' [items]='items'
[innerRadius]='10' [spinAmount]='10' [textOrientation]='textOrientation' [textAlignment]='textAlignment'
pointerStrokeColor='black' pointerFillColor='white' [idToLandOn]='idToLandOn' (onSpinStart)='before()'
(onSpinComplete)='after()'>
I hope to find the answer here. Thank you
First, you don't need await, async and ,toPromise()... remove them and simply return
return this.httpClient.get<any[]>(this.restEndpoint, httpOptions);
inside your component you should use your constructor only for simple data initialization: if you have to consume a rest api it is a better approach to move that piece of code inside the ngOnInit method:
items: any[] = []
constructor(private restService: RestService){}//dependency injection
ngOnInit(): void {
this.restService.getServiceId().subscribe(response => {
console.log('response success: ', response);
this.items = response; //this may change a little based on your api
console.log('items: ', this.items);
}, errorLog => {
console.log('response error: ', errorLog)
});
}
The above solution is valid, you can enrich it by adding a *ngIf="isLoaded" on your html element and set to true the isLoaded INSIDE subscribe method. but if you prefer you can do the following in the component.ts
items$: Observable<any> = EMPTY;
constructor(private restService: RestService){}//dependency injection
ngOnInit(): void {
this.items$ = this.restService.getServiceId();
}
then, in your html it would change to the following:
<ngx-wheel #wheel *ngIf="items$ | async as items" [width]='350' [height]='350' [spinDuration]='8' [disableSpinOnClick]='true' [items]='items'
[innerRadius]='10' [spinAmount]='10' [textOrientation]='textOrientation' [textAlignment]='textAlignment'
pointerStrokeColor='black' pointerFillColor='white' [idToLandOn]='idToLandOn' (onSpinStart)='before()'
(onSpinComplete)='after()'>
I'm new to Angular and hoping someone can guide me through the process of making a soap call. I can call the endpoint with a Request in SoapUI and it returns the correct Response. Now I'd like to know how to do the same thing in Angular.
The closest one I could find is Answer #3. But it doesn't provide enough context for a beginner.
Here's what I've got so far:
app.component.ts
import { Component } from '#angular/core';
import { SoapService } from './soap.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
title = 'Test of SOAP calls'
name = 'SOAP Prototype';
response: any;
constructor(private soapService: SoapService)
{
soapService.getResponse().subscribe(
res => {
console.log("returned data: ",res);
}
);
}
}
soap.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '#angular/common/http';
import { Subject } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
#Injectable()
export class SoapService
{
constructor(private httpClient: HttpClient) { }
getResponse()
{
const myheaders = new HttpHeaders();
myheaders.set('Content-Type','text/xml');
const myparams = new HttpParams();
myparams.set('username', 'me');
myparams.set('acctId','1585');
myparams.set('domain','USR');
myparams.set('active','true');
const response = this.httpClient.post<any>('url-to-soap-service', {headers: myheaders, params: myparams, responseType: 'text'});
console.log(response);
return response;
}
}
Nothing is logged to the console in app.component.ts, nor in soap.service.ts.
I'm see this error in the browser console:
"<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">soap:Bodysoap:Faultsoap:ClientError
reading XMLStreamReader: Unexpected character '{' (code 123) in
prolog; expected '<'\n at [row,col {unknown-source}]:
[1,1]</soap:Fault></soap:Body></soap:Envelope>"
I don't see how there can be an unexpected char when the HttpClient is generating the soap envelope.
What am I doing wrong?
I have an component where i am adding a new object called customer by calling the api like this:
public onAdd(): void {
this.myCustomer = this.customerForm.value;
this.myService.addCustomer(this.myCustome).subscribe(
() => { // If POST is success
this.callSuccessMethod();
},
(error) => { // If POST is failed
this.callFailureMethod();
},
);
}
Service file:
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Observable, Subject } from 'rxjs';
import {ICustomer } from 'src/app/models/app.models';
#Injectable({
providedIn: 'root',
})
export class MyService {
private baseUrl : string = '....URL....';
constructor(private http: HttpClient) {}
public addCustomer(customer: ICustomer): Observable<object> {
const apiUrl: string = `${this.baseUrl}/customers`;
return this.http.post(apiUrl, customer);
}
}
As shown in component code, i have already subscribed the api call like this:
this.myService.addCustomer(this.myCustome).subscribe(
() => { // If POST is success
.....
},
(error) => { // If POST is failed
...
},
);
But,I want to subscribe the results in another component, I have tried like this:
public getAddedCustomer() {
this.myService.addCustomer().subscribe(
(data:ICustomer) => {
this.addedCustomer.id = data.id; <======
}
);
}
I am getting this lint error: Expected 1 arguments, but got 0 since i am not passing any parameter.
What is the right approach to subscribe the api call in other components? after POST operation.
Because i want to get added object id for other functionality.
Well it totally depends on the design of your application and the relation between components. You can use Subjects for multicasting the data to multiple subscribers.
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Observable, Subject } from 'rxjs';
import { ICustomer } from 'src/app/models/app.models';
#Injectable({
providedIn: 'root',
})
export class MyService {
private baseUrl : string = '....URL....';
private latestAddedCustomer = new Subject();
public latestAddedCustomer$ = this.latestAddedCustomer.asObservable()
constructor(private http: HttpClient) {}
public addCustomer(customer: ICustomer): Observable<object> {
const apiUrl: string = `${this.baseUrl}/customers`;
return this.http.post(apiUrl, customer).pipe(map((data) => this.latestAddedCustomer.next(data)));
}
}
and subscribing to the subject as follows
this.latestAddedCustomer$.subscribe()
should get you the latest added customer details. Even though i would not do this the way its written. I would basically write a seperate service to share the data between the components or would write a cache service if its used across the application. But the idea here is to use the concept of Subjects. You can read more about it Here
I am stuck at the phase of learning CRUD operation in Angular 5
I have been trying for hours but no avail, it seems i can't solve the error.
When I subscribe data which comes from service and try to insert data using push. It says undefined.
addtasks.component.ts
import { Component } from '#angular/core';
import { AddTaskService } from '../../services/add-task.service';
import { Tasks } from '../../../Tasks/Tasks';
#Component({
selector: 'app-addtasks',
templateUrl: './addtasks.component.html',
styleUrls: ['./addtasks.component.css']
})
export class AddtasksComponent {
tasks: Tasks[];
title: string;
constructor(private addTaskService: AddTaskService) {
console.log("Add tasks page has been accessed...");
}
addTasks(event){
event.preventDefault();
var newTask = {
title: this.title,
isDone: false
};
this.addTaskService.addTask(newTask).subscribe(task => {
this.tasks.push(task);
this.title = '';
});
}
}
add-task.service.ts
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class AddTaskService {
constructor(private http: Http) { console.log("Add Task service initialized..."); }
addTask(newTask){
var headers = new Headers();
headers.append('Content-Type', 'application/json');
console.log(newTask);
return this.http.post('http://localhost:2200/api/tasks', JSON.stringify(newTask), {headers: headers})
.map(res => res.json());
}
}
Model
Tasks.ts
export class Tasks {
title: string;
isDone: boolean;
}
The error showing in my console
TypeError columnNumber: 13 fileName:
"http://localhost:2200/main.bundle.js" lineNumber: 193 message:
"_this.tasks is undefined" stack:
"../../../../../src/app/components/addtasks/addtasks.component.ts/AddtasksComponent.prototype.addTasks/<#http://localhost:2200/main.bundle.js:193:13\n../../../../rxjs/_esm5/Subscriber.js/SafeSubscriber.prototype.tryOrUnsub#http://localhost:2200/vendor.bundle.js:1697:13\n../../../../rxjs/_esm5/Subscriber.js/SafeSubscriber.prototype.next#http://localhost:2200/vendor.bundle.js:1644:17\n../../../../rxjs/_esm5/Subscriber.js/Subscriber.prototype._next#http://localhost:2200/vendor.bundle.js:1585:9\n../../../../rxjs/_esm5/Subscriber.js/Subscriber.prototype.next#http://localhost:2200/vendor.bundle.js:1549:13\n../../../../rxjs/_esm5/operators/map.js/MapSubscriber.prototype._next#http://localhost:2200/vendor.bundle.js:4978:9\n../../../../rxjs/_esm5/Subscriber.js/Subscriber.prototype.next#http://localhost:2200/vendor.bundle.js:1549:13\nonLoad#http://localhost:2200/vendor.bundle.js:75626:21\n../../../../zone.js/dist/zone.js/http://localhost:2200/polyfills.bundle.js:2504:17\nonInvokeTask#http://localhost:2200/vendor.bundle.js:53623:24\n../../../../zone.js/dist/zone.js/http://localhost:2200/polyfills.bundle.js:2503:17\n../../../../zone.js/dist/zone.js/http://localhost:2200/polyfills.bundle.js:2271:28\n../../../../zone.js/dist/zone.js/http://localhost:2200/polyfills.bundle.js:2578:24\ninvokeTask#http://localhost:2200/polyfills.bundle.js:3619:9\nglobalZoneAwareCallback#http://localhost:2200/polyfills.bundle.js:3645:17\n"
__proto: Object { stack: "", … }
You should initialize tasks variable before using it.
Initialize it in the constructor function.
constructor(private addTaskService: AddTaskService) {
console.log("Add tasks page has been accessed...");
this.tasks = [];
}
That's why you have an error saying its undefined.
I have ts file and I would like to create POST method inside component. I try in the way shown below unfortunately without positive results.
this.http.post("http://localhost:8000/", JSON.stringify({ body: 'String' }), {headers:{'Content-Type': 'application/json'}})
UPDATE
I have a little modified my backend logic and I realized that I don't need to send body in POST method. I can send my data in URL parameter. I would like to send GET request and assign received data to object object.sth which needs object of Isth[] type. At this moment my code looks in the way shown below. However console.log("data: "+object.sth); after assignment returns data: undefined.
this.http.get("http://localhost:8000/path?sth=exampleurl", headers).map(res => res.json()).subscribe(data => this.data = data);
object.sth = this.data;
this.http.post(url, JSON.stringify(YOURSTRING), {headers:{'Content-Type': 'application/json'}})
It should work for request. (Ur first question)
in top of ur component
import { Headers, Http } from "#angular/http";
ur component:
constructor(private http: Http) {}
yourRequest() {
let headers = new Headers({'Content-Type': 'application/x-www-form-urlencoded' })
this.http.post(url, JSON.stringify(YOURSTRING), headers).subscribe(res=>console.log(res));
}
I'm going to update the answer with more complete syntax. Hopefully that can get you something running without an error.
import { Http } from '#angular/http';
import { Component } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Component({
selector: 'my-app',
template: `<h1>Hello World</h1>`,
styleUrls: ['./app.component.css']
})
export class AppComponent {
private headers: Headers;
private options: RequestOptions;
constructor(private http: Http) {
this.headers = new Headers({ 'Content-Type': 'application/x-www-form- urlencoded' });
this.options = new RequestOptions({ headers: this.headers });
}
ngOnInit() {
this.doPost().subscribe(response => {
console.log(response);
});
}
doPost() {
return this.http.post("http://localhost:8000/sth", this.options).map(res => res.json());
}
}
Original:
I think what you're missing is the subscribe. Observables won't execute unless you subscribe to them.
this.http.post("http://localhost:8000/", JSON.stringify({ body: 'String' }), {headers:{'Content-Type': 'application/json'}}).subscribe(res=>console.log(res));
Just for the record, it is usually better to put your http calls in a service, not inside the component.