Angular2 Router interacting with Material Design L

2020-02-06 12:28发布

问题:

I've come across an interaction between the Angular2 router and the Material Design Lite (MDL) animations. If I create an <input> element in a component that is rendered by the <router-outlet> component in Angular2, MDL doesn't properly handle my interactions with it (doesn't show focus animation, doesn't clear placeholder text, etc). If, on the other hand, the <input> appears outside the <router-outlet>, there is no problem.

It seems like it has something to do with the dynamic nature of the contents of <router-outlet>. I thought this would solve the issue. I added an ngAfterViewInit and ngAfterViewChecked handler to my application (and even to my custom directive that extends RouterOutlet). No luck. I can see the componentHandler variable and call the updateDom method...no problem. But it has no effect.

There must be some way to get MDL to "see" these dynamically created elements, but my attempts with upgradeDom haven't been working. Maybe upgradeDom isn't the problem...but then what is.

Any suggestions?

回答1:

So after further digging, I thought I had found a solution. Playing with the plunkr I was able to show that the right manual call to componentHandler.<something> could address a similar issue I had managed to contrive in that plunkr.

However, the approach there (of creating a custom directive that triggered those calls on lifecycle events that the directive was attached to) didn't solve my issue. The "dynamic" nature of the router-outlet was still interfering. As far as I can tell, the calls to componentHandler were still premature and being done before the DOM had truly been updated by the router-outlet.

What I eventually had to do was to add some code to the activate method of RouterOutlet. I was already creating a custom RouterOutlet class, so it was simple enough to stick the code in the activate method.

However, I found that is is essential that you wait until the Promise associated with the activate method is resolved. So I did something like this:

declare var componentHandler: any;

...
export class MyRouterOutlet extends RouterOutlet {
  ...
  activate(instruction: ComponentInstruction) {
    // My custom activate stuff (i.e., check that user is
    // authorized to view this content)

    // Important part, call base class...
    return super.activate(instruction)
       .then((x) => {
          componentHandler.upgradeDom();
          return x;
       });
  }
}

Update:

I have not confirmed it, but I suspect that the reason the other solutions I alluded to did not work was because of another issue I ran across. My suspicion is that addressing that issue properly would have allowed the other solutions I referenced here to work.