angular - 在 Angular 组件中对导入的服务方法使用 forkJoin() 时,“void”类型的参数不可分配
问题描述
我正在尝试将来自三个不同 API 获取请求的三组数据发送到 Angular 组件。目前,我有一个处理 HTTP 请求的服务,我将该服务导入到我的组件中,以便我可以访问服务方法。
我目前可以订阅并返回任何单个任务服务方法的数据,这样做:
this.tasksService.getTasks();
this.tasksSub = this.tasksService.getTaskUpdateListener()
.subscribe((allTasks: Task[]) => {
this.allTasks = allTasks;
});
console.log(allTasks)
将返回所需的结果。
但是,我需要将来自三种不同方法的数据获取到我的组件中,但我不能。这是我最近一次尝试使用forkJoin()
来完成此操作:
this.tasksSub = forkJoin(
this.tasksService.getTasks(),
this.tasksService.getOpenTasks(),
this.tasksService.getClosedTasks()
).this.tasksService.getTaskUpdateListener()
.subscribe((allTasks: Task[], openTasks: Task[], closedTasks: Task[]) => {
this.allTasks = allTasks;
this.openTasks = openTasks;
this.closedTasks = closedTasks;
});
这段代码在第一个参数上给了我这个错误消息forkJoin()
:
问题: 关于为什么会发生这种情况以及如何解决它的任何想法?
下面是我的整个 component.ts 和 service.ts:
任务列表.component.ts
import { Component, OnInit, OnDestroy } from "@angular/core";
import { Subscription, forkJoin } from 'rxjs';
import {CdkDragDrop, moveItemInArray, transferArrayItem} from '@angular/cdk/drag-drop';
import { Task } from "../task.model";
import { TasksService } from "../tasks.service";
import { AuthService } from 'src/app/auth/auth.service';
@Component({
selector: "app-task-list",
templateUrl: "./task-list.component.html",
styleUrls: ["./task-list.component.css"]
})
export class TaskListComponent implements OnInit, OnDestroy {
constructor(public tasksService: TasksService, private authService: AuthService) {}
allTasks: Task[] = [];
openTasks: Task[] = [];
closedTasks: Task[] = [];
employeeIsAuthenticated = false;
eId: string;
isAdmin: string;
private tasksSub: Subscription;
private authStatusSub : Subscription;
ngOnInit() {
this.eId = this.authService.getEmployeeId();
this.isAdmin = this.authService.getIsAdmin();
this.tasksService.getTasks();
this.tasksSub = this.tasksService.getTaskUpdateListener()
.subscribe((allTasks: Task[]) => {
this.allTasks = allTasks;
});
this.tasksSub = forkJoin(
this.tasksService.getTasks(),
this.tasksService.getOpenTasks(),
this.tasksService.getClosedTasks()
).this.tasksService.getTaskUpdateListener()
.subscribe((allTasks: Task[], openTasks: Task[], closedTasks: Task[]) => {
this.allTasks = allTasks;
this.openTasks = openTasks;
this.closedTasks = closedTasks;
});
// auth sub
this.employeeIsAuthenticated = this.authService.getIsAuth();
this.authStatusSub = this.authService
.getAuthStatusListener()
.subscribe( isAuthenticated => {
this.employeeIsAuthenticated = isAuthenticated;
this.eId = this.authService.getEmployeeId();
this.isAdmin = this.authService.getIsAdmin();
});
}
drop(event: CdkDragDrop<string[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
transferArrayItem(event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex);
}
}
onDelete(taskId: string) {
this.tasksService.deleteTask(taskId);
}
ngOnDestroy() {
this.tasksSub.unsubscribe();
this.authStatusSub.unsubscribe();
}
}
任务服务.ts
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Subject } from "rxjs";
import { map } from "rxjs/operators";
import { Router } from "@angular/router";
import { Task } from "./task.model";
@Injectable({ providedIn: "root" })
export class TasksService {
private tasks: Task[] = [];
private tasksUpdated = new Subject<Task[]>();
// we will need to construct this to use CRUD operations and router capabilities
constructor(private http: HttpClient, private router: Router) {}
// gets all tasks
getTasks() {
this.http
.get<{ message: string; tasks: any }>("http://localhost:3000/api/tasks/alltasks")
.pipe(
map(taskData => {
return taskData.tasks.map(task => {
return {
title: task.title,
content: task.content,
id: task._id,
creator: task.creator,
done: task.done
};
});
})
)
.subscribe(transformedTasks => {
console.log(transformedTasks);
this.tasks = transformedTasks;
this.tasksUpdated.next([...this.tasks]);
});
}
// get tasks for single employee
getMyTasks(creator: string) {
this.http
.get<{ message: string; tasks: any }>("http://localhost:3000/api/tasks/mytasks/"+creator)
.pipe(
map(taskData => {
return taskData.tasks.map(task => {
return {
title: task.title,
content: task.content,
id: task._id,
creator: task.creator,
done: task.done
};
});
})
)
.subscribe(transformedTasks => {
console.log(transformedTasks);
this.tasks = transformedTasks;
this.tasksUpdated.next([...this.tasks]);
});
}
// get open tasks
getOpenTasks() {
this.http
.get<{ message: string; tasks: any }>("http://localhost:3000/api/tasks/opentasks/")
.pipe(
map(taskData => {
return taskData.tasks.map(task => {
return {
title: task.title,
content: task.content,
id: task._id,
creator: task.creator,
done: task.done
};
});
})
)
.subscribe(transformedTasks => {
console.log(transformedTasks);
this.tasks = transformedTasks;
this.tasksUpdated.next([...this.tasks]);
});
}
// get closed tasks
getClosedTasks() {
this.http
.get<{ message: string; tasks: any }>("http://localhost:3000/api/tasks/closedtasks/")
.pipe(
map(taskData => {
return taskData.tasks.map(task => {
return {
title: task.title,
content: task.content,
id: task._id,
creator: task.creator,
done: task.done
};
});
})
)
.subscribe(transformedTasks => {
console.log(transformedTasks);
this.tasks = transformedTasks;
this.tasksUpdated.next([...this.tasks]);
});
}
getTaskUpdateListener() {
return this.tasksUpdated.asObservable();
}
// get specific task with id passed in
getTask(id: string) {
return this.http.get<{
_id: string;
title: string;
content: string;
creator: string;
done: boolean;
}>(
"http://localhost:3000/api/tasks/" + id
);
}
// create a task
addTask(title: string, content: string, creator: string, done: boolean) {
const task: Task = { id: null, title: title, content: content, creator: creator, done: done};
this.http
.post<{ message: string; taskId: string }>(
"http://localhost:3000/api/tasks",
task
)
.subscribe(responseData => {
const id = responseData.taskId;
task.id = id;
this.tasks.push(task);
this.tasksUpdated.next([...this.tasks]);
// return to tasks
this.router.navigate(["/mytasks/"+creator]);
});
}
// update a task
updateTask(id: string, title: string, content: string, creator: string, done: boolean ) {
const task: Task = { id: id, title: title, content: content, creator:creator, done: done };
this.http
.put("http://localhost:3000/api/tasks/" + id, task)
.subscribe(response => {
const updatedTasks = [...this.tasks];
const oldTaskIndex = updatedTasks.findIndex(t => t.id === task.id);
updatedTasks[oldTaskIndex] = task;
this.tasks = updatedTasks;
this.tasksUpdated.next([...this.tasks]);
// return to tasks
this.router.navigate(["/mytasks/"+creator]);
});
}
// delete a task
deleteTask(taskId: string) {
this.http
.delete("http://localhost:3000/api/tasks/" + taskId)
.subscribe(() => {
const updatedTasks = this.tasks.filter(task => task.id !== taskId);
this.tasks = updatedTasks;
this.tasksUpdated.next([...this.tasks]);
});
}
}
解决方案
forkJoin只接受 observables 作为参数。在此场景中,您展示的情况并非如此。为了使它工作,TaskService中的所有 3 个方法都应该返回Observables。请在下面找到代码片段:
在服务文件(TaskService)中:
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs";
import { Post } from "../models/index";
@Injectable({
providedIn: "root"
})
export class TaskService {
constructor(private http: HttpClient) {}
public getTasks() {
const url = "https://jsonplaceholder.typicode.com/posts"; // URL just to demonstrate
return this.http.get<Post[]>(url);
}
public getOpenTasks() {
const url = "https://jsonplaceholder.typicode.com/posts"; // URL just to demonstrate
return this.http.get<Post[]>(url);
}
public getClosedTasks() {
const url = "https://jsonplaceholder.typicode.com/posts"; // URL just to demonstrate
return this.http.get<Post[]>(url);
}
}
在组件中:
constructor(private taskService:TaskService){}
ngOnInit(){
forkJoin(
this.taskService.getTasks(),
this.taskService.getOpenTasks(),
this.taskService.getClosedTasks(),
).subscribe(response=>{
console.log(response);
}, error=>{
console.log(error)
})
}
在这里,服务文件中的函数返回 observables。在组件中,我们进行 3 次并行 API 调用并有一个共同的订阅。我们将以数组的形式返回响应。请在下面的演示网址中找到:
https://stackblitz.com/edit/angular-sf-forkjoin-issue?file=src/app/app.component.ts
https://angular-sf-forkjoin-issue.stackblitz.io
希望这会给你一个清晰的认识。
推荐阅读
- javascript - 视口单元是否应该在阴影 DOM 中响应?
- javascript - jQuery 按键动态排序`.append()` dict?
- python - 合并两个字符串值
- c# - CefSharp:我想在 ChromiumWebBrowse 中打开我的自定义键盘
- image - skimage中的图像文本提取
- r - 打印 R 输出并且不在导出到 LaTeX 的 org 模式下打印 R 代码
- amazon-web-services - 在 AWS 放大中设置烧瓶后端
- ruby-on-rails - rails: Link_to 查找方法
- javascript - 如何在 jquery 中使问题测验中的其他选项不可点击
- python - 如果 render_to_response 方法没有包含在任何地方,为什么我会收到 ImportError?