Search code examples
angularangular2-directivesangular-router

Angular 2 bound values not shown until after mouse move when routing


I have a directive which adds an icon to whatever element it is added to. When that icon is clicked, I need to call a function in whatever component contains the directive. This function uses router.navigate to navigate a named-outlet to a new component. Everything works, except that after I click the icon, the new contents of the named router outlet don't show until I move my mouse.

Here are the relevant parts of the directive:

@Directive({
    selector: '[editable]',        
})
...    
@Output() doEdit = new EventEmitter<string>();
...
private emitEditMessage(){
        console.log("emitting");   <-----just so I can see that the function is called
        this.doEdit.emit(this.targetField);
}

Here is where I use the directive in a template:

<span editable (doEdit)="editField($event)">
    {{CurrentPersonInfo}}                              
</span>

Here is the function from my parent component that is called when the directive emits:

public editField(fldName :string){
    console.log("before nav");
    this.router.navigate([{ outlets: { 'task-pane': 'edit' } }]);
    console.log("after nav");
}

When I run and click on the icon shown by the directive, I see the expected messages in the console: "emitted", "before nav", "after nav". But the secondary route ("name:task-pane") doesn't update with the new contents until I move the mouse.

Update: Just noticed this: if the content in the task pane is just a hard-coded string, then it is shown immediately. However, if I add an interpolated binding to a property of the task pane component (e.g {{Title}} ) then any hard-coded text before the binding shows immediately. The bound text and any hard-coded text after it doesn't show up until I move the mouse.

Here is the panel component:

@Component({
    ...
})
export class PersonEditPanelComponent extends BasePanel{    
    constructor(){
        super();
        console.log("panel ctor");
    }

    public Title: string = "Edit Person"
}

Here is the panel template HTML:

This shows immediately.

{{Title}}

This and the "Title" won't show until I move the mouse after clicking the icon

Finally, if I put a link on my parent component that just directly calls its editField function (the same one called when the directive emits), then everything works - all text (hard-coded and bound) shows immediately.

So, my questions: Is there something inherent in the routing that is causing this delay for bindings being resolved? Any idea how to fix this?

Thanks!


Solution

  • Solved. I took a different approach to attaching the event listener and got it all working. Here are the details:

    Injected Renderer2 via the constructor on my directive:

    constructor(elem: ElementRef, private renderer: Renderer2, private router: Router)
    {}
    

    Then after the code that added the icon into the page, I attached the listener like this:

    this.renderer.listen(this.editIcon, 'click', (evt) => {
        this.doEdit.emit(this.targetField);
    });
    

    Where editIcon is the DOM element I created and added:

        private editIcon = document.createElement('a');
        this.editIcon.innerHTML = '<i class="fa fa-pencil" aria-hidden="true" style="font-size:18px; color:red;"></i>';
        node.appendChild(this.editIcon);