I have a function that does a post request to the API, and gets back an object for a newly created document. I am successfully getting data back from the API in this function call, but while I am getting a new object with the correct "_id" info logged to the console, my "this.router.navigate(['/record', this._id])" is not triggering. I assume I should be able to tack it onto the end of this function like I am doing, so that it programmatically handles the navigation when the data is returned. But it's not working. The app doesn't navigate at all when that function is triggered. What am I missing here?
createRecord() {
this.recordsService.createRecord().subscribe(
data => {
// refresh the list
console.log(data);
return true;
},
error => {
console.error("Error creating record...");
return Observable.throw(error);
}
);
console.log('createRecord function initiated...');
this.router.navigate(['/record', this._id]);
}
My service looks like this:
createRecord() {
const headers = new Headers({ 'Content-Type': 'application/json' });
const options = new RequestOptions({ headers: this.headers });
const body = JSON.stringify({deleted: true});
return this._http.post
('https://api.somesite.com/v0/records?apikey=someapikey',
body, options).map((res: Response) => res.json());
}
Actually, you should call router.navigate when you successfully get your data (in the success callback)
createRecord() {
this.recordsService.createRecord().subscribe(
data => {
// refresh the list
this.router.navigate(['/record', data._id]);
},
error => {
console.error("Error creating record...");
return Observable.throw(error);
}
);
}
Related
I am using the react-native google API to request calendar data via HTTP request using axios.
After the user clicks a login button the function calendarData is initiated and successfully pulls the data and I use setCalendarEvents to set the state of my page to this response data.
I expected this to re-render the screen and display the data but it is not...How can I initiate a page refresh after this data is received from the HTTP request without a manual re-render?
STATE
const [calendarEvents, setCalendarEvents] = useState([]);
calendarData function RUNS AFTER LOG IN BUTTON IS PRESSED BY USER
const calendarData = async function signInWithGoogleAsync() {
try {
const result = await Google.logInAsync({
androidClientId: `['CLIENT ID]`,
iosClientId: `['CLIENT ID']`,
scopes: [
"profile",
"email",
"https://www.googleapis.com/auth/calendar",
"https://www.googleapis.com/auth/calendar.events",
],
});
if (result.type === "success") {
axios({
//HTTP GET REQUEST FOR DATA
method: "get",
baseURL: "https://www.googleapis.com/calendar/v3/calendars/['USER CALENDAR]/events?key=['API KEY']",
headers: {
Authorization: "Bearer " + result.accessToken,
Accept: "application/json",
},
})
.then((response) => {
const responseDataArray = [];
//RESPONSE DATA
response.data["items"].map((event) => {
if (typeof event["start"].dateTime !== undefined) {
responseDataArray.push(event);
}
//SET STATE TO RETREIVED AND FILTERED DATA STORED IN responseDataArray
setCalendarEvents(responseDataArray);
});
})
//CATCH ERRORS
.catch((error) => console.log(error));
} else {
return { cancelled: true };
}
} catch (e) {
return { error: true };
}
};
WHERE DATA SHOULD BE RENDERED ON THE SCREEN AFTER SUCCESSFUL GET
return (
<View>
{calendarEvents.map((event) => {
<View>{event}</View>
}
}
</View>
)
EXAMPLE OF RESPONSE DATA ITEM
I am looking to filter out "start":{"dateTime":"2021-04-16T17:30:00-04:00"} if it exists
{"kind":"calendar#event","etag":"\"3237003518996000\"","id":"7t1q67ai1p7t586peevd7s9mhg","status":"confirmed","htmlLink":"https://www.google.com/calendar/event?eid=N3QxcTY3YWkxcDd0NTg2cGVldmQ3czltaGcgbWF0dEBoZWFydGhkaXNwbGF5LmNvbQ","created":"2021-04-14T16:45:34.000Z","updated":"2021-04-15T15:49:19.498Z","summary":"customer journey beta buddies","creator":{"email":"meilin#hearthdisplay.com"},"organizer":{"email":"meilin#hearthdisplay.com"},"start":{"dateTime":"2021-04-16T17:30:00-04:00"},"end":{"dateTime":"2021-04-16T18:30:00-04:00"},"iCalUID":"7t1q67ai1p7t586peevd7s9mhg#google.com","sequence":0,"attendees":[{"email":"meilin#hearthdisplay.com","organizer":true,"responseStatus":"accepted"},{"email":"matt#hearthdisplay.com","self":true,"optional":true,"responseStatus":"accepted"},{"email":"susie#hearthdisplay.com","responseStatus":"accepted"},{"email":"nathalie#hearthdisplay.com","responseStatus":"accepted"}],"hangoutLink":"https://meet.google.com/xyb-qhpb-uej","conferenceData":{"entryPoints":[{"entryPointType":"video","uri":"https://meet.google.com/xyb-qhpb-uej","label":"meet.google.com/xyb-qhpb-uej"},{"entryPointType":"more","uri":"https://tel.meet/xyb-qhpb-uej?pin=3822838393771","pin":"3822838393771"},{"regionCode":"US","entryPointType":"phone","uri":"tel:+1-818-514-5197","label":"+1 818-514-5197","pin":"222000933"}],"conferenceSolution":{"key":{"type":"hangoutsMeet"},"name":"Google Meet","iconUri":"https://fonts.gstatic.com/s/i/productlogos/meet_2020q4/v6/web-512dp/logo_meet_2020q4_color_2x_web_512dp.png"},"conferenceId":"xyb-qhpb-uej","signature":"AGirE/Jmi4pFHkq0kcqgRyOuAR2r"},"reminders":{"useDefault":true},"eventType":"default"}
Maybe try with this, add conditional rendering :
return ({
calendarEvents.length>0 &&
calendarEvents?.map(...your code)
})
I have this functions to save and get data on it:
to save:
try {
const request = new Request('https://yandexmap-96969-default-rtdb.firebaseio.com/locations.json', {
method: 'post',
body: JSON.stringify(addNewLocation)
})
const response = await fetch(request)
window.location.reload()
return await response.json()
} catch (error) {
alert('Try again: ', error)
}
//to get:
try {
const request = new Request('https://yandexmap-96969-default-rtdb.firebaseio.com/locations.json', { method: 'get'})
const response = await fetch(request)
return await response.json()
} catch (error) {
alert('Try again: ', error)
}
And when I use "delete" instead of "get" it deletes the locations folder entirely, but when I use a link with a key at the end of the link, I get an error
You need make a DELETE request at the location you need to delete.
curl -X DELETE \
'https://[PROJECT_ID].firebaseio.com/locations.json'
const request = new Request('https://yandexmap-96969-default-rtdb.firebaseio.com/locations.json', { method: 'DELETE'})
const response = await fetch(request)
return await response.json()
I'm not sure about how your database structure looks like but the above request will delete the whole "locations" node. Here's an example:
If you want to delete only location2, then make a delete request at https://[PROJECT_ID].firebaseio.com/locations/location2.json
I'm not sure if there's any specific reason for you to use the REST API but you can try using Firebase Web SDK. It's easier to use, for example to delete location2:
firebase.database().ref("locations/location2").remove()
you can use the remove method
let userRef = this.database.ref('users/' + userId);
userRef.remove()
You can use the following code
deleteSomeData(id) {
fetch(
// don't add .json at [data Name]
`https://[your FireBase project url]/[data Name (don't add .json)]/${id}.json`,
{
method: 'Delete',
headers: {
'Content-Type': 'application/json',
},
}
)
.then((response) => {
if (response.ok) {
// if sucess do something
} else {
// if fail throw error
throw new Error('could not delete data');
}
})
.catch((error) => {
this.error = error.message;
console.log(id);
});
},
You can user item id to delete it like below.
const request = new Request('https://yandexmap-96969-default-rtdb.firebaseio.com/locations/<localtion_id>.json', { method: 'delete'})
your location id can be value like this, -MyB0qQoQuf9lPnwderfg
I am trying to add a custom header on all network requests going from application and I am trying to do this via service worker fetch.
The content of header needs to come from app(client), so I need to wait for a response from client before responding to any event.
Below is my attempt to achieve this
Here is my fetch listener code
function send_message_to_client(client, msg){
return new Promise(function(resolve, reject){
var msg_chan = new MessageChannel();
msg_chan.port1.onmessage = function(event){
if(event.data.error){
reject(event.data.error);
}else{
resolve(event.data);
}
};
client.postMessage("SW Says: '"+msg+"'", [msg_chan.port2]);
});
}
self.addEventListener('fetch', function (event) {
event.waitUntil(async function () {
const client = await clients.get(event.clientId);
send_message_to_client(client, "Pass Transaction Details")
.then(function (m) {
var req = new Request(event.request.url, {
method: event.request.method,
headers: event.request.headers,
mode: 'same-origin',
credentials: event.request.credentials,
redirect: 'manual'
});
var res_obj = JSON.parse(m);
req.headers.append('MY_CUSTOM_HEADER', res_obj.hdr_val);
return event.respondWith(fetch(req));
})
.catch(function (error) {
console.log("Error after event.respondWith call");
console.log(error);
});
}());
});
and here is how I registered this worker and its message listener
navigator.serviceWorker.register('/my-sw.js', {scope: '/'})
.then(function(reg) {
navigator.serviceWorker.onmessage = function (e) {
var msg_reply = {
"message" : "Replying to SW request",
};
msg_reply.hdr_val = sessionStorage.getItem('__data_val');
console.log("Replying with "+ JSON.stringify(msg_reply));
e.ports[0].postMessage(JSON.stringify(msg_reply));
};
}).catch(function(error) {
// registration failed
console.log('Registration failed with ' + error);
});
but apparently its shooting 2 requests, 1 original request and 1 with modified headers.
Any idea what am I doing wrong ? I am a newbie in javascript so pardon me if there is some stupid mistake.
From service worker debug console, I found that its going in catch block right after event.respondWith() call, so something wrong there probably ?
You must call FetchEvent.respondWith() synchronously in your fetch handler. In your code you are calling waitUntil() synchronously, but calling respondWith() later. By not calling respondWith() before returning from the fetch handler you are telling the browser to continue on with its normal networking path without interception.
I think you want something like this:
self.addEventListener('fetch', function (event) {
// call respondWith() here
event.respondWith(async function () {
const client = await clients.get(event.clientId);
send_message_to_client(client, "Pass Transaction Details")
.then(function (m) {
var req = new Request(event.request.url, {
method: event.request.method,
headers: event.request.headers,
mode: 'same-origin',
credentials: event.request.credentials,
redirect: 'manual'
});
var res_obj = JSON.parse(m);
req.headers.append('MY_CUSTOM_HEADER', res_obj.hdr_val);
// just return the response back to the respondWith() here
return fetch(req);
})
// You probably want to add a .catch() to return some reasonable fallback
// response.
i got a frisby function
createPOST = function () {
return frisby.post(url, {
body: qs.stringify({
username: data.user,
password: data.password
}),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then((resp) => {
let respJson = resp.json;
return respJson;
}, (error) => {
console.error("Error:: " + error);
throw error;
});
}
and second function
getRespJson = function () {
createToken().then(function (value) {
console.log("resp::"+value);
});
}
im trying to retrieve this json response in another function, but not able to using frisby. no log is even displaying
If your data coming in the body(that you are expecting) or anywhere, simply store into other variable and then by nested way you able to use it. if you have multiple nested body then in that situation you also able to use it.
I'm using the same with that workaround.
or try to use it by storing that into another file.
Thanks
I am working on my first Angular app, but am having a problem going an http.put call. Here is the function I call:
updateUser(columns, values) : Observable<boolean> | boolean {
const headers: Headers = new Headers(); // Need to set content type
headers.append('Content-Type', 'application/json; charset=utf-8');
headers.append('Authorization', `Bearer ${this.authenticationService.token}`);
const options = new RequestOptions({ headers: headers });console.log('test service');
return this.http.put(`${API_URL}users/${this.authenticationService.userId}`, JSON.stringify({ columns: columns, values: values }) , options)
.map((response: Response) => {
console.log('test service1');return Observable.of(true);
})
.catch(e => {
console.log('test service2');return Observable.of(false);
});
When I call the function test service prints to the console, but test service1 and test service2 never print out. I checked my express backend and chrome dev tools and the app is never making the put call to the backend. There are no errors in the console either. So I am missing something, but can't figure it out.
Thank you for any help
Edit: I'm wondering if the issue is because I am just calling this function in another function:
saveColumns(){
this.userService.updateUser('home_columns',this.columns_show);
localStorage.setItem('columns_show', JSON.stringify(this.columns_show) );
}
for http.get functions, I typically do something like this:
loadStudents(page: number, grade = []) {
if (grade.length != 0){
this.student_query_filter = { key:'grade_level',value:grade.join('||') };
} else {
this.student_query_filter = {};
}
this.studentService.getStudentsCount([{ key: 'last_name', value: this.student_search_filter },this.student_query_filter])
.subscribe(
total => this.total = total, //Assign returned student count to local property
err => { console.log(err); });
}
You want to pass the data as an object instead of with JSON.stringify.
You want to return the result from map, not another Observable. If you did want to return a different observable you should change map to switchMap.
The signature should be Observable<boolean> as that is what you are returning.
Be sure to check the developer console in your browser to see if the request is being sent and what the response is. It might be something simple like putting together the URL incorrectly (missing a / for example)
updateUser(columns, values) : Observable<boolean> {
const headers: Headers = new Headers(); // Need to set content type
headers.append('Content-Type', 'application/json; charset=utf-8');
headers.append('Authorization', `Bearer ${this.authenticationService.token}`);
const options = new RequestOptions({ headers: headers });
console.log('test service, sending to: ' + `${API_URL}users/${this.authenticationService.userId}`);
return this.http.put(`${API_URL}users/${this.authenticationService.userId}`, { columns: columns, values: values }, options)
.map((response: Response) => {
console.log('test service1');
return true;
})
.catch(e => {
console.log('test service2');
return false;
});
}
Edit
If your caller is not going to do anything with the result and you do not care what that result is then do not return an Observable at all. Change the return signature to void and execute a subscribe after the call to log the result.
this.http.put(`${API_URL}users/${this.authenticationService.userId}`, { columns: columns, values: values }, options)
.subscribe((response: Response) => {
console.log('test service1'); }
, e => {
console.log('test service2');
});