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

Wrong display order on Angular 9 #189

Open
snalesso opened this issue Mar 24, 2020 · 15 comments
Open

Wrong display order on Angular 9 #189

snalesso opened this issue Mar 24, 2020 · 15 comments

Comments

@snalesso
Copy link

Description

Only a single draggable div as follows:

<div [sortablejs]="selectedItems" [sortablejsOptions]="selectedItemsOptions">
    <button *ngFor="let item of selectedItems; let i = index;" [class.active]="item.isSelected" (click)="remove(item)">{{i + 1}}° {{item.label}}</button>
</div>

If an item is moved to the last position, when another item is addeded via code this.selectedItems.push(item) the list of items visualized is sorted wrongly.
The array items order is correct, but the visual representation of it is not.
I guess it's some incompatibility between sortablejs/ngx-sortablejs and Angular 9, since if I try to reproduce the issue on a Angular 8 project it doesn't happen.

How to reproduce

I uploaded a sample project here.
The code is very simple, it's just a new Angular application with changes on app.component.ts and app.component.html.

If you don't want to download the sample you can just follow these steps:

  1. Create a new project with: ng new <project_name>
  2. Install dependencies:
    npm i -S ngx-sortablejs sortablejs
    npm i -D @types/sortablejs
  3. Import SortablejsModule in AppModule.ts
  4. Edit only app.component.ts and app.component.html according to the sample linked above.

Environment

I tested this on Angular 9.0.7 and Angular 8.2.14.
Versions mentioned above are those indicated in <app-root ng-version="">.
The issue shows up only on Angular 9.

@Etienne-Buschong
Copy link

I have the same issue. Any update on this?

@Etienne-Buschong
Copy link

Etienne-Buschong commented Jun 3, 2020

A temporary solution is to use the onUpdate hook of the sortable-js options object and overwrite the sortablejs bindingTarget in it. This forces Angular's change detection to run and re-render the ngFor correctly.

// We are in .ts component file
// For this example binding target is called "data"
 const sortablejsOptions = {
   onUpdate: () => {
      const originalData = {...this.data};
      this.data = {};
      setTimeout(() => {
         this.data = originalData;
      )}
   }
}

The data will then be rendered correctly.

Note: I also tried to omit the Angular2-Binding and use sortablejs directly with Angular, but this leads to the same problem. So maybe this problem is also/more related to the original sortablejs library.

@dorthrithil
Copy link

I guess this is the same issue that Dragula faces. It seems to be related to the Ivy compiler. I experienced the exact same issue for Dragula and Sortable.

Here is a solution for Dragula: https://stackoverflow.com/questions/63532041/ng2-dragula-after-adding-new-item-its-getting-displayed-at-the-top/63609337#63609337

Can we somehow apply the same for Sortable? For now Iv'e switched to Dragula but I would love to switch back as soon as this bug is gone or can be worked around.

@onur-ozguzel
Copy link

onur-ozguzel commented Feb 17, 2021

Hi there;

Can you please try version 3.1.3 and let me know if it' s working for you too or not?

I' m using 3.1.3 on Angular 10, it' s working fine. But later versions have this bug & i cannot update ngx-sortable because of that.

Related topic which i opened is: #202

@markanye
Copy link

Same problem here! Angular 10 with ngx-sortablejs 10.1.0.

@snalesso
Copy link
Author

snalesso commented Mar 1, 2021

Problem persists with:

  • Angular @ 11.2.3
  • ngx-sortablejs @ 11.1.0

@jianxiangxun
Copy link

Same problem here! Angular 13.1.0 with ngx-sortablejs 11.1.0.

@jianxiangxun
Copy link

A temporary solution is to use the onUpdate hook of the sortable-js options object and overwrite the sortablejs bindingTarget in it. This forces Angular's change detection to run and re-render the ngFor correctly.

// We are in .ts component file
// For this example binding target is called "data"
 const sortablejsOptions = {
   onUpdate: () => {
      const originalData = {...this.data};
      this.data = {};
      setTimeout(() => {
         this.data = originalData;
      )}
   }
}

The data will then be rendered correctly.

Note: I also tried to omit the Angular2-Binding and use sortablejs directly with Angular, but this leads to the same problem. So maybe this problem is also/more related to the original sortablejs library.

i think requestAnimationFrame is better than setTimeout

@equilerex
Copy link

Having the same issue. In my case, i am unable/willing to overwrite/rebind the data since its a FormArray originating from the parent component (and i do not want to sever that connection).

As a really rough temporary fix, i'm just hiding the whole element with ngIf for a split second
(adding new items is done in a modal window in my solutin, so the flash is not too noticeable)

// we forcefully remove and re-render the sortable element before adding new tiles
  hardRefresh() {
    // relevant only if the order was changed beforehand
    if (this.orderChanged) {
      this.forceOrderRefresh = true;
      this.orderChanged = false;
       this.cdr.detectChanges();
      setTimeout(() => {
        this.forceOrderRefresh = false;
         this.cdr.detectChanges();
      }, 0);
    }
  }

added to the element:

      <div
      *ngIf="!forceOrderRefresh"
      [sortablejs]="mediaArray.controls"
      [sortablejsOptions]="sortablejsOptions" 
      class="ao-media-upload__multi-file-draggable-area"
    >

and to make sure that the trick is only used in case drag was used, ive added "orderChanged " into dragend:

  onDragEnd(event) {  
    this.cdr.detectChanges();
    this.updateArrayValidators();
    this.orderChanged = true;
  }

@MichaelJFordham
Copy link

Still experiencing this problem with:

Angular @ 13.3.2
ngx-sortablejs @ 11.1.0

@MichaelJFordham
Copy link

MichaelJFordham commented Apr 13, 2022

For anyone suffering with this problem, I found this worked for me:

  sortableOptions: SortableOptions = {
    ...other options...
    onUpdate: () => {
      // Replace this.arrayContent with your data
      this.arrayContent = [
        ...this.arrayContent
      ];
    },
  };

It seems like re-assigning the data triggers Angular to re-render the *ngFor section, which means items are displayed in the correct order.

@Klapik
Copy link

Klapik commented Mar 13, 2023

Any news?

@kerimdragolj
Copy link

any update on this?

@zhandosainabek
Copy link

Just use drag and drop from @angular/cdk. It is way more better.

@COBRASoft5
Copy link

Just use drag and drop from @angular/cdk. It is way more better.

And how does that work for grids, both horizontal and vertical at the same time? Say a 3 by 4 grid. Horizontal first, then next row...

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