How to use angular material drag and drop CDK to update value in a service?

67 views Asked by At

I have an angular service that generates a data structure called a Template. A Template is

export interface Template {
  id: string;
  data: number;
}

My service in full looks like this.

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(),
    };
  }
}

In my main component, I am using the drag and drop cdk to allow dragging of these templates.

<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>
}

When I use a signal to display these templates, they update fine for the most part. They even reorder as the user drags the templates up and down.

templatepicture

The problem I'm running into however is when I try to create another computed signal that transforms these values with a function.

  generated = computed(() => {
    return this.format(this.templates());
  });

  private format(data: Template[]) {
    console.log(data);
    return data.map((template, index) => {
      return { ...template, generatedIndex: index };
    });
  }

This works... but it doesn't show the reordered templates whenever the user drags them. This makes me think that the drop event should be reordering the templates from the service rather than directly on the computed signal.

Here's a stackblitz demo I created that displays the problem. Notice how the top 2 arrays update properly when you drag and drop to reorder them, but the bottom one doesn't. Here's the link to the code in the demo.

Any help is appreciated. I think either I need to change my approach with the drop function to call on the template service, or I need to figure out why adding in a format function in a computed signal means that signal only updates when a new template is added.

0

There are 0 answers