With ngx-restangular post() , i receive in my json-server PUT /feedback/4?firstname=aa&lastname=aa - angular2-routing

i work with angular 2 and use Restangular.
with my code i see in my json-server this response
and i would like to know how i can save it in my application
OPTIONS /feedback/4?firstname=aa&lastname=aa
PUT /feedback/4?firstname=aa&lastname=aa
an advice
thanks
Cordially

Yes I know it's not very clear.
my class Feedback:
export class Feedback {
firstname:string;
lastname:string;
telnum:number;
email:string;
agree:boolean;
contacttype:string;
message:string;
};
i have this function in service
submitFeedback(): Observable<Feedback>{
return this.restangular.all('feedback').post(Feedback);
}
in my component, i want retrieve information and send it to my db.json
this.route.params
.switchMap( (feedback:Params) => this.feedbackservice.submitFeedback() )
.subscribe( feedback => { this.feedback = feedback; this.feedbackcopy = feedback; },
errmess => this.errMess = <any>errmess );//u
console.log('feedback::: ' + this.feedbackcopy );
via a form
this.feedback = this.feedbackForm.value;
this.feedbackcopy.save(this.feedback)
.subscribe( feedback => this.feedbackcopy = feedback );
I don't know how save "this.feedback" in my db.json
For instance in my db.json only an feedback.id is writting and not the other parameters
"feedback": [
{
"id": 1
}
]
for me the restangular.post() method isn't clear
I hope to be a little clearest
Cordially

You should pass to this function your JSON as the parameter with type Feedback and then pass it to post:
submitFeedback(feedback: Feedback ): Observable<Feedback>{
return this.restangular.all('feedback').post(feedback);
}

Related

Ionic rxjs pipe function not getting called after http post

I am using ionic 5
when I try to connect to firebase using post and get the response data and process the response using pipe and tap then it's not working. The log is not printing.
But when I replace the pipe with subscribe then it's working correctly and I can see the log correctly.
Please see the working and not working code below.
Can someone please help me to solve this issue. Thanks for your help.
WORKING CODE
return this.http.post("https://project-name.firebaseio.com/offered-places.json", {
...newPlace,
id: null
}).subscribe(resDate => {
console.log(resDate);
});
NOT WORKING CODE
return this.http.post("https://project-name.firebaseio.com/offered-places.json", {
...newPlace,
id: null
}).pipe(
tap(resData => {
console.log(resData);
})
);
As stated in comments you have to call subscribe method
Here's the snippet which reproduces your cases and provides mentioned solution.
const exampleObservable1 = rxjs.of([{}]);
const exampleObservable2 = rxjs.of([{}]);
const exampleObservable3 = rxjs.of([{}]);
console.log('working example');
exampleObservable1.subscribe(resDate => {
console.log(resDate);
});
console.log('not working example');
exampleObservable2.pipe(
rxjs.operators.tap(resData => {
console.log(resData);
}))
console.log('suggestion');
exampleObservable3.pipe(
rxjs.operators.tap(resData => {
console.log('tap', resData);
})).subscribe(resDate => {
console.log('subscription', resDate);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.js"></script>

Trigger a action upon success full response of another action ngrx

I created a ngrx effect that's responsible for sending a POST request to a back end. now i want to change the implementation little bit. if the post request is successful I want to trigger another action that responsible update my ngrx store. but I couldn't figure out how to do that.
I tried to use switch map and merge map but didn't work.
creatTour$ = createEffect(() =>
this.actions$.pipe(
ofType(TourAction.createTour),
mergeMap((action) => {
const payload = action.tour;
const endpoint = environment.urls.tour.replace("{tourProviderId}", "1");
const request = new ServiceRequest(endpoint, 'POST', payload, options);
return this.requestHandlerService.invoke(request).pipe(
map((sucessResponce) => {
if (sucessResponce.code === 200) {
TourListAction.updateTourList({ tour: [tour] }) // i want to trigger this action and
// below action
}
return TourAction.createTourSucess({ responce: sucessResponce.message })
}),
catchError(err => {
const errorMessage = JSON.stringify(err);
console.log(errorMessage);
return of(TourAction.createTourFail({ errorMessage }))
})
)
})
)
);
i tried this way too
return [TourAction.createTourSucess({ responce: sucessResponce.message }
TourListAction.updateTourList({ tour: [tour] })]
it throws this error
Property 'type' is missing in type '(({ responce: string; }
& TypedAction<"[Tour] Create Tour Success">) | ({ tour: Tours[]; } &
TypedAction<"[Tour List] Tour List Update">))[]' but required in type
'Action'.
is this the better way to do this.i saw there is new thing called entity should I use that for this implementation?
Why not update your state on the createTourSucess action?
You can also return multiple actions:
.pipe(
switchMap(() =>
return [
TourListAction.updateTourList({ tour: [tour] }) ,
TourAction.createTourSucess({ responce: sucessResponce.message })
]
)
)
https://medium.com/#amcdnl/dispatching-multiple-actions-from-ngrx-effects-c1447ceb6b22
You can return multiple actions from your effect, they will all be dispatched.
See https://medium.com/#tanya/understanding-ngrx-effects-and-the-action-stream-1a74996a0c1c
For your code:
return successResponse.code === 200 ? [
createTourUpdateAction(tour),
TourAction.createTourSuccess
] : [TourAction.createTourSuccess]

Get data from Firebase in Ionic 2

I have written my app with ionic 2 and followed the tutorial of Josh Morony, but I don't know how I can get a specific element from my firebase database.
For example I have this tree :
user
|__ (user_id)
|_ name : 'toto'
And so on...
I tried this way:
elt: FirebaseListObservable<any[]>;
this.elt = af.database.list('/user');
But how can I work with the selected data?
I found this solution which is similar than yours :
af.database.list('/user', { preserveSnapshot: true})
.subscribe(snapshots=>{
snapshots.forEach(snapshot => {
console.log(snapshot.key, snapshot.val());
this.items.push({
id: snapshot.key,
name: snapshot.val().name
});
});
});
In order to get the data as an array from a provider you need to return a promise which will be returned once the firebaseListObservable event is triggered with return data.
In your provider .ts
getData(fbPath): Promise<any> {
return new Promise(resolve => {
this.db.list(fbPath).subscribe(data => {
resolve(data);
})
})
}
Here the promise resolves once the data is populated and returns an array with easy access to the $value and $key properties. Which is ideal for creating conditionals or complex queries or a provider service with generic properties ( as opposed to querying the snapshot of the firebaseListObservable directly )
In your controller you can then write something like
this.providerName.getData('users').then(data => {
console.log('data',data);
})
This will return an object literal with the values
$exists
$key
$value
So now if you want a match conditional you can loop through the data with the match condition on the $key of the table users
if(myUserIdVar === data.$key){ // do something here };
A tidier syntax can be found using a library like lodash Where for example if you want a condition to match a stored id, say firebase.auth().currentUser.uid you can do a simple _.find
import { find } from 'lodash';
import * as firebase from 'firebase'; // Or just the firebase auth stuff
...
let filteredUser = find(data, ['$key', firebase.auth().currentUser.uid])
The $key value will be equal to the |__ (user_id) value
I think, af.database.list('/user') returns an Observable. You need to subscribe to it. Like this:
af.database.list('/user')
.subscribe(data => {
console.log("Data is : ",data);
},
(ex) => {
console.log('Found exception: ', ex);
});
Also, if this is in your provider and you want to return the data, you can create a new Observable and return it. If need help, could edit my answer to that also.

HTTP: Angular 2+TS How to use Observables in HTTP

I found an example from angular.io. This example is very similar to my app, with same kind of methods. This example is using Promises, but I'm using Observables. If I use this example as a reference, I have every method working in my app, except the getHero method in the service, and the ngOnInit in the HeroDetailComponent. So I'm wondering if someone can help and convert this method to an observable, because I'm having trouble with the syntax. Here is the codes I need converted to Observable and the plunker
//HeroService
getHero(id: number) { // my id is String
return this.getHeroes()
.then(heroes => heroes.filter(hero => hero.id === id)[0]);
}
//HeroDetailComponent
ngOnInit() {
if (this.routeParams.get('id') !== null) {
let id = +this.routeParams.get('id');
this.navigated = true;
this.heroService.getHero(id)
.then(hero => this.hero = hero);
} else {
this.navigated = false;
this.hero = new Hero();
}
}
So I want something like this:
//HeroService
public getHero(id: string) {
return this.getHeroes()
.subscribe(heroes => this.heroes.filter(hero => heroes.id === id)[0]); //BTW, what does this [0] mean??
}
EDIT: I had to actually retrieve the list directly, it didn't work with return this.heroes as suggested in answers below. Working example:
public getById(id: string) {
//return this.getHeroes() <---- didn't work
return this.http.get('someUrl') // WORKS!
.map(heroes => this.heroes.filter(hero => hero.id === id)[0]);
}
Now I'm still having trouble with my ngOnit, and I can't really understand why!
ngOnInit(){
let id = this._routeParams.get('id');
this.heroService.getById(id)
//console.log("retrieved id: ",id ) <----- gives correct id!
.subscribe(hero => this.hero = hero);
//console.log("hero: ", this.hero); <----- gives undefined!
}
EDIT2, still getting undefined when trying to move to the detail page :( I think you had one bracket to much in your answer, tried to look and get the correct places for the brackets?
ngOnInit(){
let id = this._routeParams.get('id');
this.heroService.getById(id)
.subscribe(heroes => {
// this code is executed when the response from the server arrives
this.hero = hero
});
// code here is executed before code from the server arrives
// even though it is written below
}
If you call subscribe() on an Observable a Subscription is returned. You can't call subscribe() on a subscription.
Instead use just an operator (map()) and use subscribe() on the call site:
public getHero(id: string) {
return this.getHeroes()
.map(heroes => this.heroes.filter(hero => heroes.id === id)[0]);
}
ngOnInit(){
let id = this._routeParams.get('id');
this.heroService.getHero(id)
.subscribe(hero => this.hero = hero);
}
In contrary to subscribe(), map() also operates on an Observable but also returns an Observable.
[0] means to just take the first item of the filtered heroes.
update
ngOnInit(){
let id = this._routeParams.get('id');
this._searchService.getById(id)
.subscribe(searchCase => {
// this code is executed when the response from the server arrives
this.searchCase = searchCase;
console.log("id: ", this.searchCase);
});
// code here is executed before code from the server arrives
// event though it is written below
}
This code is a function
searchCase => {
// this code is executed when the response from the server arrives
this.searchCase = searchCase);
console.log("id: ", this.searchCase);
}
that is passed to subscribe() and the Observable calls this function when it has new data for the subscriber. Therefore this code is not executed immediately but only when the observable emits new data.
Code that comes after subscribe() is executed immediately and therefore before above function and therefore this.searchCase does not yet have a value.
This is a way you can do it:
//HeroService
public getHero(id: string) {
return this.getHeroes()
.map(heroes => this.heroes.filter(hero => heroes.id === id)[0]);
}
//HeroDetailComponent
ngOnInit(){
let id = this._routeParams.get('id');
this.heroService.getHero(id)
.subscribe(hero => {
// your code here
});
}
The [0] is an array accessor. You're selecting the first element on array index 0 with it. You need this, because Array.filter() returns a new array with the filtered values, but you only want one hero.

Angular2 - How to chain async service calls (http requests) in a component?

I have a component which first need to call a service that POST something. Then in the same component I want to wait until the POST is done, to call another service which GETs data.
How can I make the GET call wait for the POST call to finish?
In new-version.component.ts:
private createNewVersion(value) {
...
// create new version, then call on all available versions
// POST call
this._newVersionService.createNewVersion(vnr);
// GET call
this._versionService.getAvailableVersions();
...
}
In new-version.service.ts:
export class NewVersionService {
response$: Subject<any>;
constructor(private _http: Http) {
this.response$ = new BehaviorSubject<any>(null);
}
public createNewVersion(versionNr) {
this._http.post('http://localhost:8080/services/' + versionNr, null, {
method: 'POST',
})
.subscribe(response => {
this.response$.next(response.status);
},
error => console.error(error));
}
Thanks!
When a call returns a Promise chain the calls with
someFunction() {
return returnsPromise()
.then(result => doSomethingNext())
.then(result => doSomethingAfterThat());
}
Ensure you have a return that returns the Promise of that chain so the caller of someFunc() also has a chance to time additional work to execute after doSomethingAfterThat() is completed.
When a call returns an Observable then use the complete callback
someFunction() {
return returnsObservable()
.subscribe(
event => doForEachEvent(),
error => handleError(),
() => doSomethingNext()
.then(result => doSomethingAfterThat());
}
doSomethingNext() is executed after the last event and doSomethingAfterThat() is again chained with then() to show how to mix observable and promise. doSomething().
You should be able to concat to achieve sequence, and reduce to collect the emitted values:
var a = this._newVersionService.createNewVersion(vnr);
var b = this._versionService.getAvailableVersions();
Rx.Observable.concat(a, b).reduce((acc:Array<any>, x:any) => {
acc.push(x); return acc;
}, []).subscribe(t=> {
var firstEmitted = t[0];
var secondEmitted = t[1];
});
You can do like this:
Change createNewVersion to:
public createNewVersion(versionNr) {
return this._http.post('http://localhost:8080/nod_inspection_plugin/services/' + versionNr, null, {
method: 'POST',
});
}
Then in your call:
this._newVersionService.createNewVersion(vnr).subscribe(response=> {
this._versionService.getAvailableVersions();
}, error => console.error(error));
Another way to do the same is to subscribe in the new-version.component.ts and call you GET request from within the POST request i.e check whether your POST request is done Correctly or not
if yes POST is done Properly then call you GET request. As below:
In new-version.component.ts:
private createNewVersion(value) {
...
// create new version, then call on all available versions
// POST call
this._newVersionService.createNewVersion(vnr)
.subscribe((res) => {
if(res){
console.log(res);
if (---Post request done properly check via status or something else here----{
CALL YOUR GET REQUEST HERE.....
// GET call
this._versionService.getAvailableVersions();
}
else {
DO something else whatever you want....
}
}
});
...
}
In new-version.service.ts:
export class NewVersionService {
response$: Subject<any>;
constructor(private _http: Http) {
this.response$ = new BehaviorSubject<any>(null);
}
public createNewVersion(versionNr) {
this._http.post('http://localhost:8080/nod_inspection_plugin/services/' + versionNr, null, {
method: 'POST',
})
.map(response => {
return [{status: response.status, json: response.json()}];
},
error => console.error(error));
}
for more info related to http request you can read here.
Better use switchMap() here.
const versions$ = this._newVersionService.createNewVersion(vnr)
.switchMap(response => this._versionService.getAvailableVersions());
versions$.subscribe(response2 => this.versions = response2)
But the problem will be if you make another POST request before first has been resolved, the previous request will get cancelled.

Resources