I'm struggling in finding a solution to my problem: I'm working on a "survey" module where you answer some questions. But the problem lies in the "answer" compontent. Lets say you have an input field that POSTs your answer on every input, and after the first time you posted it needs to PUT based on the id the POST returns.
What i have so far: (this is just an example, so something might not be correct, but the problem is still the same)
@Component({
selector: 'app-answer',
template: '<input [(ngModel)]="answer.text" (ngModelChange)="change()">',
})
export class AnswerNgmodelComponent {
answer: Answer = { id: 0, text: '' };
private answerChanged = new Subject<string>();
constructor(private http: HttpClient) {
this.answerChanged
.pipe(
debounceTime(1000),
switchMap((res) =>
this.answer.id > 0
? this.updateAnswer(this.answer)
: this.postAnswer(this.answer)
)
)
.subscribe((res) => {
if(res) {
this.answer.id = res;
}
});
}
change() {
this.answerChanged.next();
}
//Returns id of created answer
postAnswer(answer: Answer): Observable<number> {
return this.http.post<number>('http://api.com/answer', answer);
}
//Updates answer
updateAnswer(answer: Answer): Observable<any> {
return this.http.put('http://api.com/answer/' answer.id, answer);
}
}
export class Answer {
id: number;
text: string;
}
The problem i'm running into: The first time you answer the question we need to wait for the post to finish and set the id of the answer. But if theres abit of delay in the post request theres a window where you can "update" your answer when it hasnt finished posting yet, and is going to post the answer again.
How can i wait for the "create" post to finish, and then begin to "update" after?
UPDATE Apparently it is as easy as changing switchMap to concatMap - thanks to @akotech
CodePudding user response:
You can save the request subscription and unsubscribe before the new request if exists, This will cancel active request.
@Component({
selector: 'app-answer',
template: '<input [(ngModel)]="answer.text" (ngModelChange)="change()">',
})
export class AnswerNgmodelComponent {
answer: Answer = { id: 0, text: '' };
private answerChanged = new Subject<string>();
private activeRequestSubscription: Subscription = null;
constructor(private http: HttpClient) {
this.answerChanged
.pipe(
debounceTime(1000),
switchMap((res) =>
this.answer.id > 0
? this.updateAnswer(this.answer)
: this.postAnswer(this.answer)
)
)
.subscribe((res) => {
if(res) {
this.answer.id = res;
}
});
}
change() {
this.answerChanged.next();
}
//Returns id of created answer
postAnswer(answer: Answer): Observable<number> {
this.activeRequestSubscription?.unsubscribe();
this.activeRequestSubscription = this.http.post<number>('http://api.com/answer', answer);
return this.activeRequestSubscription;
}
//Updates answer
updateAnswer(answer: Answer): Observable<any> {
this.activeRequestSubscription?.unsubscribe();
this.activeRequestSubscription = this.http.put('http://api.com/answer/' answer.id, answer);
return this.activeRequestSubscription;
}
}
export class Answer {
id: number;
text: string;
}
I recomends to you to use a service for manage http requests.
CodePudding user response:
Use post request only and maintain id when you first time hit post request you passed id: 0 after that you will have a id for update then you can pass id in post data so in simple words if you have id=0 it means you answer first time in particular survey. and if you have any id from your backend, you pass that id in your data and update existing pool
example:
- when you first time answer:
your req data:
let reqData = { id: 0, content: 'test', des: 'test' }
- when you update your answer pool:
your req data:
let reqData = { id: 112, content: 'test', des: 'test' }
note: id 112 generated by your backend