我有一个角度服务,可以生成称为模板的数据结构。模板是
export interface Template {
id: string;
data: number;
}
我的完整服务看起来像这样。
export interface Template {
id: string;
data: number;
}
export type AddTemplate = Omit<Template, 'id' | 'data'>;
export interface TemplateState {
templates: Template[];
}
@Injectable({
providedIn: 'root',
})
export class TemplateService {
private state = signal<TemplateState>({
templates: [],
});
templates = computed(() => this.state().templates);
add$ = new Subject<AddTemplate>();
constructor() {
this.add$.pipe(takeUntilDestroyed()).subscribe((template) =>
this.state.update((state) => ({
...state,
templates: [...state.templates, this.constructNewTemplate(template)],
}))
);
}
private constructNewTemplate(template: AddTemplate) {
return {
...template,
id: Math.floor(Math.random() * 1000000000).toString(),
data: Date.now(),
};
}
}
在我的主要组件中,我使用拖放 cdk 来允许拖动这些模板。
<div cdkDropList (cdkDropListDropped)="drop($event)">
@for(template of templates(); track template.id){
<div class="template" cdkDrag>
<p>id: {{template.id}}</p>
<p>data: {{template.data}}</p>
</div>
}
@empty{
<p>add a template!</p>
}
当我使用信号来显示这些模板时,它们在很大程度上更新得很好。当用户上下拖动模板时,它们甚至会重新排序。
然而,我遇到的问题是当我尝试创建另一个用函数转换这些值的计算信号时。
generated = computed(() => {
return this.format(this.templates());
});
private format(data: Template[]) {
console.log(data);
return data.map((template, index) => {
return { ...template, generatedIndex: index };
});
}
这有效...但每当用户拖动模板时,它都不会显示重新排序的模板。这让我认为放置事件应该对服务中的模板进行重新排序,而不是直接对计算的信号进行排序。
这是我创建的显示问题的 stackblitz 演示。请注意,当您拖放以重新排序时,顶部 2 个数组如何正确更新,但底部的数组却没有。这是 演示中代码的链接。
如有任何帮助,我们将不胜感激。我认为要么我需要改变我的方法,使用 drop 函数来调用模板服务,要么我需要弄清楚为什么在计算信号中添加格式函数意味着信号仅在添加新模板时更新。
重新排序服务中的模板:
drop($event)
函数中,调用服务方法以对
state
信号中的模板重新排序:
import { moveItemInArray } from '@angular/cdk/drag-drop';
// ...
drop(event: CdkDragDrop<Template[]>) {
const { container, previousIndex, currentIndex } = event;
moveItemInArray(this.templateService.templates, previousIndex, currentIndex);
}
优化变化检测的计算属性:
map
运算符可转换可观察值的发射值。您可以使用它来实现结果:
generated = this.templateService.templates.pipe(
map((templates: Template[]) => this.format(templates))
);