Я пытаюсь интегрировать Angular HTTP Client в мое простое угловое приложение CRUD.Я хочу, чтобы приложение генерировало изображение собаки (взято из API) и отображало его в браузере.Каждое изображение имеет набор свойств (текст, идентификатор, дата, URL).Все работает отлично, за исключением того, что я не могу получить данные (для URL) из API (это работает, если я предоставляю URL для изображений в виде жестко закодированных данных, но я хочу динамически добавлять данные из API).API не требует никакой аутентификации, он бесплатный и запрос на выборку работает, я думаю, что я что-то не так делаю.API это:
https://dog.ceo/dog-api/
и я получаю эту ссылку
https://dog.ceo/api/breeds/image/random;
Запрос возвращает объект со статусом и сообщением (в сообщении есть ссылка и яхотите передать эту ссылку как свойство URL компоненту изображения).Свойства изображений инициализируются с помощью компонента формы.
Я использую Angular 7 и работаю на компьютере с Windows 8, в моем приложении также есть следующие настройки:
-a служба
-форма компонента
-изображения компонента
-У меня также есть интерфейс для изображения, которое импортируется как в компоненты формы / изображения, так и в сервис, но я не могу заставить его работать.
//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
*/
Спасибо Чау Трану за ваш ответ, однако он не работает для моей проблемы, или я неправильно его реализую.Вот что я попробовал:
//*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()
}
Если я попробую вот так, я получу следующие ошибки:
Ошибка синтаксического анализа модуля: зарезервировано ключевое слово yield (33:21)соответствующий загрузчик для обработки этого типа файлов.|текст: этот.текст, |дата: новая дата (),
url: yield this.generateUrl()
|//this.generateUrl () |};
Выражение 'await' разрешено только внутри функции async
Что означает «соответствующий загрузчик для обработки этого типа файлов»?И что такое «тип файла»?Я потерялся здесь.Кроме того, я могу сделать onSubmit()
в конструкторе асинхронным?Как бы это реализовать (решая и мою проблему url
).
Я также пытался изменить generateUrl()
, чтобы подписаться на getUrl()
, наблюдаемый в сервисе, но я либо не подписываюсь 'правильно 'или что-то еще' выключено ':
Я тоже так пытался (как если бы подписался на наблюдаемое getUrl()
в сервисе, если я что-то делаю не так, кто-то, пожалуйста, укажите это,Я не могу понять это сам:
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
Как предложил Чау Тран, я добавлю немного больше кода, может быть, это может помочь кому-то понять, что я не могу самостоятельно:
Вот мой app.component.ts:
import {Component} из '@ angular / core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'dogapp';
}
Вот мой 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"
}
}
Вот мой 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);
}
}
Вот мой 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 =).