Aurelia:视图和视图模型的继承

时间:2018-08-21 14:20:23

标签: typescript aurelia

我正在构建一个Aurelia应用程序,该应用程序将基本上允许用户显示不同资源的不同列表。这些列表共享了一些功能,例如具有搜索和刷新功能的工具栏以及分页的资源列表。

我为单个资源创建了这个文件,并且一切工作都像个魅力,但是现在我需要复制TypeScript代码的大部分以及其他资源列表的HTML。我决定采用另一种方法,使用一些命名的视图槽和一个抽象的视图模型创建一个自定义元素。此操作在第一次运行时有效,但是在操作列表后,它将立即停止更新广告位内容。

有没有办法实现我想要做的事情?

任何帮助将不胜感激。

旁注:我试图创建一个简单的Gist来演示该问题,但似乎我能找到的最新CDN版本尚不支持视图插槽(我无法获得它)去工作)。 :(

基本上我想做的是:

list.html

<template>
    <div>list: ${counter}</div>
    <slot></slot>
    <button click.delegate="load()">Increase counter</button>
</template>

list.ts

import { autoinject } from 'aurelia-dependency-injection';
import { customElement } from 'aurelia-templating';

@customElement('list')
@autoinject
export abstract class List {
    public abstract counter;
    public abstract load();
}

resource.html

<template>
    <require from="./list"></require>

    <list>
        <div>resource: ${counter}</div>
    </list>
</template>

resource.ts

import { autoinject } from 'aurelia-dependency-injection';
import { List } from './list';

@autoinject
export class App extends List {
    public counter = 0;

    constructor() {
        super();
    }

    public load() {
        this.counter++;
    }
}

这将提供以下输出:

list: 0
resource: 0
<button>Increase counter</button>

单击按钮后,它应该同时增加了列表和资源计数器,但仍然显示资源“ 0 ”。 我的猜测是,该按钮正在没有实现的抽象父类上调用load函数,因此什么也不做。将按钮更改为子类是可以的,但实际上并不能帮助我减少代码。如何继续使用实现者的(资源)绑定上下文?有办法吗?还是我完全偏离了轨道?

编辑
所以我找到了解决它的方法,但是感觉不对。我更改了List中的以下位:

@bindable({defaultBindingMode: bindingMode.twoWay}) public abstract counter:number;

然后在resource HTML中:

<list counter.bind="counter">
    <div>users: ${counter}</div>
</list>

通过这种方式,它可以同步counter属性的绑定上下文。我希望有一种方法可以告诉List完全不具有自己的绑定上下文,因为从理论上讲,这可能会导致许多可绑定对象。有人知道我如何告诉List继承绑定上下文吗?

编辑2
找到了先前EDIT的另一种解决方法,删除了可绑定的行为,并在bind组件中实现了List回调。这使我可以访问父绑定上下文作为第一个参数。我将本地保存在List组件中,然后在counter属性更改时手动更新父绑定上下文。这仍然是一种解决方法,因为这会使List组件很大,但让我不必担心资源中的绑定。 List现在看起来像这样:

import { customElement } from 'aurelia-templating';
import { autoinject } from 'aurelia-dependency-injection';
import { observable } from 'aurelia-binding';

@customElement('list')
@autoinject
export abstract class List {
    private parentContext;
    @observable public abstract counter:number;

    bind(bindingContext) {
        this.parentContext = bindingContext;
    }

    counterChanged(newValue) {
        if (this.parentContext) this.parentContext.counter = newValue;
    }

    public abstract load();
}

我仍然对删除List组件的绑定上下文的方法感兴趣,完全让它继承父绑定上下文。

GitHub issue中提到的

注意指令。inheritBindingContext的行为类似于one-time的初始继承,因此在我的情况下没有用,但可能对其他人有用。

2 个答案:

答案 0 :(得分:1)

看看这篇博客文章 Aurelia Dynamic Compose 使用compose和v-model和model,您可以在同一列表中拥有不同的自定义元素

答案 1 :(得分:0)

After Edit 2 I was still getting issues when I had multiple resource lists implemented. It seemed like it was doing all kinds of functions x amount of times. So instead of manually syncing the binding contexts I now only update the parent (resource) context, like so:

List.ts

import { customElement } from 'aurelia-templating';

@customElement('list')
export abstract class List {
    public parentContext;
    public abstract counter:number;

    bind(bindingContext) {
        this.parentContext = bindingContext;
    }

    public abstract load();
}

List.html

<template>
    <div>list: ${parentContext.counter}</div>
    <slot></slot>
    <button click.delegate="parentContext.load()">Increase counter</button>
</template>

This is not only decreasing the complexity of my List, but also making a lot more sense and is less error prone.