Peter
Peter

Reputation: 14508

Aurelia - Custom element inside repeat.for is not created after collection changes

In Aurelia, I've setup a list of template objects and allow a user to add new templates using a button. Each template has a detail view that consists of a custom element.

<div class="middle-box">
    <a class="btn btn-primary" click.delegate="addMailTemplate()"><i class="fa fa-envelope"></i> Add Email</a>
    <a class="btn btn-primary" click.delegate="addNotificationTemplate()"><i class="fa fa-bell"></i> Add Notification</a>
</div>
<div class="row p-sm">
    <div class="col-xs-3 no-padding">
        <ul class="nav nav-pills nav-stacked" id="myTabs">
            <li class="${template.IsActive ? 'active' : ''}" repeat.for="template of templates">
                <a data-toggle="pill" href="#tab-${template.Id}" aria-expanded="${template.IsActive ? 'true' : 'false'}"> ${template.Key}</a>
            </li>
        </ul>
    </div>
    <div class="col-xs-9 no-padding">
        <div class="tab-content dad-templates-tabpane">
            <div id="tab-${template.Id}" class="tab-pane" repeat.for="template of templates">
                <div class="panel">
                    <div class="panel-body">
                        <email-template-editor template.bind="template" if.bind="template.TemplateType == 'email'"></email-template-editor>
                        <notification-template-editor template.bind="template" if.bind="template.TemplateType == 'notification'"></notification-template-editor>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

The problem I have is that when I create a new template (I add the new template to the templates collection) it correctly adds the new item to the list of templates but it doesn't create a new custom email-template-editor element.

As you can see, the template-editor is not being rendered

On the initial load, it does load all the templates as you can see here:

enter image description here

So this must have something to do with the binding of the repeat.for?

Here's the viewmodel js for the emailtemplateeditor.js

export class EmailTemplateEditor {
    activate(model) {
        this.template = model;
    }
}

And here's the html for the emailtemplateeditor.html

<template bindable="template">
    <div class="row">
        <div class="form-group">
            <div class="col-md-2 vcenter">
                <label for="key" class="control-label label-lg">Identification Key: </label>
            </div>
            <div class="col-md-6">
                <input type="text" id="key" value.bind="template.Key" class="form-control input-lg" placeholder="Enter the unique key" maxlength="100" />
            </div>
            <div class="col-md-2">
                <label class="label-lg">
                    <i class="fa fa-info-circle fa-2x label-lg" title="This is the parameter you pass into the WEBNOTIFICATION('Identification key') or EMAIL('Identification key') function."></i>
                </label>
            </div>
        </div>
    </div>
    <div class="row">
        <div class="form-group">
            <div class="col-md-2 vcenter">
                <label for="to" class="control-label label-lg">To: </label>
            </div>
            <div class="col-md-10">
                <input type="text" id="to" value.bind="template.To" class="form-control input-lg" placeholder="To: Enter recipients" />        
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col-md-2 vcenter">
            <label for="subject" class="control-label label-lg">Subject: </label>
        </div>
        <div class="col-md-10">
            <input type="text" id="subject" value.bind="template.Subject" class="form-control input-lg" placeholder="E-mail subject" />        
        </div>
    </div>
    <div class="row">
        <div class="col-md-12">
            <label for="key" class="control-label label-lg">Body: </label>
        </div>
        <div class="col-md-12">
            <textarea value.bind="template.Body" rows="20" class="form-control template-mail-body"></textarea>
        </div>
    </div>
</template>

Here's the code for the add methods and the data loading intially:

activate() {
    var id = $("#data-analysis-definition-id").val();
    var sortByCreatedAt = function(a, b) {
        return (a.CreatedAt < b.CreatedAt) ? -1 : ((a.CreatedAt > b.CreatedAt) ? 1 : 0);
    }
    return Promise.all([
        this.dataAnalysisDefinitionService.get(id).then(data => {
            this.dad = data;
        }),
        this.dataAnalysisDefinitionService.getEmailTemplates(id).then(data => {
            data.forEach(function(obj) { obj.TemplateType = "email"; });
            this.templates = this.templates.concat(data);
            this.templates.sort(sortByCreatedAt);
        }),
        this.dataAnalysisDefinitionService.getNotificationTemplates(id).then(data => {
            data.forEach(function(obj) { obj.TemplateType = "notification"; });
            this.templates = this.templates.concat(data);
            this.templates.sort(sortByCreatedAt);
        })
    ]);
}

addMailTemplate() {
    var self = this;
    this.dataAnalysisDefinitionService.createEmailTemplate(this.dad.Id).then(function (newTemplate) {
        self.templates.push(newTemplate);
    });
}

addNotificationTemplate() {
    var self = this;
    this.dataAnalysisDefinitionService.createNotificationTemplate(this.dad.Id).then(function (newTemplate) {
        self.templates.push(newTemplate);
    });
}

Upvotes: 3

Views: 452

Answers (2)

bigopon
bigopon

Reputation: 1964

The code is correct and should work. Probably your newly created template doesn't have the right TemplateType. Ensure that it has either email or notification and things should be ok.

Upvotes: -1

Jesse
Jesse

Reputation: 3622

Your code seems to be fine, from what you've shared here. Is it possible you can inspect your DOM using the Aurelia Inspector for Google Chrome and see if all the properties are correctly bound to the newly added element?

You need an Id:

id="tab-${template.Id}"

and a TemplateType:

if.bind="template.TemplateType == 'email'"

Upvotes: 3

Related Questions