Aurelia-Dialog: ref elements not working?

So in another thread I was asking about markdown editors and I was trying to setup a few tests using some of them.

I currently have a custom dialog input form setup that just uses a textarea for some content that I would like to have some text formatting options for the user, and I was trying to set a ref to that element to pass into the CKEditor. For some reason it wasn’t showing up. So i immediately thought, “What did I screw up?!” :wink:

I proceeded to create a code pen to make sure I was implementing it correctly and it worked there. (in a plain view, not dialog)
I then went back to my code, and created a test on a non-aurelia-dialog served page, and it worked there.

However for an aurelia-dialog served view template it appears its not setting ref type element bindings as its not available in the attached hook.

Is this expected behavior, a bug, I did screw up?

1 Like

I think it’s unclear what error / issue you ran into. I do things you mentioned too, and ref works fine, so it would be great if you could provide an example / sandbox demo

1 Like

I used your hello world pen for the first test.
I am unsure how to setup aurelia-dialog there though.

Is that available someplace from a CDN (or is it already in the aurelia-script?

Actually not sure a pen is the best place to try that as I need separate files.

1 Like

So I found this gist.run: https://gist.run/?id=5abaa0a16e8ee3c01efed8f99a4c0d20

and just added a ref to one of the templates button, and used alert to display it in the attached hook. It appears to be working there.

The only difference is I am using typescript that I can see. Now to look to see if I can find something like this one using typescript.

1 Like

Just in case its something that is easily visible to the trained eye here are the view and viewmodel.

View
<template>
    <style>
        ux-dialog-overlay.active {
            background-color: black;
            opacity: .5;
        }

        ux-dialog-header {
            border-radius: 6px 6px 0px 0px;
            background-color: yellow;
            padding: 3px;
        }
        .edit-news-title {
            margin: 5px;
            font-weight: bold;
        }
        .edit-news-item {
            margin: 10px 10px 10px 40px;
        }

        .edit-news-input {
            width: 50ch;
        }

        .edit-news-short-input {
            width: 20ch;
        }

        .edit-news-largecheckbox {
            margin-left: 4px;
            transform: scale(2);
        }
    </style>

    <ux-dialog with.bind="model">
        <ux-dialog-header>Edit News Item #${id}</ux-dialog-header>

        <ux-dialog-body style="height: 800px; overflow-y: scroll;">
            <button class="btn btn-danger" click.trigger="delete()">Delete</button>
            
            <!-- <div class="edit-news-title">Created On</div>
            <div class="edit-news-item">${createdOn | dateFormat: "YYYY-MM-DD"}</div>

            <div class="edit-news-title">Created By</div>
            <div class="edit-news-item">${createdBy}</div> -->

            <div class="edit-news-title">Never Expires</div>
            <div class="edit-news-item">
                <input class="edit-news-largecheckbox" type="checkbox" checked.bind="neverExpires">
            </div>
            
            <div class="edit-news-title">Start Date</div>
            <div class="edit-news-item">
                <input type="datetime-local" value.bind="startDate | dateToLocal: 'YYYY-MM-DDTHH:mm:ss'">
            </div>
            
            <div class="edit-news-title">End Date</div>
            <div class="edit-news-item">
                <input type="datetime-local" value.bind="endDate | dateToLocal: 'YYYY-MM-DDTHH:mm:ss'">
            </div>

            <div class="edit-news-title">IsActive</div>
            <div class="edit-news-item">
                <input class="edit-news-largecheckbox" type="checkbox" checked.bind="isActive">
            </div>
            
            <div class="edit-news-title">IsPublic</div>
            <div class="edit-news-item">
                <input class="edit-news-largecheckbox" type="checkbox" checked.bind="isPublic">
            </div>
            
            <div class="edit-news-title">IsPinned</div>
            <div class="edit-news-item">
                <input class="edit-news-largecheckbox" type="checkbox" checked.bind="isPinned">
            </div>
            
            <div class="edit-news-title">IsHighlight</div>
            <div class="edit-news-item">
                <input class="edit-news-largecheckbox" type="checkbox" checked.bind="isHighlight">
            </div>

            <div class="edit-news-title">Tags (Max 20 char)</div>
            <div class="edit-news-item">
                <input value.bind="tagInput" maxlength="20" class="edit-news-short-input"> <button click.trigger="addTag()">Add Tag</button>
                <ul style="margin: 10px;">
                    <li style="width: 180px; height: 30px;" repeat.for="item of tags">${item} <button class="pull-right" click.trigger="removeTag($index)">Remove</button></li>
                </ul>
            </div>

            <div class="edit-news-title">Title (Max 50 char)</div>
            <div class="edit-news-item">
                <input value.bind="title" maxlength="50" rows="10" class="edit-news-input">
            </div>
            <div class="edit-news-title">Content</div>
            <div>
                <textarea id="editor" ref="editor" value.bind="content"></textarea>
            </div>
View
        </ux-dialog-body>
        <ux-dialog-footer>
            <button click.trigger="cancel()">Cancel</button>
            <button click.trigger="save()">Save</button>
        </ux-dialog-footer>
    </ux-dialog>
</template>
ViewModel
import { CommonDialogs } from 'resources/dialogs/common-dialogs';
import { inject } from 'aurelia-framework';
import { DialogController } from 'aurelia-dialog';
import { NewsEntry } from 'models/news-entry';
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';

@inject(DialogController)
export class EditNewsItem
{
    model: NewsEntry;
    tagInput: string;
    tags: string[];
    commonDialogs: CommonDialogs
    editor: Element;
ViewModel
    constructor(private dialogController: DialogController)
    {
    }
    activate(model)
    {
        console.log(this.editor);

        this.model = model.newsItem;
        this.commonDialogs = model.commonDialogs;
        this.tags = this.model.tags;
        this.tagInput = "";        
        
        ClassicEditor.create(this.editor)
            .then(editor =>
            {
                console.log(editor);
            })
            .catch(error =>
            {
                console.error(error);
            });
    }
ViewModel

    addTag()
    {
        if(this.tagInput && this.tagInput.length > 3)
        {
            this.model.tags.push(this.tagInput);
            this.tags = this.model.tags;
            this.tagInput = "";
        }
    }

    removeTag(index: number)
    {
        this.model.tags.splice(index, 1);
        this.tags = this.model.tags;
    }

    cancel()
    {
        this.dialogController.cancel();
    }

    save()
    {
        this.dialogController.ok(this.model);
    }

    delete()
    {
        this.commonDialogs.showMessage("This will move the news item to the archive. Are you sure?", "Delete", ["Yes", "No"])
        .whenClosed(response => {
            if(response.wasCancelled) return;

            this.model.isDeleted = true;
            this.dialogController.ok(this.model);
        });
    }
}
1 Like

I see, if you question was why this.editor resolves to undefined in activate, then the answer is it’s the expected behavior. ref attribute will create a binding, that will resolve during bind() lifecycle, activate lifecycle is specific to composition and will be invoked before bind(), thus it is undefined.

activate can be understood as a step to prepare the necessary data for binding.

1 Like

Gah, I was right when I thought I was wrong! I just caught that myself.
To many freaking A’s…yeah, I scewed up with activate instead of attached.

Thanks for your time on this, I appreciate it. Now to go crawl into my hole again. :flushed:

1 Like

One final note on this.

CKEditor would still not display its interface after I fixed the incorrect initialization inside activate by moving it into attached.

Process of elimination ended up showing that it does not like being inside a with.bind.

Removing the with.bind, or moving it outside that enclosing section finally displayed the interface and started working.