Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Angular dynamic swapy implementation #109

Open
Ookamini95 opened this issue Jan 2, 2025 · 1 comment
Open

[BUG] Angular dynamic swapy implementation #109

Ookamini95 opened this issue Jan 2, 2025 · 1 comment

Comments

@Ookamini95
Copy link

Ookamini95 commented Jan 2, 2025

My current angular implementation

swapy.html

<div class="container" #swapyContainer>
  @for (v of slottedItems(); track v.item?.index) {
  <div class="slot top" [attr.data-swapy-slot]="v.slotId">
    <div class="item item-a" [attr.data-swapy-item]="v.itemId">
      <div>{{ v.item?.value ?? 'undef' + $index }}</div>
    </div>
  </div>
  }
</div>

swapy.ts

  _swapyContainer = viewChild<ElementRef<HTMLDivElement>>('swapyContainer');
  swapyContainer = computed(() => this._swapyContainer()?.nativeElement);

  swapy?: ReturnType<typeof createSwapy>;

  _exampleItems = Array.from({ length: 3 }, (_, i) => ({
    value: `value-${i}`,
    index: i,
  }));
  exampleItems = signal(this._exampleItems);

  // swapy manual
  slotItemMap = signal(utils.initSlotItemMap(this.exampleItems(), 'index'));
  slottedItems = linkedSignal(() =>
    utils.toSlottedItems(this.exampleItems(), 'index', this.slotItemMap())
  );
  slotItemsEffect = effect(() => {
    const items = this.exampleItems();
    console.log('Effect items: ', items);
    utils.dynamicSwapy(
      this.swapy ?? null,
      items,
      'index',
      untracked(this.slotItemMap),
      (value) => {
        console.log('Setting value: ', value);
        this.slotItemMap.set(value)
      }
    );
  });

  ngOnInit() {
    const container = this.swapyContainer();
    if (container) {
      this.swapy = createSwapy(container, {
        animation: 'dynamic',
        dragAxis: 'y',
        manualSwap: true,
      });

      this.#swapyTestEvents();
    }
  }
  ngAfterViewInit() {
    this.swapy?.update();
  }

  #swapyTestEvents() {
    if (!this.swapy) return;
    this.swapy.onBeforeSwap((event) => {
      console.log('beforeSwap', event);
      // This is for dynamically enabling and disabling swapping.
      // Return true to allow swapping, and return false to prevent swapping.
      return true;
    });

    this.swapy.onSwapStart((event) => {
      console.log('start', event);
    });

    this.swapy.onSwap((event) => {
      console.log('swap', event);
      requestAnimationFrame(() => {
        console.log('Old slotItemMap:', this.slotItemMap());
        console.log('New slotItemMap:', event.newSlotItemMap.asArray);
        // this.slotItemMap.set(event.newSlotItemMap.asArray); *****
      });
    });

    this.swapy.onSwapEnd((event) => {
      console.log('swap end:', event);
    });
  }
}

***** If I uncomment this I get the following behaviour:

  • Drag and drop works once, but items become undefined (weird item/slot swap behaviour) and stops working

if i leave it:

  • Drag works, but doesn't react to it (and drop)

I'm pretty sure I'm doing something wrong here, maybe someone could help?

Edit: Managed to get correct Drag and drop behaviour by changing

  _exampleItems = Array.from({ length: 3 }, (_, i) => ({
    value: `value-${i}`,
    index: i.toString(), // here
  }));

but i still get erratic behaviour, expecially the 'track' in the loop seems to behave differently depending on : 'track v.item?.index' | 'track v.itemId' | 'track v.slotId' | $index. All have in common the fact that at some point the 'onSwap' breaks and starts firing multiple events.

Stackblitz: https://stackblitz.com/~/github.com/Ookamini95/test-swapy-dynamic

@Ookamini95
Copy link
Author

Managed to produce a more stable version with the following modifications

swapy.html

  @for (v of slottedItems(); track v) { // only track v

swapy.ts

this.swapy.onSwap((event) => {
      console.log('swap', event);
      // requestAnimationFrame(() => { // removed as it kills animations
      this.slotItemMap.set(event.newSlotItemMap.asArray);
        // });
    });

    this.swapy.onSwapEnd((event) => {
       requestAnimationFrame(() => { // necessary when swapMode: 'drop', else makes no difference
        this.swapy?.update();
      });
    });

Still behaviour is different from expected when swapMode: 'hover', whilst I think I've managed to narrow down the swapMode: 'drop'.

Expected behaviour:

  • After initial swap, user should still be able to swap items.

Behaviour

  • After initial swap, user has to drop the item in order to re-enable dnd functionality.

If I'm able to find a fix I can clean it up for v.1.0 standards and do a pull, in the meantime I've updated the stackblitz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant