Display a js object from the console to the html page - fetch

I'm learning api and request with fetch. I'm a student.
I can't find why when i'm doing like my teacher, everything is going right, but when i have to adapt the code for my personnal working, it doen't work as i' m expecting ; lol...
I want to display on a web page my request result, i can get the array in my console but can't display it on my web page. Could someone help me to find a solution please.
Thank you ! Regards.
const url = 'https://reqres.in/api/users?page=2';
async function getUsers() {
const request = await fetch(url, {
method: 'GET',
});
if (!request.ok) {
alert("y'a une couille dans l'beurre!");
} else {
let datas = await request.json(); // on récupère les données en json et on en fait un objet js;
/* console.log(datas); */
document.querySelector('.users').textContent = datas.data[0];
console.log(datas.data);
}
// on va stocker fetch dans variable : const request;
//await veur dire qu'on va attendre fetch
}
getUsers();

by the way, you can't just display or inject an entire object of data into the textContent. datas.data[0] is an object of data. What you can do instead are:-
A. Just pick one data to be displayed
document.querySelector('.users').textContent = datas.data[0].email
B. Just inject entire new HTML
document.querySelector('.users').innerHTML = `
<h2>${datas.data[0].first_name} ${datas.data[0].last_name} (ID: ${datas.data[0].id})</h2>
<p>${datas.data[0].email}</p>
`
C. Inject all data available
datas?.data?.map((item) => {
let html = `
<h2>${item?.first_name} ${item?.last_name} (ID: ${item?.id})</h2>
<p>${item?.email}</p>
`;
document.querySelector(".users").insertAdjacentHTML("beforeend", html);
});
You can see a working example here: https://codesandbox.io/s/thirsty-hypatia-n3cpn?file=/src/index.js:484-722

Related

newbie question - firebase svelte-infinite-loading - unable to read new data from firestore

I'm trying to load db content on scroll down, but i'm getting errors because i don't know how to read correctly the data. Error shows that there is no data.hits, is undefined. What that means?
I used this sample: svelte-infinite-loading sample and tried to apply to work with firebase, but I don't know how to read the console.log(data), hits is undefined, but should it be?
Could someone help me?
ContentBlocks.svelte
<script>
import InfiniteLoading from "svelte-infinite-loading";
let page = 1;
function fetchData({ detail: { loaded, complete } }) {
const response = db
.collection("todos")
.orderBy("created", "desc")
.startAfter(page*5)
.limit(5);
response.get().then((data) => {
console.log(data)
if (data.hits.length) {
page += 1;
list = [...list, ...data.hits];
loaded();
} else {
complete();
}
});
}
</script>
<Box>
<InfiniteLoading on:infinite={fetchData} />
</Box>
is use async / await but that will still help you (also, your list variable is not declared anywhere we can see):
const results = await queryObj.get(); // queryObj == your response constant
if (results.docs) {
list.concat(results.docs.map((doc) => doc.data()));
}
doc is here, with another solution to that problem : https://firebase.google.com/docs/firestore/query-data/get-data#get_multiple_documents_from_a_collection

NextJS special characters routes do not work from browser

Using NextJS, I am defining some routes in getStaticPaths by making an API call:
/**
* #dev Fetches the article route and exports the title and id to define the available routes
*/
const getAllArticles = async () => {
const result = await fetch("https://some_api_url");
const articles = await result.json();
return articles.results.map((article) => {
const articleTitle = `${article.title}`;
return {
params: {
title: articleName,
id: `${article.id}`,
},
};
});
};
/**
* #dev Defines the paths available to reach directly
*/
export async function getStaticPaths() {
const paths = await getAllArticles();
return {
paths,
fallback: false,
};
}
Everything works most of the time: I can access most of the articles, Router.push works with all URLs defined.
However, when the article name includes a special character such as &, Router.push keeps working, but copy/pasting the URL that worked from inside the app to another tab returns a page:
An unexpected error has occurred.
In the Network tab of the inspector, a 404 get request error (in Network) appears.
The component code is mostly made of API calls such as:
await API.put(`/set_article/${article.id}`, { object });
With API being defined by axios.
Any idea why it happens and how to make the getStaticPaths work with special characters?
When you transport values in URLs, they need to be URL-encoded. (When you transport values in HTML, they need to be HTML encoded. In JSON, they need to be JSON-encoded. And so on. Any text-based system that can transport structured data has an encoding scheme that you need to apply to data. URLs are not an exception.)
Turn your raw values in your client code
await API.put(`/set_article/${article.id}`)
into encoded ones
await API.put(`/set_article/${encodeURIComponent(article.id)}`)
It might be tempting, but don't pre-encode the values on the server-side. Do this on the client end, at the time you actually use them in a URL.

Cloud vision api face detection no image present error

We are getting No image present. error while attempting face detection with the cloud vision api.
We are using code from the official documentation.
Please see the code below.
const request1={
"requests":[
{
"image":{
"content": imgdatauri //It contains image data uri
},
"features": [
{
"type":"FACE_DETECTION",
"maxResults":1
}
]
}
]
};
client
.annotateImage(request1)
.then(response => {
console.log(response);
response.send(response);
})
.catch(err => {
console.error(err);
response.send(err);
});
Here is the error message.
Error: No image present.
at _coerceRequest (/rbd/pnpm-volume/e40024d2-3d05-4f3d-a435-6d4e6ca96fb0/node_modules/.registry.npmjs.org/#google-cloud/vision/1.1.3/node_modules/#google-cloud/vision/src/helpers.js:69:21)
at ImageAnnotatorClient.<anonymous> (/rbd/pnpm-volume/e40024d2-3d05-4f3d-a435-6d4e6ca96fb0/node_modules/.registry.npmjs.org/#google-cloud/vision/1.1.3/node_modules/#google-cloud/vision/src/helpers.js:224:12)
at PromiseCtor (/rbd/pnpm-volume/e40024d2-3d05-4f3d-a435-6d4e6ca96fb0/node_modules/.registry.npmjs.org/#google-cloud/promisify/1.0.2/node_modules/#google-cloud/promisify/build/src/index.js:71:28)
at new Promise (<anonymous>)
at ImageAnnotatorClient.wrapper [as annotateImage] (/rbd/pnpm-volume/e40024d2-3d05-4f3d-a435-6d4e6ca96fb0/node_modules/.registry.npmjs.org/#google-cloud/promisify/1.0.2/node_modules/#google-cloud/promisify/build/src/index.js:56:16)
We would like to know what we need to do to resolve the issue.
Method 1:
In case of vision API, if image is stored locally you must convert that image to base64 string. Now this converted string is passed as value to content.
Make sure that you are converting image to base64 string and then passing to the content value.
There are some services available online to convert image to base64 string. You can also convert image to base64 by writing a piece of code. You can find services online and select anyone them. I am providing link to one service.
https://www.browserling.com/tools/image-to-base64
Method 2:
You can provide public url of image to vision API.
{
"requests":[
{
"image":{
"source":{
"imageUri": PUBLIC_URL
}
},
"features":[
{
"type":TYPE_OF_DETECTION,
"maxResults":MAX_NUMBER_OF_RESULTS
}
]
}
]
}
Method 3:
You can create bucket and put image there.
Now you can provide this image object URL or path.
I think this will help you.
Thank you.
I have created a Cloud Function with Cloud Storage Trigger, my function gets triggered ( with event ) when I upload an image file I can see there is event.mediaLink event.selfLink, I tried using both to load image, but it keeps complaining about No Image being present
here is the code
exports.analyzeImage = function(event) {
const vision = require('#google-cloud/vision');
const client = new vision.ImageAnnotatorClient();
console.log('Event', event.mediaLink)
let image = {
source: {imageUri: event.mediaLink}
};
return client.labelDetection(image).then(resp => {
let labels = resp[0].labelAnnotations.map( l => {
return {
description: l.description,
score: l.score
};
});
return labels;
// const dataset = bigquery.dataset('dataset')
// return dataset.table
}).catch(err => {
console.error(err)
})
}

Angular 4 and ASP.Net MVC 5 : returns an Empty JSON in response

after merging angular app with asp.net MVC calling API from angular returns an empty JSON.
The angular and asp.net are in the same domain.
If I call the API With PostMan, I have a JSON with the result. but if I call it in the angular app my JSON result is empty.
Are there any tips for communicating angular app with asp.net MVC after merging and serving in the same domain?
Update 1:
The code that used to calling Webservice:
getSheets(): Observable<Sheet[]> {
return this.http.get(this.config.apiUrl + '/api/SheetsRelationAPI',
this.jwt())
.map(this.extractData)
.do(data => console.log('SheetsData:', data)) // debug
.catch(this.handleError);
}
/**
* Handle HTTP error
*/
private handleError(error: any) {
// In a real world app, we might use a remote logging infrastructure
// We'd also dig deeper into the error to get a better message
const errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error(errMsg); // log to console instead
return Observable.throw(errMsg);
}
// private helper methods
private jwt() {
// create authorization header with jwt token
const currentUser = JSON.parse(atob(this.cookie.getCookie('currentUser')));
if (currentUser && currentUser.access_token) {
const headers = new Headers({ 'Authorization': 'Bearer ' + currentUser.access_token},
);
return new RequestOptions({ headers: headers });
}
}
private extractData(res: Response) {
const body = res.json();
return body || [];
}
Update 2:
I notice that my API if I called it from outside domain it respond 2 times:
inspecting network with google chrome inspect element:
the first response is "zone.js" initiator and the second response is an "other" initiator
If I call the API from inside of the Domain I just have a response from "zone.js" initiator and it returns an empty JSON.
Update 3
export class OtherComponent implements OnInit {
sheets: Sheet[] = [];
errorMessage: string;
constructor(private httpService: HttpService) {
// this.sheets = this.ichartHttp.getSheets();
// console.log(this.sheets);
}
getSheets() {
this.httpService.getSheets()
.subscribe(
sheets => this.sheets = sheets,
error => this.errorMessage = <any>error
);
}
ngOnInit() {
this.getSheets();
}
}
The Problem is with my Authentication methods,
I use two types of authentication, MVC and WebAPI they conflict if I send a request to API under the same Domain.
So my Answer is: Your Angular Code looks good, take a look at your middleware project

HTTP GET and POST, how to implement in Angular 2 to be able to list, add and remove objects

Okay, so I am new to working with HTTP and actually getting some data from the server. Been sifting through a lot of tutorials, examples and questions asked here, but I am not finding what I want. All tutorials I've found only shows how to retrieve and add some data.
So based on those examples I've managed to retrieve data:
service:
getCases(){
return this.http.get('someUrl');
}
Case component constructor:
this._service.getCases()
.map((res: Response) => res.json())
.subscribe(cases => this.cases = cases);
Adding cases
service:
public saveCase(case: case) {
let body = JSON.stringify(case);
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.post('someUrl', body, options)
.map(this.extractData)
.catch(this.handleError)
.subscribe(case => this.cases.push(case));
}
Case Component:
saveCase() {
let case = new Case(this.id, this.name, this.date)
this._service.saveCase(case);
this.name = '';
}
Okay, so I have and Array "Cases" which contains Case objects. Getting the data from the server displays the cases like I want them to. When I add a new case it gets sent to the server, but how do I get the Array updated when I add a new Case. Because now the new case appears only after I refresh the browser.
Second question is that the user can click a case and it then routes to a detail list where the user can add steps and feedback. If it matters, case has the attributes id, name, date and an array of steps, at this point the array is empty. The step object is it's own class and the object contains an array of feedback. Feedback is also an own class and the object has two attributes, which are both strings. So it's all nested. When I click the case, it does route to the detail page, but there the case name should be printed and it doesn't. It also shows my button for adding steps, but it does nothing. Obviously I'm missing something in my methods, but I have no clue to as what to do. As a comment I can say that before adding the http in my code it all worked as it should. Here are the methods, that are probably missing something:
Case Component:
gotoDetail(case: Case) {
this._router.navigate(['CaseDetail', {"id": case.name}]);
}
Service:
public getById(id: string): Case {
for (let case of this.cases) {
if (case.id === id) {
return case;
}
}
return null;
}
Then there is the matter of syntax for removing cases, haven't found an example that works for me yet, I've tried a bunch... among others the example links provided by #shershen below. None works. The original methods I have, that should be changed to work with http:
Component:
removeSearchCase(case: Case) {
this._service.removeCase(case);
}
Service:
public removeCase(value: Case): void {
let index = this.cases.indexOf(value);
this.cases.splice(index, 1);
}
So the case removal is with post.
And about the backend I can say as much that I only have the following three posts and gets:
getCases (GET), saveCase (also works as updating the case)(POST) and removeCase (POST).
It's hard to debug without sample demo, however the descriptions quite detailed. I am adding some points that may fix the problem while improving the code structure:
First, you should move the request subscription/observing into the service methods; that will encapsulate the request handling logic in service layer:
//service.ts
#Injectable()
export class service {
getCases(){
if (!this.request) {
this.request = this.http.get('/assets/data.json')
.map((response: Response) => response.json())
.map((data: string[]) => {
this.request = null;
return this.names = data;
});
}
return this.request;
}
}
Second, you need to create an instance of your service in your Component's constructor instead of using it as a static method of the service:
//component.ts
import {MyService} from 'PATH_TO_YOUR_SERVICE';
class CaseComponent {
constructor(private _service : MyService){
//other stuff..
}
getData(){
this._service.getCases()
}
}
Additional references:
Official "Getting and Saving Data with HTTP"
Service example with Observables (with Firebase, but still)
Simple service in Angular2 seed project
I think you should put your cases Array in the CaseComponent:
case.component.ts:
cases: Case[];
constructor(private caseService: CaseService){}
getCases() {
this.caseService.getCases()
.subscribe(cases => this.cases = cases);
}
saveCase() {
let case = new Case(this.id, this.name, this.date);
this.caseService.saveCase(case)
.subscribe(case => this.cases = [...this.cases, case]);
}
case.service.ts:
getCases() {
return this.http.get(this.casesUrl)
.map(this.extractData)
.catch(this.handleError);
}
saveCase (case: Case) {
let body = JSON.stringify({ case });
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.post(this.casesUrl, body, options)
.map(this.extractData)
.catch(this.handleError);
}
Then try to change "name" to "id" in gotoDetail:
gotoDetail(case: Case) {
this._router.navigate(['CaseDetail', {"id": case.id}]);
}

Resources