问题
I'm trying to get my head around observables in Angular 6, but I'm new to anything more recent than AngularJS and seriously struggling right now. I think I've gone through every tutorial I can find and searched extensively here, so hopefully I'm not missing anything, but happy to take friendly pointers...
What I'm trying to do is this:
- GET request to a backend API, returns a JSON array of items, and display that array in a component as a data list
- Allow a second component to POST new items to the backend, and also add that item to the list of items above
I'm guessing I'm describing an observable, because #1 needs to be asynchronous, but all the examples I've seen seem to only deal with one of the two steps, not both together. What am I missing?
回答1:
@1: GET request to a backend API, returns a JSON array of items, and display that array in a component as a data list
let's call this one ComponentA:
export class ComponentA {
arrayOfItems:Type[];
constructor(private http:HttpClient) {}
getDataFromAPI():Observable<Type[]> {
this.http.get<Type[]>('api-get-url')
.subscribe(
(items) => {
//print them if you want;console.log('response from the api', items);
this.arrayOfItems = items;
}
)
}
}
@2.1: Allow a second component to POST new items to the backend (omitted a part of the question on purpose)
export class ComponentB {
// let's assume this array is already populated
// via you 2-way bindings or whatever means
newItems:Type[];
constructor(private http:HttpClient) {}
postDataToAPI():Observable<any> {
this.http.post('api-post-url', this.newItem)
.subscribe(
response => console.log('response from the api', response);
)
}
}
@2.2 and also add that item to the list of items above
Everything ^ was straightforward, but now you gotta stop and think: I have something 'here' and something 'there'. How can I ... connect them? Ha! Connect! So I need some sort of mechanism to connect the 2 components. What do you do? You use a service! But a service whose purpose is to store a shared data set. You can call it DataStoreService.
Let's (re)write some code:
@Injectable()
export class DataStoreService() {
items:Type[] = [];
constructor(private http:HttpClient) {}
getDataFromTheAPI():Observable<Type[]> {
this.http.get<Type[]>('api-get-url')
.subscribe(items => this.items = items)
}
postDataToTheAPI(itemToAdd:Type):Observable<any> {
this.http.post('api-post-url', itemsToAdd)
.subscribe(
(response) => {
// check if all is good, and add it to the 'items' array
addItem(itemToAdd);
}
}
)
}
getItems() {
return this.items;
}
addItem(item:Type) {
this.items.push(item);
}
}
Now, your Component A changes to:
export class ComponentA implements OnInit{
constructor(private dataStoreService: DataStoreService) {}
ngOnInit(): void {
this.dataStoreService.getDataFromTheAPI();
// ^ will request the data from the API and store it
// inside the service
}
// and here you get a reference to that data
get itemsReferenceFromService() {
return this.jobsStoreService.getJobsArray();
}
}
And ComponentB to:
export class ComponentB {
newItem:Type;
constructor(private dataStoreService: DataStoreService) {}
// when you do this, if successful, addItem method
// will also be called that will 'and also add that item to the list of items above'; as componentA only has a reference to the data in
// the service, the new item will be displayed it it
this.dataStoreService.postDataToTheAPI(newItem);
}
Hope this answers your question. If you have any other doubts, say it loud. Info like urls were omitted.
A further improvement is to have another service that only handles the API calls, and keep the DataService clean just for storing purposes. That will ease testing.
Be aware that the lifespan of any Service/Component in angular is up untill the end user refreshed the page. The service described is not a persistence mechanism.
回答2:
That because it is two different things.
The first is an request that you are expecting data from. so you subscribe to it.
$newsletter = NewYorkTimesService.getData(); // this does some http stuff.
$newsletter.subscribe(newspaper => readData(newpaper) /*or whatever you want to do with json */ );
The second is a total different call (and different observable) to send data, where you are only really subscribing to know if it was successful.
$paymentResults = NewYorkTimesService.makePayment(paymentJSON); //this does http stuff too.
$paymentResults.subscribe(() => /*I guess it was successful */ , (error)=> /*it failed */);
The only thing they share is that they might be of the same called from the same service.
回答3:
Here is a basic example of doing it in Angular 5. I think the only thing that may be different between 5 and 6 is where the libraries you are importing come from.
@Injectable()
export class ItemsService {
constructor(private http: HttpClient) { }
private backendURL= "http://myurl.endpoint.com/";
getItems(): Observable<IItem[]> {
return this.http.get<IItem[]>(backendURL);
}
saveItems(items: IItem[]): Observable<IItem[]> {
let options = { headers: new HttpHeaders({'Content-Type': 'application/json'})};
return this.http.post(backendUrl, items, options);
}
}
In your Component class you import the component and subscribe to it.
export class ItemComponent {
itemList: Item[];
constructor(private itemService: ItemService) { }
ngOnInit() {
this.itemService.getItems().subscribe(data => this.itemList = data);
}
}
Here is a pretty good tutorial that goes over the basics https://angular.io/tutorial
来源:https://stackoverflow.com/questions/51218241/angular-observable-array-populated-by-an-http-request-and-manually-added-data