Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular animate query incorrectly returning zero elements

I'm working on an Electron app using Angular, and the main page is supposed to display a list of items which are loaded asynchronously from a JSON file.

They load and animate fine, but in order to stagger their animation, I call angular animate's Query function.

Unfortunately, this query returns zero elements, despite the fact that they successfully load almost immediately, with the correct animation (just not staggered).

I suspect this has something to do with the query firing before the data is loaded, but I'm not sure what I can do to resolve that.

The relevant code is included below.

HTML:

<div [@itemList]="itemService.items.length">
  <div class="item-card" *ngFor="let item of itemService.items | 
  async;">
  </div>
</div>

Component:

@Component({
    selector: 'app-notes-list',
    templateUrl: './notes-list.component.html',
    styleUrls: ['./notes-list.component.css'],
    animations: [
        trigger('items', [
            transition(':enter', [
                style({ transform: 'scale(0.5)', opacity: 0 }),  // initial
                animate('1s cubic-bezier(.8, -0.6, 0.2, 1.5)',
                    style({ transform: 'scale(1)', opacity: 1 }))  // final
            ]),
            transition(':leave', [
                style({ transform: 'scale(1)', opacity: 1, height: '*' }),
                animate('1s cubic-bezier(.8, -0.6, 0.2, 1.5)',
                    style({
                        transform: 'scale(0.5)', opacity: 0,
                        height: '0px', margin: '0px'
                    }))
            ])
        ]),
        trigger('itemList', [
            transition(':enter', [
                query('.item-card', stagger(3000, animateChild()))
            ]),
        ])
    ]
})
export class NotesListComponent implements OnInit {

    constructor(private itemService: ItemService) { }

    ngOnInit() {
        this.getItems();
    }

    getItems(): void {
        this.itemService.getItems();
    }
}

Service:

@Injectable()
export class ItemService {

    items: Subject<Item[]>;
    itemDataStore: Item[];

    constructor(private electronService: ElectronService,
        private zone: NgZone) {

        this.items = new Subject<Item[]>();

        this.electronService.ipcRenderer.on('sending-items', (event, args) => {
            this.itemDataStore = args;
            this.zone.run(() => {
                console.log('Got data');
                this.items.next(this.itemDataStore);
            });
        });
    };

    getItems(): Observable<Item[]> {
        this.electronService.ipcRenderer.send('get-items');
        return this.items.asObservable();
    }
}
like image 229
Matthew Oldham Avatar asked Dec 24 '22 11:12

Matthew Oldham


1 Answers

items: Subject<Item[]>; should be in the component that call the service.

Then you should subscribe to the method returning an Observable, to get the items in the component. It should look close to this :

this.itemService.getItems().subscribe(data => {
    this.items = data;
});

Then in component.html

<div [@itemList]="items.length">
    <div class="item-card" *ngFor="let item of items | 
  async;">
    </div>
</div>

Update

To solve the issue (length of undefined), set the optional parameter to true, in the query :

trigger('itemList', [
      transition(':enter', [
        query('.item-card', [
          stagger(3000, [
            animateChild()
          ]),
        ], { optional: true })
      ]),
    ])

and in the the div : [@itemList]="items?.length"

like image 125
br.julien Avatar answered Dec 28 '22 11:12

br.julien