Lazy register issue
zladuric opened this issue · 12 comments
Hi,
I'm trying to use mdl-selectfield in an angular2 project, but I'm having strange issues with the floating label.
The major issue is that if the content is, obviously, lazily added. I do have an componentHandler.upgradeAllRegistered();
call that seems to register and render properly most of the elements, including the select field - but the labels do not float. However, if I call the registration logic again:
componentHandler.register({
constructor: MaterialSelectfield,
classAsString: 'MaterialSelectfield',
cssClass: 'mdl-js-selectfield',
widget: true
});
...it throws an error, naturally, that The provided className has already been registered. I could live with the error as my floating label now works, but the problem is that my own components then do not. (probably that thrown exception stops execution). If I wrap the call in a try/catch, again the floating label doesn't work. This makes me think the registration is only partially successful and try/catch works like a rolled-back transaction here.
So I've tried postponing the registration part, then calling the newly added __register()
before and after componentHandler upgrade, but again same problem - the float label doesn't work.
I'm kind of out of ideas. Is there something else I could try to get this to work?
Well, for what it's worth, this works (so far):
- let the script register itself normally,
- do a
componentHandler.upgradeAllRegistered();
- postpone upgrade to the next tick:
setTimeout(function() {componentHandler.upgradeAllRegistered();});
Closing the ticket, but I'm curious as to what is the underlaying reason for this behavior?
Would you have any working example of this? if this is linked to angular2, it sounds pretty normal to do the upgrade in a timeout and not right after adding the component
You're right, as I get more into this, I am figuring out what things do. It has to do with late component render, I guess. A short gist of what I'm doing is here.
If you comment out the setTimeout() call (app.ts, the mdl upgrade component) and just do the upgrade directly, you can see the results.
Thanks for the help, anyway.
At the same time if you just set this.show = true;
in your SubComponent
, it works right? you only have to differ the componentHandler.upgradeAllRegistered();
by 2500
ms because you actually only render the <select>
element after 2000
ms, so obviously registering the component before it actually exists has no effect. I would say either you remove this timeout, or you use events.publish
/event.subscribe
mechanism to trigger the update when it is actually visible (actually I don't know much about angular2 so maybe it's handle differently)
@zladuric Can you tell me how you added the componentHandler login in there? I'm struggling with this as I'm new to angular and using mdl-selectfield for the first time. So far I have everything working when I first load the page, but after AJAX updates, the selectfield does not render properly. Where exactly did you call the componentHandler.upgradeAllRegistered() method? I've also had the problem of floating labels not working after AJAX.
you have to call it after receiving the ajax response, so something like:
this.http.get(...).subscribe((data) => {
setTimeout(() => componentHandler.upgradeAllRegistered());
});
@mebibou Thanks - I just tried that but it goes into some kind of infinite loop. Angular change detection may be a culprit here, but basically as soon as I load the page, the Chrome tab becomes unresponsive and my CPU goes high, so I'm guessing it's some sort of stack overflow or infinite loop where it's upgrading all elements in a circular loop. Any idea why that might be?
does it go in the loop of the ajax call? if so, you could put a debugger
before the call and see why it's calling your ajax again
It doesn't seem to be in the ajax call. Something internally with angular or mdl. When I run it in Firefox, it gives me the script has stopped responding message. So it is definitely something within the page. Most of the time the page partially loads. I have 14 selectfields on the page and only 3 or 4 load and the animation stops and page stops responding. I've tried doing the upgradeAllRegistered from many places including from within the view and from outside the component and they all end up in infinite loop. Weird thing is that when I only have 2 selectfields, it works fine except for one thing - if the select field has more than 2 options, it doesn't show them, and you cannot scroll down on them. Not sure if that gives you any more info about what the problem might be. If you think of anything, it would be of much help. I'm trying to debug it myself at moment to see why it's going into infinite loop.
Turns out that simply calling upgradeAllRegistered() sends it into some endless loop. I tried to call it using a button, so that it's completely detached from all events, and it still went into an infinite loop. I am using angular2-mdl (https://github.com/mseemann/angular2-mdl) and library as well, so maybe that is somehow colliding with your library. I'll try removing that library and see if that solves the issue.
@zladuric Thanks for the tips, but it seems like it had something to do with my architecture. I got it working finally, but mostly by sidestepping the weird behavior. I think I still have issues in the app but I think those are not related to mdl-selectfield. The way I have it working now is I put componentHandler.upgradeAllRegistered(); inside ngAfterViewInit() instead of after the AJAX call. I did find where the infinite loop was, and it was related to angular change detection. I had a getter property (in typescript) being fed into the input of the component that contains mdl-selectfield. This was somehow causing ng2 change detection to keep firing repeatedly ad infinitum (perhaps because of some special way ng2 change detection treats getters). Removing the getter and mapping it using a regular property seems to have fixed the issue. It's probably my ignorance as how to change detection works. That's the problem with trying to weave two technologies together (Angular 2 and MDL) when you barely understand either :)
@zladuric @mebibou thank you both for your help.
Edit: Another thing I've noticed even after I got it working is this: If I have a button on the page that manually invokes componentHandler.upgradeAllRegistered(), and if I hit the button after the page has loaded, all the selectfields stop working. It's not an issue for me at the moment, but at some point I'll spend time investigating why this is happening.