35

I have a small problem in integrating a meterial design (http://www.getmdl.io/) in ng2 Can you please help me I will put it in points what I have done

  1. http://www.getmdl.io/started/index.html#tab1, explains the integration of the design
  2. http://www.getmdl.io/components/index.html#textfields-section, this is an example of textfield with floating label and now I Have the Plunkr, which I integrated, but DID NOT WORK can you please have a look As you can see in the index.html I have the css and js files inclustion as suggested by http://www.getmdl.io/started/index.html#tab1

<!-- GetMDL scripts --> <link rel="stylesheet" href="https://storage.googleapis.com/code.getmdl.io/1.0.6/material.indigo-pink.min.css"> <script src="https://storage.googleapis.com/code.getmdl.io/1.0.6/material.min.js"></script> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"> <!-- GetMDL scripts --> And in the app.component.ts file :

import {Component, ViewEncapsulation} from 'angular2/core';

@Component({
    selector: 'my-app',
    template: `<form action="#">
  <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
    <input class="mdl-textfield__input" type="text" id="sample3">
    <label class="mdl-textfield__label" for="sample3">Text...</label>
  </div>
</form>`,
encapsulation:ViewEncapsulation.None,
})
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
RONE
  • 5,415
  • 9
  • 42
  • 71
  • 1
    The answers here were really useful, but I found that they were not sufficient when dealing with components that were being rendered by the router. If you run into issues related to the router, you might be interested in [this question](http://stackoverflow.com/questions/36162649/angular2-router-interacting-with-material-design-lite/36163652#36163652) (and answer). – Michael Tiller Mar 22 '16 at 19:43

7 Answers7

38

Thanks guys, works like a charm, to wrap this up a complete solution, that works well for me (tested with beta6). Without too much boilerplate code. The only thing I did not get to work are really dynamically added elements via *ngFor depending on a component variable. See dynamic elements in the template. Maybe one of you guys knows how to get around that.

See a working plunkr (the preview must be at least 1024px wide to see the header)

Install MDL

npm i material-design-lite --save

Reference it in your index.html

<script src="/node_modules/material-design-lite/material.min.js"></script>
<!-- from http://www.getmdl.io/customize/index.html -->
<link rel="stylesheet" href="/css/customized-material.min.css">

Create MaterialDesignLiteUpgradeElement.ts

import {Directive, AfterViewInit} from 'angular2/core';
declare var componentHandler: any;

@Directive({
    selector: '[mdl]'
})    
export class MDL implements AfterViewInit {
    ngAfterViewInit() {
        componentHandler.upgradeAllRegistered();
    }
}

Then in your component import and register it

import { Component } from '@angular/core';    
import { MDL } from '../../../directives/MaterialDesignLiteUpgradeElement';

@Component ({
  selector: 'my-component',
  directives: [ MDL ],
  templateUrl: 'app/components/Header/Header.html'
})
export class Header {
  public dynamicArray:number[] = [];

  add() {
    this.dynamicArray.push(Math.round(Math.random() * 10));
  }
}

And in your template add mdl to the root component

<header mdl class="mdl-layout__header">
    <div class="mdl-layout__header-row">
      <span class="mdl-layout-title">Home</span>
      <div class="mdl-layout-spacer"></div>

      <button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon"
              (click)="add()">
          <i class="material-icons">add</i>
      </button>
      <button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon" id="hdrbtn">
          <i class="material-icons">more_vert</i>
      </button>
      <ul class="mdl-menu mdl-js-menu mdl-js-ripple-effect mdl-menu--bottom-right" for="hdrbtn">
          <li class="mdl-menu__item">Static entry</li>

          <!-- semi dynamic, known when view is created -->
          <li class="mdl-menu__item" *ngFor="#nr of [1,2,3]">Semi Dynamic entry {{nr}}</li>

          <!-- dynamic, depends on service manipulated array -->
          <li class="mdl-menu__item" *ngFor="#nr of dynamicArray">Dynamic entry {{nr}}</li>
      </ul>
  </div>
</header>
theUtherSide
  • 3,338
  • 4
  • 36
  • 35
Rob
  • 664
  • 7
  • 16
  • Thanks Rob, this was very helpful. You noted that you couldn't add dynamic elements. Is that not what you were doing with the menu items? Perhaps you can explain further. – Stephen Paul Apr 20 '16 at 08:36
  • 1
    Hi Steve, basically anything that gets generated at runtime. The semi dynamic stuff can be generated before OnInit fires, because [1,2,3] is known and therefore the according views can be rendered. Content of dynamicArray isn't. We switched to ng2-material, works better for us. – Rob Apr 21 '16 at 05:59
  • Man, this is awesome! Real life+time saver. Thanks a lot @Rob – softvar May 07 '16 at 13:09
  • Awesome. Thanks a lot. – user2180794 May 18 '16 at 07:34
  • Thank you. Apparently this doesn't work when I use ngformmodel of angular2.. It breaks the MDL behavior. – user2180794 May 29 '16 at 00:28
  • where `declare var componentHandler: any;` is initialized? Thanks! – iamandrewluca Jun 30 '16 at 06:59
  • Huge help! Really nice solution too. Thank you! – GuiDoody Jul 09 '16 at 06:18
  • 3
    A better solution is to use `AfterViewChecked` interface to be able to do it only once, on the root application component. See my full answer here : http://stackoverflow.com/a/39040342/1969987 – Julien Boulay Aug 19 '16 at 13:34
  • 1
    I am getting directive does not exist in type component... Anyone else encountering this? Do I need to be using both the beta version ('angular2/core') and a release version('@angular/core') for this to work? – BillHaggerty Sep 22 '16 at 22:13
  • 2
    For dynamically added elements after the initial view is loaded, you can try using `ngAfterContentChecked()` instead of `AfterViewChecked`. – estaples Oct 25 '16 at 20:01
  • Insert MDL to `declarations` array instead of `directives` – Vlad May 16 '17 at 07:50
9

The problem is Material Design Lite isn't designed to be used with dynamic pages like those generated by Angular2. That said it should be possible by using the MDL componentHandler.upgradeElement function.

More information on this can be found here: http://www.getmdl.io/started/#dynamic

I'd suggest getting an ElementRef in your Angular components then calling this function on the element ref in one of your components lifecycle hooks, probably ngAfterViewInit()

Zyzle
  • 2,210
  • 1
  • 16
  • 19
8

I am able to get the solution from angualrjs channel, and it is super cool solution, ofource we have to use componentHandler.upgradeElement(this.elementRef.nativeElement);

//This is the way to make the

@Directive({
  selector: '[mdlUpgrade]'
})
class MdlUpgradeDirective {
  @Input() mglUpgrade;

  constructor(el: ElementRef) {
    componentHandler.upgradeElement(el.nativeElement);
  }
}

@Component ({
  selector: 'login',
   ...
  directives: [MdlUpgradeDirective]
})

and use the Directive on the HTML tags to use it.

It works,

NOTE: https://github.com/justindujardin/ng2-material , this guys has made super cool material stuff, can refer this too

RONE
  • 5,415
  • 9
  • 42
  • 71
  • a u actually using MDL + ng2-material together? Did you had any issues with MDL components (angular2 creating parent tag/selector for each component which is braking its view)? – angularrocks.com Mar 15 '16 at 04:34
  • 1
    I found that this works better when calling `componentHandler.upgradeElement(el.nativeElement);` in `ngAfterViewInit()` (otherwise upgrade is done before other directives, like `ngModel`, kick into action) – Yoav Aharoni Apr 12 '16 at 12:00
  • I'm not questioning the solution you provided only clarifying something about the link you provided. The article mentioned above is referencing Material2, not Material Design Lite, which is different. – Post Impatica May 24 '16 at 13:55
  • @Helzgate, If you have read the whole line, you would have got an idea, It is basically a reference for other design. – RONE May 26 '16 at 02:57
  • 1
    I have to say, I'm very confused, why the plain adding classes on html elements solution needs to be so complicated? – Eugene Nov 30 '16 at 10:27
1

I was facing the same problem (as I'm using the same template as you).

Just try componentHandler.upgradeAllRegistered() it will work fine in your case.

A different issue occurs when you try to break the header into small components.

0

just import ElementRef and OnInit from the angular2/core and inject it to a constructor as so:

constructor(@Inject(ElementRef) elementRef: ElementRef) {
    this.elementRef = elementRef;

}

then use an ngOnInit method and use the componentHandler.upgradeElement on any dynamically added tag you used.

theUtherSide
  • 3,338
  • 4
  • 36
  • 35
Esteban Morales
  • 1,626
  • 14
  • 14
0

Just thought it's worth mentioning here that the official Material Design for Angular 2 library is now in alpha.2, so you might consider starting new projects with it.

Yoav Aharoni
  • 2,672
  • 13
  • 18
  • I looked at this and I don't fully understand how to use it in a project. Would love to see an example if anyone has one! – theUtherSide May 25 '16 at 02:18
  • Take a look at the demo-app in the source https://github.com/angular/material2/tree/master/src/demo-app – Yoav Aharoni May 25 '16 at 05:12
  • Or if you like, I can copy a snippet from my project later today – Yoav Aharoni May 25 '16 at 05:13
  • A year later, they still don't have basic components like tables implemented. This really isn't production ready, don't make the same mistake I did. – Davor Jun 17 '17 at 13:45
0

The ng2-webpack Demo project includes a simple ng2 CRUD application that uses vanilla MDL

Steps:

  • npm install --save material-design-lite
  • import the entire library in src/vendor.js
  • or just the desired components
  • in src/style/app.scss, import the desired components:

Issues:

Issue - MDL augmented DOM effects are not applied:

  • consistently during state changes
  • during route changes

Solution:

ngAfterViewInit() {
    // Ensure material-design-lite effects are applied
    componentHandler.upgradeDom();
}

see Working with Material Design Lite for more details.