HTTP Client, can't fetch data from API (cannot communicate between service and component)
I am trying to integrate the Angular HTTP Client to my simple angular CRUD App. I want the app to generate a picture of a dog (taken from an API) and to display it in the browser. Each picture has a set of properties (text, id, date, URL). Everything works fine except I cannot fetch the data (for the URL) from an API (it works if I provide the URL for the images as hard coded data, but I want dynamically added data from the API). The API does not require any authentication, it's free and the fetch request works, I think I am not doing something right. The API is this:
https://dog.ceo/dog-api/
and I am fetching from this link
https://dog.ceo/api/breeds/image/random;
The request returns an object with a status and a message (in the message is the link and I want to pass that link as an URL property to the image component). The Images' properties are being initialized through the form component.
I am using angular 7 and am on a windows 8 machine, I also have the following setup in my app:
-a service
-form component
-images component
-I also have an interface for the image which is imported in both form/image components and in the service but I can t seem to make it work.
//Here's my code so far:
//Interface (image.ts)
export interface Image {
id: string;
text: string;
url: string;
date: any;
}
//Service (image-service.ts)
import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs";
import { Observable } from "rxjs";
import { of } from "rxjs";
import { Image } from "../models/Image";
import { HttpClient, HttpHeaders } from "@angular/common/http";
@Injectable({
providedIn: "root"
})
export class ImageService {
images: Image;
private imageSource = new BehaviorSubject<Image>({
id: null,
text: null,
url: null,
date: null
});
selectedImage = this.imageSource.asObservable();
imageUrl: string = "https://dog.ceo/api/breeds/image/random";
constructor(private http: HttpClient) {
this.images = [
{
id: "1",
text: "Generated Pet 1",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("10/25/2017 12:54:32")
},
{
id: "2",
text: "Generated Pet 2",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("12/26/2017 12:58:33")
},
{
id: "3",
text: "Generated Pet 3",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("12/28/2017 12:59:30")
}
];
}
getImages(): Observable<Image> {
return of(this.images);
}
setFormImage(image: Image) {
this.imageSource.next(image);
}
addImage(image: Image) {
this.images.unshift(image);
}
//I have to modify this function but I can't seem to manage T__T
getUrl(): Observable<any> {
return this.http.get(this.imageUrl);
}
}
//Images component (images-component.ts)
import { Component, OnInit } from "@angular/core";
//import interface/model
import { Image } from "../../models/Image";
//import service
import { ImageService } from "../../services/image.service";
@Component({
selector: "app-images",
templateUrl: "./images.component.html",
styleUrls: ["./images.component.css"]
})
export class ImagesComponent implements OnInit {
images: Image;
//inject service as dependency into the constructor;
constructor(private imageService: ImageService) {}
ngOnInit() {
this.imageService.getImages().subscribe(images => {
this.images = images;
});
}
onSelect(image: Image) {
this.imageService.setFormImage(image);
}
}
//Form component (img-form-component.ts)
import { Component, OnInit } from "@angular/core";
import { Image } from "../../models/Image";
//import service
import { ImageService } from "../../services/image.service";
import { getUrlScheme } from "@angular/compiler";
import { Observable } from "rxjs";
import { of } from "rxjs";
import { HttpClient, HttpHeaders } from "@angular/common/http";
@Component({
selector: "app-img-form",
templateUrl: "./img-form.component.html",
styleUrls: ["./img-form.component.css"]
})
export class ImgFormComponent implements OnInit {
id: string;
text: string;
url: string;
date: any;
isNew: boolean = true;
constructor(private imageService: ImageService) {}
ngOnInit() {
//subscribe to selectedImage observable
this.imageService.selectedImage.subscribe(image => {
if (image.id !== null) {
this.isNew = false;
this.id = image.id;
this.text = image.text;
this.url = image.url;
this.date = image.date;
}
});
}
onSubmit() {
//check if new image
if (this.isNew) {
//create new image
const newImg = {
id: this.generateId(),
text: this.text,
date: new Date(),
url: this.generateUrl()
};
//add the image
this.imageService.addImage(newImg);
} else {
//create image to be updated
const updImg = {
id: this.id,
text: this.text,
date: new Date(),
url: this.url
};
//update image
// this.imageService.updateImage(updImg);
}
}
generateId() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
generateUrl() {
let url = this.imageService.getUrl();
return url;
}
}
/*Please let me know If I explained throughly enough the issue, and sorry if I seem clumsy and explaining, I am fairly new to Angular and am trying to learn it. This app is part of the process.
Thanks
*/
Thanks Chau Tran for your answer, however it's not working for my issue, or I am not implementing it right. Here's what I tried:
//*function in the service*
getUrl(): Observable<any> {
return this.http.get(this.imageUrl);
}
// * functions in the form component*
generateUrl() {
return this.imageService.getUrl().toPromise();
}
// *image instantiation*
const newImg = {
id: this.generateId(),
text: this.text,
date: new Date(),
url: await this.generateUrl()
}
If I try like this I get the following errors:
Module parse failed: The keyword 'yield' is reserved (33:21)
You may need an appropriate loader to handle this file type.
| text: this.text,
| date: new Date(),
url: yield this.generateUrl()
| //this.generateUrl()
| };
'await' expression is only allowed within an async
function
What does it mean 'appropriate loader to handle this file type' ? And what 'file type'? I m lost here. Also, can I make the onSubmit()
in the constructor asynchronous? How would an implementation of that look (solving my url
issue as well).
I also tried to modify the generateUrl()
so as to subscribe to the getUrl()
observable in the service but I am either not subscribing 'correctly' or something else is 'off':
I also tried like this (as if to subscribe to the observable getUrl()
in the service, if I'm doing something wrong, someone please point it out, I can't figure it out myself:
generateUrl() {
let url = this.imageService.getUrl().subscribe(response => {
return response;
let url = response[1];
return url;
});
console.log(url);
return url;
}
I put `url` = response[1] because that's how the response is formatted in the dog API. So, what am I doing wrongly, can someone please explain this to me ? Thanks
As Chau Tran suggested, I will include a bit more code maybe this can help someone figure what I can't on my own:
Here's my app.component.ts:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'dogapp';
}
Here's my package.json:
{
"name": "dogapp",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "~7.1.0",
"@angular/common": "~7.1.0",
"@angular/compiler": "~7.1.0",
"@angular/core": "~7.1.0",
"@angular/forms": "~7.1.0",
"@angular/platform-browser": "~7.1.0",
"@angular/platform-browser-dynamic": "~7.1.0",
"@angular/router": "~7.1.0",
"bootstrap": "4.0.0-beta.2",
"core-js": "^2.5.4",
"font-awesome": "^4.7.0",
"jquery": "^3.3.1",
"popper.js": "^1.14.6",
"rxjs": "~6.3.3",
"tslib": "^1.9.0",
"zone.js": "~0.8.26"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.11.0",
"@angular/cli": "~7.1.4",
"@angular/compiler-cli": "~7.1.0",
"@angular/language-service": "~7.1.0",
"@types/node": "~8.9.4",
"@types/jasmine": "~2.8.8",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "~4.5.0",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~3.1.1",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~1.1.2",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.11.0",
"typescript": "~3.1.6"
}
}
Here's my image-service.ts:
import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs";
import { Observable } from "rxjs";
import { of } from "rxjs";
import { Image } from "../models/Image";
import { HttpClient, HttpHeaders } from "@angular/common/http";
@Injectable({
providedIn: "root"
})
export class ImageService {
images: Image;
private imageSource = new BehaviorSubject<Image>({
id: null,
text: null,
url: null,
date: null
});
selectedImage = this.imageSource.asObservable();
imageUrl: string = "https://dog.ceo/api/breeds/image/random";
constructor(private http: HttpClient) {
this.images = [
{
id: "1",
text: "Generated Pet 1",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("10/25/2017 12:54:32")
},
{
id: "2",
text: "Generated Pet 2",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("12/26/2017 12:58:33")
},
{
id: "3",
text: "Generated Pet 3",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("12/28/2017 12:59:30")
}
];
}
getImages(): Observable<Image> {
return of(this.images);
}
setFormImage(image: Image) {
this.imageSource.next(image);
}
addImage(image: Image) {
this.images.unshift(image);
}
getUrl(): Observable<any> {
return this.http.get(this.imageUrl);
}
}
Here's my images.component.ts:
import { Component, OnInit } from "@angular/core";
//import interface/model
import { Image } from "../../models/Image";
//import service
import { ImageService } from "../../services/image.service";
@Component({
selector: "app-images",
templateUrl: "./images.component.html",
styleUrls: ["./images.component.css"]
})
export class ImagesComponent implements OnInit {
images: Image;
//inject service as dependency into the constructor;
constructor(private imageService: ImageService) {}
ngOnInit() {
this.imageService.getImages().subscribe(images => {
this.images = images;
});
}
onSelect(image: Image) {
this.imageService.setFormImage(image);
}
}
Here's my image-form.component.ts:
import { Component, OnInit } from "@angular/core";
import { Image } from "../../models/Image";
//import service
import { ImageService } from "../../services/image.service";
import { getUrlScheme } from "@angular/compiler";
import { Observable } from "rxjs";
import { of } from "rxjs";
import { HttpClient, HttpHeaders } from "@angular/common/http";
@Component({
selector: "app-img-form",
templateUrl: "./img-form.component.html",
styleUrls: ["./img-form.component.css"]
})
export class ImgFormComponent implements OnInit {
id: string;
text: string;
url: string;
date: any;
isNew: boolean = true;
//imageUrl: string = "https://dog.ceo/api/breeds/image/random";
constructor(private imageService: ImageService) {}
ngOnInit() {
//subscribe to selectedImage observable
this.imageService.selectedImage.subscribe(image => {
if (image.id !== null) {
this.isNew = false;
this.id = image.id;
this.text = image.text;
this.url = image.url;
this.date = image.date;
}
});
//this.imageService.getUrl.subscribe(url => (this.url = url));
}
onSubmit() {
//check if new image
if (this.isNew) {
//create new image
const newImg = {
id: this.generateId(),
text: this.text,
date: new Date(),
url: this.generateUrl()
};
//add the image
this.imageService.addImage(newImg);
} else {
//create image to be updated
const updImg = {
id: this.id,
text: this.text,
date: new Date(),
url: this.url
};
//update image
// this.imageService.updateImage(updImg);
}
}
generateId() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
generateUrl() {
let url = this.imageService.getUrl().subscribe(response => {
return response;
let url = response[1];
return url;
});
console.log(url);
return url;
}
}
Here's my interface:
export interface Image {
id: string;
text: string;
url: string;
date: any;
}
I cannot manage to make a get request to the dog API (https://dog.ceo/dog-api/) to fetch a URL and pass it as a property to each image, once it is being instantiated (data for each image instantiation is being initialized in the image-form component.ts). Thanks for any help =).
service observable angular7 angular-httpclient
add a comment |
I am trying to integrate the Angular HTTP Client to my simple angular CRUD App. I want the app to generate a picture of a dog (taken from an API) and to display it in the browser. Each picture has a set of properties (text, id, date, URL). Everything works fine except I cannot fetch the data (for the URL) from an API (it works if I provide the URL for the images as hard coded data, but I want dynamically added data from the API). The API does not require any authentication, it's free and the fetch request works, I think I am not doing something right. The API is this:
https://dog.ceo/dog-api/
and I am fetching from this link
https://dog.ceo/api/breeds/image/random;
The request returns an object with a status and a message (in the message is the link and I want to pass that link as an URL property to the image component). The Images' properties are being initialized through the form component.
I am using angular 7 and am on a windows 8 machine, I also have the following setup in my app:
-a service
-form component
-images component
-I also have an interface for the image which is imported in both form/image components and in the service but I can t seem to make it work.
//Here's my code so far:
//Interface (image.ts)
export interface Image {
id: string;
text: string;
url: string;
date: any;
}
//Service (image-service.ts)
import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs";
import { Observable } from "rxjs";
import { of } from "rxjs";
import { Image } from "../models/Image";
import { HttpClient, HttpHeaders } from "@angular/common/http";
@Injectable({
providedIn: "root"
})
export class ImageService {
images: Image;
private imageSource = new BehaviorSubject<Image>({
id: null,
text: null,
url: null,
date: null
});
selectedImage = this.imageSource.asObservable();
imageUrl: string = "https://dog.ceo/api/breeds/image/random";
constructor(private http: HttpClient) {
this.images = [
{
id: "1",
text: "Generated Pet 1",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("10/25/2017 12:54:32")
},
{
id: "2",
text: "Generated Pet 2",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("12/26/2017 12:58:33")
},
{
id: "3",
text: "Generated Pet 3",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("12/28/2017 12:59:30")
}
];
}
getImages(): Observable<Image> {
return of(this.images);
}
setFormImage(image: Image) {
this.imageSource.next(image);
}
addImage(image: Image) {
this.images.unshift(image);
}
//I have to modify this function but I can't seem to manage T__T
getUrl(): Observable<any> {
return this.http.get(this.imageUrl);
}
}
//Images component (images-component.ts)
import { Component, OnInit } from "@angular/core";
//import interface/model
import { Image } from "../../models/Image";
//import service
import { ImageService } from "../../services/image.service";
@Component({
selector: "app-images",
templateUrl: "./images.component.html",
styleUrls: ["./images.component.css"]
})
export class ImagesComponent implements OnInit {
images: Image;
//inject service as dependency into the constructor;
constructor(private imageService: ImageService) {}
ngOnInit() {
this.imageService.getImages().subscribe(images => {
this.images = images;
});
}
onSelect(image: Image) {
this.imageService.setFormImage(image);
}
}
//Form component (img-form-component.ts)
import { Component, OnInit } from "@angular/core";
import { Image } from "../../models/Image";
//import service
import { ImageService } from "../../services/image.service";
import { getUrlScheme } from "@angular/compiler";
import { Observable } from "rxjs";
import { of } from "rxjs";
import { HttpClient, HttpHeaders } from "@angular/common/http";
@Component({
selector: "app-img-form",
templateUrl: "./img-form.component.html",
styleUrls: ["./img-form.component.css"]
})
export class ImgFormComponent implements OnInit {
id: string;
text: string;
url: string;
date: any;
isNew: boolean = true;
constructor(private imageService: ImageService) {}
ngOnInit() {
//subscribe to selectedImage observable
this.imageService.selectedImage.subscribe(image => {
if (image.id !== null) {
this.isNew = false;
this.id = image.id;
this.text = image.text;
this.url = image.url;
this.date = image.date;
}
});
}
onSubmit() {
//check if new image
if (this.isNew) {
//create new image
const newImg = {
id: this.generateId(),
text: this.text,
date: new Date(),
url: this.generateUrl()
};
//add the image
this.imageService.addImage(newImg);
} else {
//create image to be updated
const updImg = {
id: this.id,
text: this.text,
date: new Date(),
url: this.url
};
//update image
// this.imageService.updateImage(updImg);
}
}
generateId() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
generateUrl() {
let url = this.imageService.getUrl();
return url;
}
}
/*Please let me know If I explained throughly enough the issue, and sorry if I seem clumsy and explaining, I am fairly new to Angular and am trying to learn it. This app is part of the process.
Thanks
*/
Thanks Chau Tran for your answer, however it's not working for my issue, or I am not implementing it right. Here's what I tried:
//*function in the service*
getUrl(): Observable<any> {
return this.http.get(this.imageUrl);
}
// * functions in the form component*
generateUrl() {
return this.imageService.getUrl().toPromise();
}
// *image instantiation*
const newImg = {
id: this.generateId(),
text: this.text,
date: new Date(),
url: await this.generateUrl()
}
If I try like this I get the following errors:
Module parse failed: The keyword 'yield' is reserved (33:21)
You may need an appropriate loader to handle this file type.
| text: this.text,
| date: new Date(),
url: yield this.generateUrl()
| //this.generateUrl()
| };
'await' expression is only allowed within an async
function
What does it mean 'appropriate loader to handle this file type' ? And what 'file type'? I m lost here. Also, can I make the onSubmit()
in the constructor asynchronous? How would an implementation of that look (solving my url
issue as well).
I also tried to modify the generateUrl()
so as to subscribe to the getUrl()
observable in the service but I am either not subscribing 'correctly' or something else is 'off':
I also tried like this (as if to subscribe to the observable getUrl()
in the service, if I'm doing something wrong, someone please point it out, I can't figure it out myself:
generateUrl() {
let url = this.imageService.getUrl().subscribe(response => {
return response;
let url = response[1];
return url;
});
console.log(url);
return url;
}
I put `url` = response[1] because that's how the response is formatted in the dog API. So, what am I doing wrongly, can someone please explain this to me ? Thanks
As Chau Tran suggested, I will include a bit more code maybe this can help someone figure what I can't on my own:
Here's my app.component.ts:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'dogapp';
}
Here's my package.json:
{
"name": "dogapp",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "~7.1.0",
"@angular/common": "~7.1.0",
"@angular/compiler": "~7.1.0",
"@angular/core": "~7.1.0",
"@angular/forms": "~7.1.0",
"@angular/platform-browser": "~7.1.0",
"@angular/platform-browser-dynamic": "~7.1.0",
"@angular/router": "~7.1.0",
"bootstrap": "4.0.0-beta.2",
"core-js": "^2.5.4",
"font-awesome": "^4.7.0",
"jquery": "^3.3.1",
"popper.js": "^1.14.6",
"rxjs": "~6.3.3",
"tslib": "^1.9.0",
"zone.js": "~0.8.26"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.11.0",
"@angular/cli": "~7.1.4",
"@angular/compiler-cli": "~7.1.0",
"@angular/language-service": "~7.1.0",
"@types/node": "~8.9.4",
"@types/jasmine": "~2.8.8",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "~4.5.0",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~3.1.1",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~1.1.2",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.11.0",
"typescript": "~3.1.6"
}
}
Here's my image-service.ts:
import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs";
import { Observable } from "rxjs";
import { of } from "rxjs";
import { Image } from "../models/Image";
import { HttpClient, HttpHeaders } from "@angular/common/http";
@Injectable({
providedIn: "root"
})
export class ImageService {
images: Image;
private imageSource = new BehaviorSubject<Image>({
id: null,
text: null,
url: null,
date: null
});
selectedImage = this.imageSource.asObservable();
imageUrl: string = "https://dog.ceo/api/breeds/image/random";
constructor(private http: HttpClient) {
this.images = [
{
id: "1",
text: "Generated Pet 1",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("10/25/2017 12:54:32")
},
{
id: "2",
text: "Generated Pet 2",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("12/26/2017 12:58:33")
},
{
id: "3",
text: "Generated Pet 3",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("12/28/2017 12:59:30")
}
];
}
getImages(): Observable<Image> {
return of(this.images);
}
setFormImage(image: Image) {
this.imageSource.next(image);
}
addImage(image: Image) {
this.images.unshift(image);
}
getUrl(): Observable<any> {
return this.http.get(this.imageUrl);
}
}
Here's my images.component.ts:
import { Component, OnInit } from "@angular/core";
//import interface/model
import { Image } from "../../models/Image";
//import service
import { ImageService } from "../../services/image.service";
@Component({
selector: "app-images",
templateUrl: "./images.component.html",
styleUrls: ["./images.component.css"]
})
export class ImagesComponent implements OnInit {
images: Image;
//inject service as dependency into the constructor;
constructor(private imageService: ImageService) {}
ngOnInit() {
this.imageService.getImages().subscribe(images => {
this.images = images;
});
}
onSelect(image: Image) {
this.imageService.setFormImage(image);
}
}
Here's my image-form.component.ts:
import { Component, OnInit } from "@angular/core";
import { Image } from "../../models/Image";
//import service
import { ImageService } from "../../services/image.service";
import { getUrlScheme } from "@angular/compiler";
import { Observable } from "rxjs";
import { of } from "rxjs";
import { HttpClient, HttpHeaders } from "@angular/common/http";
@Component({
selector: "app-img-form",
templateUrl: "./img-form.component.html",
styleUrls: ["./img-form.component.css"]
})
export class ImgFormComponent implements OnInit {
id: string;
text: string;
url: string;
date: any;
isNew: boolean = true;
//imageUrl: string = "https://dog.ceo/api/breeds/image/random";
constructor(private imageService: ImageService) {}
ngOnInit() {
//subscribe to selectedImage observable
this.imageService.selectedImage.subscribe(image => {
if (image.id !== null) {
this.isNew = false;
this.id = image.id;
this.text = image.text;
this.url = image.url;
this.date = image.date;
}
});
//this.imageService.getUrl.subscribe(url => (this.url = url));
}
onSubmit() {
//check if new image
if (this.isNew) {
//create new image
const newImg = {
id: this.generateId(),
text: this.text,
date: new Date(),
url: this.generateUrl()
};
//add the image
this.imageService.addImage(newImg);
} else {
//create image to be updated
const updImg = {
id: this.id,
text: this.text,
date: new Date(),
url: this.url
};
//update image
// this.imageService.updateImage(updImg);
}
}
generateId() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
generateUrl() {
let url = this.imageService.getUrl().subscribe(response => {
return response;
let url = response[1];
return url;
});
console.log(url);
return url;
}
}
Here's my interface:
export interface Image {
id: string;
text: string;
url: string;
date: any;
}
I cannot manage to make a get request to the dog API (https://dog.ceo/dog-api/) to fetch a URL and pass it as a property to each image, once it is being instantiated (data for each image instantiation is being initialized in the image-form component.ts). Thanks for any help =).
service observable angular7 angular-httpclient
-I call the getUrl() method from the service in generateUrl() in the form component and pass that as a param in the onSubmit() in the form component, but it does not work (I get a 404 status); So I think I am not performing the fetch request through the http client as I should. -The only way this works is if I define the url as hard-coded data either in getUrl() -in the service or in generateUrl() in the form component and return it, but I want the service to return a dynamically 'fetched' url from the dog API (dog.ceo/dog-api)
– Dragos
Jan 1 at 10:32
add a comment |
I am trying to integrate the Angular HTTP Client to my simple angular CRUD App. I want the app to generate a picture of a dog (taken from an API) and to display it in the browser. Each picture has a set of properties (text, id, date, URL). Everything works fine except I cannot fetch the data (for the URL) from an API (it works if I provide the URL for the images as hard coded data, but I want dynamically added data from the API). The API does not require any authentication, it's free and the fetch request works, I think I am not doing something right. The API is this:
https://dog.ceo/dog-api/
and I am fetching from this link
https://dog.ceo/api/breeds/image/random;
The request returns an object with a status and a message (in the message is the link and I want to pass that link as an URL property to the image component). The Images' properties are being initialized through the form component.
I am using angular 7 and am on a windows 8 machine, I also have the following setup in my app:
-a service
-form component
-images component
-I also have an interface for the image which is imported in both form/image components and in the service but I can t seem to make it work.
//Here's my code so far:
//Interface (image.ts)
export interface Image {
id: string;
text: string;
url: string;
date: any;
}
//Service (image-service.ts)
import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs";
import { Observable } from "rxjs";
import { of } from "rxjs";
import { Image } from "../models/Image";
import { HttpClient, HttpHeaders } from "@angular/common/http";
@Injectable({
providedIn: "root"
})
export class ImageService {
images: Image;
private imageSource = new BehaviorSubject<Image>({
id: null,
text: null,
url: null,
date: null
});
selectedImage = this.imageSource.asObservable();
imageUrl: string = "https://dog.ceo/api/breeds/image/random";
constructor(private http: HttpClient) {
this.images = [
{
id: "1",
text: "Generated Pet 1",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("10/25/2017 12:54:32")
},
{
id: "2",
text: "Generated Pet 2",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("12/26/2017 12:58:33")
},
{
id: "3",
text: "Generated Pet 3",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("12/28/2017 12:59:30")
}
];
}
getImages(): Observable<Image> {
return of(this.images);
}
setFormImage(image: Image) {
this.imageSource.next(image);
}
addImage(image: Image) {
this.images.unshift(image);
}
//I have to modify this function but I can't seem to manage T__T
getUrl(): Observable<any> {
return this.http.get(this.imageUrl);
}
}
//Images component (images-component.ts)
import { Component, OnInit } from "@angular/core";
//import interface/model
import { Image } from "../../models/Image";
//import service
import { ImageService } from "../../services/image.service";
@Component({
selector: "app-images",
templateUrl: "./images.component.html",
styleUrls: ["./images.component.css"]
})
export class ImagesComponent implements OnInit {
images: Image;
//inject service as dependency into the constructor;
constructor(private imageService: ImageService) {}
ngOnInit() {
this.imageService.getImages().subscribe(images => {
this.images = images;
});
}
onSelect(image: Image) {
this.imageService.setFormImage(image);
}
}
//Form component (img-form-component.ts)
import { Component, OnInit } from "@angular/core";
import { Image } from "../../models/Image";
//import service
import { ImageService } from "../../services/image.service";
import { getUrlScheme } from "@angular/compiler";
import { Observable } from "rxjs";
import { of } from "rxjs";
import { HttpClient, HttpHeaders } from "@angular/common/http";
@Component({
selector: "app-img-form",
templateUrl: "./img-form.component.html",
styleUrls: ["./img-form.component.css"]
})
export class ImgFormComponent implements OnInit {
id: string;
text: string;
url: string;
date: any;
isNew: boolean = true;
constructor(private imageService: ImageService) {}
ngOnInit() {
//subscribe to selectedImage observable
this.imageService.selectedImage.subscribe(image => {
if (image.id !== null) {
this.isNew = false;
this.id = image.id;
this.text = image.text;
this.url = image.url;
this.date = image.date;
}
});
}
onSubmit() {
//check if new image
if (this.isNew) {
//create new image
const newImg = {
id: this.generateId(),
text: this.text,
date: new Date(),
url: this.generateUrl()
};
//add the image
this.imageService.addImage(newImg);
} else {
//create image to be updated
const updImg = {
id: this.id,
text: this.text,
date: new Date(),
url: this.url
};
//update image
// this.imageService.updateImage(updImg);
}
}
generateId() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
generateUrl() {
let url = this.imageService.getUrl();
return url;
}
}
/*Please let me know If I explained throughly enough the issue, and sorry if I seem clumsy and explaining, I am fairly new to Angular and am trying to learn it. This app is part of the process.
Thanks
*/
Thanks Chau Tran for your answer, however it's not working for my issue, or I am not implementing it right. Here's what I tried:
//*function in the service*
getUrl(): Observable<any> {
return this.http.get(this.imageUrl);
}
// * functions in the form component*
generateUrl() {
return this.imageService.getUrl().toPromise();
}
// *image instantiation*
const newImg = {
id: this.generateId(),
text: this.text,
date: new Date(),
url: await this.generateUrl()
}
If I try like this I get the following errors:
Module parse failed: The keyword 'yield' is reserved (33:21)
You may need an appropriate loader to handle this file type.
| text: this.text,
| date: new Date(),
url: yield this.generateUrl()
| //this.generateUrl()
| };
'await' expression is only allowed within an async
function
What does it mean 'appropriate loader to handle this file type' ? And what 'file type'? I m lost here. Also, can I make the onSubmit()
in the constructor asynchronous? How would an implementation of that look (solving my url
issue as well).
I also tried to modify the generateUrl()
so as to subscribe to the getUrl()
observable in the service but I am either not subscribing 'correctly' or something else is 'off':
I also tried like this (as if to subscribe to the observable getUrl()
in the service, if I'm doing something wrong, someone please point it out, I can't figure it out myself:
generateUrl() {
let url = this.imageService.getUrl().subscribe(response => {
return response;
let url = response[1];
return url;
});
console.log(url);
return url;
}
I put `url` = response[1] because that's how the response is formatted in the dog API. So, what am I doing wrongly, can someone please explain this to me ? Thanks
As Chau Tran suggested, I will include a bit more code maybe this can help someone figure what I can't on my own:
Here's my app.component.ts:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'dogapp';
}
Here's my package.json:
{
"name": "dogapp",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "~7.1.0",
"@angular/common": "~7.1.0",
"@angular/compiler": "~7.1.0",
"@angular/core": "~7.1.0",
"@angular/forms": "~7.1.0",
"@angular/platform-browser": "~7.1.0",
"@angular/platform-browser-dynamic": "~7.1.0",
"@angular/router": "~7.1.0",
"bootstrap": "4.0.0-beta.2",
"core-js": "^2.5.4",
"font-awesome": "^4.7.0",
"jquery": "^3.3.1",
"popper.js": "^1.14.6",
"rxjs": "~6.3.3",
"tslib": "^1.9.0",
"zone.js": "~0.8.26"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.11.0",
"@angular/cli": "~7.1.4",
"@angular/compiler-cli": "~7.1.0",
"@angular/language-service": "~7.1.0",
"@types/node": "~8.9.4",
"@types/jasmine": "~2.8.8",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "~4.5.0",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~3.1.1",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~1.1.2",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.11.0",
"typescript": "~3.1.6"
}
}
Here's my image-service.ts:
import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs";
import { Observable } from "rxjs";
import { of } from "rxjs";
import { Image } from "../models/Image";
import { HttpClient, HttpHeaders } from "@angular/common/http";
@Injectable({
providedIn: "root"
})
export class ImageService {
images: Image;
private imageSource = new BehaviorSubject<Image>({
id: null,
text: null,
url: null,
date: null
});
selectedImage = this.imageSource.asObservable();
imageUrl: string = "https://dog.ceo/api/breeds/image/random";
constructor(private http: HttpClient) {
this.images = [
{
id: "1",
text: "Generated Pet 1",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("10/25/2017 12:54:32")
},
{
id: "2",
text: "Generated Pet 2",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("12/26/2017 12:58:33")
},
{
id: "3",
text: "Generated Pet 3",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("12/28/2017 12:59:30")
}
];
}
getImages(): Observable<Image> {
return of(this.images);
}
setFormImage(image: Image) {
this.imageSource.next(image);
}
addImage(image: Image) {
this.images.unshift(image);
}
getUrl(): Observable<any> {
return this.http.get(this.imageUrl);
}
}
Here's my images.component.ts:
import { Component, OnInit } from "@angular/core";
//import interface/model
import { Image } from "../../models/Image";
//import service
import { ImageService } from "../../services/image.service";
@Component({
selector: "app-images",
templateUrl: "./images.component.html",
styleUrls: ["./images.component.css"]
})
export class ImagesComponent implements OnInit {
images: Image;
//inject service as dependency into the constructor;
constructor(private imageService: ImageService) {}
ngOnInit() {
this.imageService.getImages().subscribe(images => {
this.images = images;
});
}
onSelect(image: Image) {
this.imageService.setFormImage(image);
}
}
Here's my image-form.component.ts:
import { Component, OnInit } from "@angular/core";
import { Image } from "../../models/Image";
//import service
import { ImageService } from "../../services/image.service";
import { getUrlScheme } from "@angular/compiler";
import { Observable } from "rxjs";
import { of } from "rxjs";
import { HttpClient, HttpHeaders } from "@angular/common/http";
@Component({
selector: "app-img-form",
templateUrl: "./img-form.component.html",
styleUrls: ["./img-form.component.css"]
})
export class ImgFormComponent implements OnInit {
id: string;
text: string;
url: string;
date: any;
isNew: boolean = true;
//imageUrl: string = "https://dog.ceo/api/breeds/image/random";
constructor(private imageService: ImageService) {}
ngOnInit() {
//subscribe to selectedImage observable
this.imageService.selectedImage.subscribe(image => {
if (image.id !== null) {
this.isNew = false;
this.id = image.id;
this.text = image.text;
this.url = image.url;
this.date = image.date;
}
});
//this.imageService.getUrl.subscribe(url => (this.url = url));
}
onSubmit() {
//check if new image
if (this.isNew) {
//create new image
const newImg = {
id: this.generateId(),
text: this.text,
date: new Date(),
url: this.generateUrl()
};
//add the image
this.imageService.addImage(newImg);
} else {
//create image to be updated
const updImg = {
id: this.id,
text: this.text,
date: new Date(),
url: this.url
};
//update image
// this.imageService.updateImage(updImg);
}
}
generateId() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
generateUrl() {
let url = this.imageService.getUrl().subscribe(response => {
return response;
let url = response[1];
return url;
});
console.log(url);
return url;
}
}
Here's my interface:
export interface Image {
id: string;
text: string;
url: string;
date: any;
}
I cannot manage to make a get request to the dog API (https://dog.ceo/dog-api/) to fetch a URL and pass it as a property to each image, once it is being instantiated (data for each image instantiation is being initialized in the image-form component.ts). Thanks for any help =).
service observable angular7 angular-httpclient
I am trying to integrate the Angular HTTP Client to my simple angular CRUD App. I want the app to generate a picture of a dog (taken from an API) and to display it in the browser. Each picture has a set of properties (text, id, date, URL). Everything works fine except I cannot fetch the data (for the URL) from an API (it works if I provide the URL for the images as hard coded data, but I want dynamically added data from the API). The API does not require any authentication, it's free and the fetch request works, I think I am not doing something right. The API is this:
https://dog.ceo/dog-api/
and I am fetching from this link
https://dog.ceo/api/breeds/image/random;
The request returns an object with a status and a message (in the message is the link and I want to pass that link as an URL property to the image component). The Images' properties are being initialized through the form component.
I am using angular 7 and am on a windows 8 machine, I also have the following setup in my app:
-a service
-form component
-images component
-I also have an interface for the image which is imported in both form/image components and in the service but I can t seem to make it work.
//Here's my code so far:
//Interface (image.ts)
export interface Image {
id: string;
text: string;
url: string;
date: any;
}
//Service (image-service.ts)
import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs";
import { Observable } from "rxjs";
import { of } from "rxjs";
import { Image } from "../models/Image";
import { HttpClient, HttpHeaders } from "@angular/common/http";
@Injectable({
providedIn: "root"
})
export class ImageService {
images: Image;
private imageSource = new BehaviorSubject<Image>({
id: null,
text: null,
url: null,
date: null
});
selectedImage = this.imageSource.asObservable();
imageUrl: string = "https://dog.ceo/api/breeds/image/random";
constructor(private http: HttpClient) {
this.images = [
{
id: "1",
text: "Generated Pet 1",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("10/25/2017 12:54:32")
},
{
id: "2",
text: "Generated Pet 2",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("12/26/2017 12:58:33")
},
{
id: "3",
text: "Generated Pet 3",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("12/28/2017 12:59:30")
}
];
}
getImages(): Observable<Image> {
return of(this.images);
}
setFormImage(image: Image) {
this.imageSource.next(image);
}
addImage(image: Image) {
this.images.unshift(image);
}
//I have to modify this function but I can't seem to manage T__T
getUrl(): Observable<any> {
return this.http.get(this.imageUrl);
}
}
//Images component (images-component.ts)
import { Component, OnInit } from "@angular/core";
//import interface/model
import { Image } from "../../models/Image";
//import service
import { ImageService } from "../../services/image.service";
@Component({
selector: "app-images",
templateUrl: "./images.component.html",
styleUrls: ["./images.component.css"]
})
export class ImagesComponent implements OnInit {
images: Image;
//inject service as dependency into the constructor;
constructor(private imageService: ImageService) {}
ngOnInit() {
this.imageService.getImages().subscribe(images => {
this.images = images;
});
}
onSelect(image: Image) {
this.imageService.setFormImage(image);
}
}
//Form component (img-form-component.ts)
import { Component, OnInit } from "@angular/core";
import { Image } from "../../models/Image";
//import service
import { ImageService } from "../../services/image.service";
import { getUrlScheme } from "@angular/compiler";
import { Observable } from "rxjs";
import { of } from "rxjs";
import { HttpClient, HttpHeaders } from "@angular/common/http";
@Component({
selector: "app-img-form",
templateUrl: "./img-form.component.html",
styleUrls: ["./img-form.component.css"]
})
export class ImgFormComponent implements OnInit {
id: string;
text: string;
url: string;
date: any;
isNew: boolean = true;
constructor(private imageService: ImageService) {}
ngOnInit() {
//subscribe to selectedImage observable
this.imageService.selectedImage.subscribe(image => {
if (image.id !== null) {
this.isNew = false;
this.id = image.id;
this.text = image.text;
this.url = image.url;
this.date = image.date;
}
});
}
onSubmit() {
//check if new image
if (this.isNew) {
//create new image
const newImg = {
id: this.generateId(),
text: this.text,
date: new Date(),
url: this.generateUrl()
};
//add the image
this.imageService.addImage(newImg);
} else {
//create image to be updated
const updImg = {
id: this.id,
text: this.text,
date: new Date(),
url: this.url
};
//update image
// this.imageService.updateImage(updImg);
}
}
generateId() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
generateUrl() {
let url = this.imageService.getUrl();
return url;
}
}
/*Please let me know If I explained throughly enough the issue, and sorry if I seem clumsy and explaining, I am fairly new to Angular and am trying to learn it. This app is part of the process.
Thanks
*/
Thanks Chau Tran for your answer, however it's not working for my issue, or I am not implementing it right. Here's what I tried:
//*function in the service*
getUrl(): Observable<any> {
return this.http.get(this.imageUrl);
}
// * functions in the form component*
generateUrl() {
return this.imageService.getUrl().toPromise();
}
// *image instantiation*
const newImg = {
id: this.generateId(),
text: this.text,
date: new Date(),
url: await this.generateUrl()
}
If I try like this I get the following errors:
Module parse failed: The keyword 'yield' is reserved (33:21)
You may need an appropriate loader to handle this file type.
| text: this.text,
| date: new Date(),
url: yield this.generateUrl()
| //this.generateUrl()
| };
'await' expression is only allowed within an async
function
What does it mean 'appropriate loader to handle this file type' ? And what 'file type'? I m lost here. Also, can I make the onSubmit()
in the constructor asynchronous? How would an implementation of that look (solving my url
issue as well).
I also tried to modify the generateUrl()
so as to subscribe to the getUrl()
observable in the service but I am either not subscribing 'correctly' or something else is 'off':
I also tried like this (as if to subscribe to the observable getUrl()
in the service, if I'm doing something wrong, someone please point it out, I can't figure it out myself:
generateUrl() {
let url = this.imageService.getUrl().subscribe(response => {
return response;
let url = response[1];
return url;
});
console.log(url);
return url;
}
I put `url` = response[1] because that's how the response is formatted in the dog API. So, what am I doing wrongly, can someone please explain this to me ? Thanks
As Chau Tran suggested, I will include a bit more code maybe this can help someone figure what I can't on my own:
Here's my app.component.ts:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'dogapp';
}
Here's my package.json:
{
"name": "dogapp",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "~7.1.0",
"@angular/common": "~7.1.0",
"@angular/compiler": "~7.1.0",
"@angular/core": "~7.1.0",
"@angular/forms": "~7.1.0",
"@angular/platform-browser": "~7.1.0",
"@angular/platform-browser-dynamic": "~7.1.0",
"@angular/router": "~7.1.0",
"bootstrap": "4.0.0-beta.2",
"core-js": "^2.5.4",
"font-awesome": "^4.7.0",
"jquery": "^3.3.1",
"popper.js": "^1.14.6",
"rxjs": "~6.3.3",
"tslib": "^1.9.0",
"zone.js": "~0.8.26"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.11.0",
"@angular/cli": "~7.1.4",
"@angular/compiler-cli": "~7.1.0",
"@angular/language-service": "~7.1.0",
"@types/node": "~8.9.4",
"@types/jasmine": "~2.8.8",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "~4.5.0",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~3.1.1",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~1.1.2",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.11.0",
"typescript": "~3.1.6"
}
}
Here's my image-service.ts:
import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs";
import { Observable } from "rxjs";
import { of } from "rxjs";
import { Image } from "../models/Image";
import { HttpClient, HttpHeaders } from "@angular/common/http";
@Injectable({
providedIn: "root"
})
export class ImageService {
images: Image;
private imageSource = new BehaviorSubject<Image>({
id: null,
text: null,
url: null,
date: null
});
selectedImage = this.imageSource.asObservable();
imageUrl: string = "https://dog.ceo/api/breeds/image/random";
constructor(private http: HttpClient) {
this.images = [
{
id: "1",
text: "Generated Pet 1",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("10/25/2017 12:54:32")
},
{
id: "2",
text: "Generated Pet 2",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("12/26/2017 12:58:33")
},
{
id: "3",
text: "Generated Pet 3",
url: "https://source.unsplash.com/1600x900/?pet",
date: new Date("12/28/2017 12:59:30")
}
];
}
getImages(): Observable<Image> {
return of(this.images);
}
setFormImage(image: Image) {
this.imageSource.next(image);
}
addImage(image: Image) {
this.images.unshift(image);
}
getUrl(): Observable<any> {
return this.http.get(this.imageUrl);
}
}
Here's my images.component.ts:
import { Component, OnInit } from "@angular/core";
//import interface/model
import { Image } from "../../models/Image";
//import service
import { ImageService } from "../../services/image.service";
@Component({
selector: "app-images",
templateUrl: "./images.component.html",
styleUrls: ["./images.component.css"]
})
export class ImagesComponent implements OnInit {
images: Image;
//inject service as dependency into the constructor;
constructor(private imageService: ImageService) {}
ngOnInit() {
this.imageService.getImages().subscribe(images => {
this.images = images;
});
}
onSelect(image: Image) {
this.imageService.setFormImage(image);
}
}
Here's my image-form.component.ts:
import { Component, OnInit } from "@angular/core";
import { Image } from "../../models/Image";
//import service
import { ImageService } from "../../services/image.service";
import { getUrlScheme } from "@angular/compiler";
import { Observable } from "rxjs";
import { of } from "rxjs";
import { HttpClient, HttpHeaders } from "@angular/common/http";
@Component({
selector: "app-img-form",
templateUrl: "./img-form.component.html",
styleUrls: ["./img-form.component.css"]
})
export class ImgFormComponent implements OnInit {
id: string;
text: string;
url: string;
date: any;
isNew: boolean = true;
//imageUrl: string = "https://dog.ceo/api/breeds/image/random";
constructor(private imageService: ImageService) {}
ngOnInit() {
//subscribe to selectedImage observable
this.imageService.selectedImage.subscribe(image => {
if (image.id !== null) {
this.isNew = false;
this.id = image.id;
this.text = image.text;
this.url = image.url;
this.date = image.date;
}
});
//this.imageService.getUrl.subscribe(url => (this.url = url));
}
onSubmit() {
//check if new image
if (this.isNew) {
//create new image
const newImg = {
id: this.generateId(),
text: this.text,
date: new Date(),
url: this.generateUrl()
};
//add the image
this.imageService.addImage(newImg);
} else {
//create image to be updated
const updImg = {
id: this.id,
text: this.text,
date: new Date(),
url: this.url
};
//update image
// this.imageService.updateImage(updImg);
}
}
generateId() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
generateUrl() {
let url = this.imageService.getUrl().subscribe(response => {
return response;
let url = response[1];
return url;
});
console.log(url);
return url;
}
}
Here's my interface:
export interface Image {
id: string;
text: string;
url: string;
date: any;
}
I cannot manage to make a get request to the dog API (https://dog.ceo/dog-api/) to fetch a URL and pass it as a property to each image, once it is being instantiated (data for each image instantiation is being initialized in the image-form component.ts). Thanks for any help =).
service observable angular7 angular-httpclient
service observable angular7 angular-httpclient
edited Jan 2 at 21:57
Dragos
asked Jan 1 at 10:31


DragosDragos
113
113
-I call the getUrl() method from the service in generateUrl() in the form component and pass that as a param in the onSubmit() in the form component, but it does not work (I get a 404 status); So I think I am not performing the fetch request through the http client as I should. -The only way this works is if I define the url as hard-coded data either in getUrl() -in the service or in generateUrl() in the form component and return it, but I want the service to return a dynamically 'fetched' url from the dog API (dog.ceo/dog-api)
– Dragos
Jan 1 at 10:32
add a comment |
-I call the getUrl() method from the service in generateUrl() in the form component and pass that as a param in the onSubmit() in the form component, but it does not work (I get a 404 status); So I think I am not performing the fetch request through the http client as I should. -The only way this works is if I define the url as hard-coded data either in getUrl() -in the service or in generateUrl() in the form component and return it, but I want the service to return a dynamically 'fetched' url from the dog API (dog.ceo/dog-api)
– Dragos
Jan 1 at 10:32
-I call the getUrl() method from the service in generateUrl() in the form component and pass that as a param in the onSubmit() in the form component, but it does not work (I get a 404 status); So I think I am not performing the fetch request through the http client as I should. -The only way this works is if I define the url as hard-coded data either in getUrl() -in the service or in generateUrl() in the form component and return it, but I want the service to return a dynamically 'fetched' url from the dog API (dog.ceo/dog-api)
– Dragos
Jan 1 at 10:32
-I call the getUrl() method from the service in generateUrl() in the form component and pass that as a param in the onSubmit() in the form component, but it does not work (I get a 404 status); So I think I am not performing the fetch request through the http client as I should. -The only way this works is if I define the url as hard-coded data either in getUrl() -in the service or in generateUrl() in the form component and return it, but I want the service to return a dynamically 'fetched' url from the dog API (dog.ceo/dog-api)
– Dragos
Jan 1 at 10:32
add a comment |
1 Answer
1
active
oldest
votes
generateUrl() {
let url = this.imageService.getUrl();
return url;
}
Your imageService.getUrl
returns an Observable
but you're trying to assign it to the url
property on newImage
which I assume url
is a string
.
Modify your getUrl
to return a url
or make sure you handle asynchronous data in generateUrl()
before returning url.
There are couple of ways, but in your case, I'll mention one that works right away (but it's kinda dirty):
const newImage = {
...
url: await this.generateUrl()
}
...
generateUrl() {
return this.imageService.getUrl().toPromise();
}
Hello, Your suggestion is not working or I am not implementing it correctly. Here's how I tried to implement your solution: getUrl(): Observable<any> { return this.http.get(this.imageUrl); }
– Dragos
Jan 2 at 19:09
Can you update your question with more code?
– Chau Tran
Jan 2 at 21:46
I think I included all the code in the 3 files but I will add more let me update my question. I will include more code without removing my initial explanations as I think this might help some1 figure it.
– Dragos
Jan 2 at 21:48
Try making your onSubmit() async byasync onSubmit()
– Chau Tran
Jan 2 at 21:49
What you're trying in the last snippet in your question won't work, the code is still asynchronous.
– Chau Tran
Jan 2 at 21:50
|
show 1 more comment
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53994739%2fhttp-client-cant-fetch-data-from-api-cannot-communicate-between-service-and-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
generateUrl() {
let url = this.imageService.getUrl();
return url;
}
Your imageService.getUrl
returns an Observable
but you're trying to assign it to the url
property on newImage
which I assume url
is a string
.
Modify your getUrl
to return a url
or make sure you handle asynchronous data in generateUrl()
before returning url.
There are couple of ways, but in your case, I'll mention one that works right away (but it's kinda dirty):
const newImage = {
...
url: await this.generateUrl()
}
...
generateUrl() {
return this.imageService.getUrl().toPromise();
}
Hello, Your suggestion is not working or I am not implementing it correctly. Here's how I tried to implement your solution: getUrl(): Observable<any> { return this.http.get(this.imageUrl); }
– Dragos
Jan 2 at 19:09
Can you update your question with more code?
– Chau Tran
Jan 2 at 21:46
I think I included all the code in the 3 files but I will add more let me update my question. I will include more code without removing my initial explanations as I think this might help some1 figure it.
– Dragos
Jan 2 at 21:48
Try making your onSubmit() async byasync onSubmit()
– Chau Tran
Jan 2 at 21:49
What you're trying in the last snippet in your question won't work, the code is still asynchronous.
– Chau Tran
Jan 2 at 21:50
|
show 1 more comment
generateUrl() {
let url = this.imageService.getUrl();
return url;
}
Your imageService.getUrl
returns an Observable
but you're trying to assign it to the url
property on newImage
which I assume url
is a string
.
Modify your getUrl
to return a url
or make sure you handle asynchronous data in generateUrl()
before returning url.
There are couple of ways, but in your case, I'll mention one that works right away (but it's kinda dirty):
const newImage = {
...
url: await this.generateUrl()
}
...
generateUrl() {
return this.imageService.getUrl().toPromise();
}
Hello, Your suggestion is not working or I am not implementing it correctly. Here's how I tried to implement your solution: getUrl(): Observable<any> { return this.http.get(this.imageUrl); }
– Dragos
Jan 2 at 19:09
Can you update your question with more code?
– Chau Tran
Jan 2 at 21:46
I think I included all the code in the 3 files but I will add more let me update my question. I will include more code without removing my initial explanations as I think this might help some1 figure it.
– Dragos
Jan 2 at 21:48
Try making your onSubmit() async byasync onSubmit()
– Chau Tran
Jan 2 at 21:49
What you're trying in the last snippet in your question won't work, the code is still asynchronous.
– Chau Tran
Jan 2 at 21:50
|
show 1 more comment
generateUrl() {
let url = this.imageService.getUrl();
return url;
}
Your imageService.getUrl
returns an Observable
but you're trying to assign it to the url
property on newImage
which I assume url
is a string
.
Modify your getUrl
to return a url
or make sure you handle asynchronous data in generateUrl()
before returning url.
There are couple of ways, but in your case, I'll mention one that works right away (but it's kinda dirty):
const newImage = {
...
url: await this.generateUrl()
}
...
generateUrl() {
return this.imageService.getUrl().toPromise();
}
generateUrl() {
let url = this.imageService.getUrl();
return url;
}
Your imageService.getUrl
returns an Observable
but you're trying to assign it to the url
property on newImage
which I assume url
is a string
.
Modify your getUrl
to return a url
or make sure you handle asynchronous data in generateUrl()
before returning url.
There are couple of ways, but in your case, I'll mention one that works right away (but it's kinda dirty):
const newImage = {
...
url: await this.generateUrl()
}
...
generateUrl() {
return this.imageService.getUrl().toPromise();
}
answered Jan 2 at 1:29


Chau TranChau Tran
1,3211422
1,3211422
Hello, Your suggestion is not working or I am not implementing it correctly. Here's how I tried to implement your solution: getUrl(): Observable<any> { return this.http.get(this.imageUrl); }
– Dragos
Jan 2 at 19:09
Can you update your question with more code?
– Chau Tran
Jan 2 at 21:46
I think I included all the code in the 3 files but I will add more let me update my question. I will include more code without removing my initial explanations as I think this might help some1 figure it.
– Dragos
Jan 2 at 21:48
Try making your onSubmit() async byasync onSubmit()
– Chau Tran
Jan 2 at 21:49
What you're trying in the last snippet in your question won't work, the code is still asynchronous.
– Chau Tran
Jan 2 at 21:50
|
show 1 more comment
Hello, Your suggestion is not working or I am not implementing it correctly. Here's how I tried to implement your solution: getUrl(): Observable<any> { return this.http.get(this.imageUrl); }
– Dragos
Jan 2 at 19:09
Can you update your question with more code?
– Chau Tran
Jan 2 at 21:46
I think I included all the code in the 3 files but I will add more let me update my question. I will include more code without removing my initial explanations as I think this might help some1 figure it.
– Dragos
Jan 2 at 21:48
Try making your onSubmit() async byasync onSubmit()
– Chau Tran
Jan 2 at 21:49
What you're trying in the last snippet in your question won't work, the code is still asynchronous.
– Chau Tran
Jan 2 at 21:50
Hello, Your suggestion is not working or I am not implementing it correctly. Here's how I tried to implement your solution: getUrl(): Observable<any> { return this.http.get(this.imageUrl); }
– Dragos
Jan 2 at 19:09
Hello, Your suggestion is not working or I am not implementing it correctly. Here's how I tried to implement your solution: getUrl(): Observable<any> { return this.http.get(this.imageUrl); }
– Dragos
Jan 2 at 19:09
Can you update your question with more code?
– Chau Tran
Jan 2 at 21:46
Can you update your question with more code?
– Chau Tran
Jan 2 at 21:46
I think I included all the code in the 3 files but I will add more let me update my question. I will include more code without removing my initial explanations as I think this might help some1 figure it.
– Dragos
Jan 2 at 21:48
I think I included all the code in the 3 files but I will add more let me update my question. I will include more code without removing my initial explanations as I think this might help some1 figure it.
– Dragos
Jan 2 at 21:48
Try making your onSubmit() async by
async onSubmit()
– Chau Tran
Jan 2 at 21:49
Try making your onSubmit() async by
async onSubmit()
– Chau Tran
Jan 2 at 21:49
What you're trying in the last snippet in your question won't work, the code is still asynchronous.
– Chau Tran
Jan 2 at 21:50
What you're trying in the last snippet in your question won't work, the code is still asynchronous.
– Chau Tran
Jan 2 at 21:50
|
show 1 more comment
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53994739%2fhttp-client-cant-fetch-data-from-api-cannot-communicate-between-service-and-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
-I call the getUrl() method from the service in generateUrl() in the form component and pass that as a param in the onSubmit() in the form component, but it does not work (I get a 404 status); So I think I am not performing the fetch request through the http client as I should. -The only way this works is if I define the url as hard-coded data either in getUrl() -in the service or in generateUrl() in the form component and return it, but I want the service to return a dynamically 'fetched' url from the dog API (dog.ceo/dog-api)
– Dragos
Jan 1 at 10:32