Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 ngFor elements with Material Design Lite

I'm struggling to make Material Design Lite component to work with dynamically added elements via *ngFor. I understand that I need to call componentHandler.upgradeElement, but where do I put this call? I was trying this and this directives but they don't seem to work. Specifically, I need mdl-menu on each item of my array. Any suggestions on where to look at?

like image 399
Alexander Zhidkov Avatar asked Mar 28 '16 11:03

Alexander Zhidkov


2 Answers

TLDR; You need to call componentHandler.upgradeElement after the elements have been injected into the DOM. An approach I've used in the past is described in the example below.

EDIT If you want a declarative solution this approach here seem like a pretty good one, but I have not used it myself.

I created a service that wraps the Material Lite componentHandler

import { Injectable } from '@angular/core';

export interface ComponentHandler {
    upgradeDom();

}

declare var componentHandler: ComponentHandler;


@Injectable()
export class MaterialService {
    handler: ComponentHandler;
    constructor() {
        this.handler = componentHandler;
    }

    // render on next tick
    render() {
        setTimeout(() => { this.handler.upgradeDom(); }, 0);
    }

}

Then you call the service's render function after the component has injected the elements into the DOM. In your case this is after the *ngFor

This is a very contrived example but demonstrates "where" to call render

import { Component, OnInit } from '@angular/core';
import { DataService } from 'services/data.service';
import { MaterialService } from 'services/material.service';

@Component({
    selector: 'app-thing',
    templateUrl: `
       <ul>
            <li *ngFor="let item of data">
              {{data}}
            </li>
       </ul>
    `
})
export class ThingComponent implements OnInit {
    data: string[]
    constructor(
        private service: DataService,
        private material: MaterialService
    ) { }

    ngOnInit() {
        this.service.getData()
        .subscribe(data => {
            this.data = data;
            this.material.render();
        });
     }
}
like image 178
wickdninja Avatar answered Nov 20 '22 03:11

wickdninja


Problem: MDL does not watch dynamically created DOM element.

Solution: MDL library adds componentHandler property onto Window object. execute the below code inside ngOnInit() method of the component in which you are adding element dynamically.

setTimeout(() => {
  window['componentHandler'].upgradeDom();
}, 0);
like image 43
Amit Prabhu Parrikar Avatar answered Nov 20 '22 03:11

Amit Prabhu Parrikar