调试 Aurelia ViewModel 类似于 ko.toJson

debug Aurelia ViewModel similar to ko.toJson

在 knockoutjs 中,您可以以良好的 json 格式输出 ViewModel 以进行调试

<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>

如果有办法在 Aurelia 中完成同样的事情

您可以创建自定义元素。

举个例子:https://gist.run?id=9eea8902521f4523ee2c

app.html

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

  <input value.bind="firstName">
  <input value.bind="lastName">

  <debug></debug>
</template>

app.js

export class App {
  firstName = 'Donald';
  lastName = 'Draper';
}

debug.html

<template>
  <pre><code>${json}</code></pre>
</template>

debug.js

export class Debug {
  bindingContext = null;

  updateJson() {
    if (this.bindingContext === null) {
      this.json = 'null';
    } else if (this.bindingContext === undefined) {
      this.json = 'undefined'
    } else {
      // todo: use a stringify function that can handle circular references.
      this.json = JSON.stringify(this.bindingContext, null, 2);
    }
  }

  bind(bindingContext) {
    this.bindingContext = bindingContext;
    this.updateJson();
    this.interval = setInterval(::this.updateJson, 150);
  }

  unbind() {
    this.bindingContext = null;
    clearInterval(this.interval);
  }
}

结果

我最接近的是定义一个值转换器。所以在 json.js 我有

export class JsonValueConverter {
    toView(value) {
        return JSON.stringify(value, null, "\t");
    }
}

然后在我的视图模型中 index.js 我有我的数据:

export class IndexViewModel {
    data = {
        name: "nobody!"
    };
}

最后视图 index.hml 绑定并使用转换器:

<template>
    <require from="../resources/converters/json"></require>
    <pre textContent.bind="customElementModel | json"></pre>
</template>

但是,我现在对模型和 HTML 之间缺乏实时绑定感到困惑,所以这可能无法完全回答您的问题?

作为 Jeremy Danyow 回答的补充,您还可以在视图模型的特定属性上使用 custom binding behavior,而不是 whole 视图模型.这样做的好处是你可以控制你想看到的元素,因此你可以避免循环依赖的问题(如果你只看那些你 知道 是非循环的元素。 ..)

首先定义一个JsonValueConverter(和Phil的回答一样):

export class JsonValueConverter {
    toView(value) {
        return JSON.stringify(value, null, "  ");
    }
}

然后是绑定行为。请注意,绑定通过自定义信号通知自己以应对深度模型更新。

import {inject} from "aurelia-dependency-injection";
import {ValueConverter} from "aurelia-binding";
import {BindingSignaler, SignalBindingBehavior} from "aurelia-templating-resources";

@inject(BindingSignaler, SignalBindingBehavior)
export class JsonBindingBehavior {

    constructor(signaler, signalBindingBehavior) {
      this.signaler = signaler;
      this.signalBindingBehavior = signalBindingBehavior;
    }

    bind(binding, scope) {
        // bind the signal behavior (ie. listen on signal 'update-json')
        this.signalBindingBehavior.bind(binding, scope, 'update-json');

        // rewrite the expression to use the JsonValueConverter.
        // pass through any args to the binding behavior to the JsonValueConverter
        let sourceExpression = binding.sourceExpression;

        // do create the sourceExpression only once
        if (sourceExpression.rewritten) {
            return;
        }
        sourceExpression.rewritten = true;

        let expression = sourceExpression.expression;
        sourceExpression.expression = new ValueConverter(
            expression,
            'json',
            sourceExpression.args,
            [expression, ...sourceExpression.args]);

        // send signal to ourselves each 150ms to update the binding
        this.interval = window.setInterval(() => this.signaler.signal('update-json'), 150);
    }

    unbind(binding, scope) {
        window.clearInterval(this.interval);
        this.signalBindingBehavior.unbind(binding, scope);
    }
}

您可以将两个 类 放在同一个文件中,例如json.js。然后在您的模板中要求它:

<template>
  <require from="./json"></require>
  ...
  <pre>${myData & json}</pre>
</template>

...或将其作为全球资源提供。

举个例子:https://gist.run/?id=bde01135fa85f76202c72c11d3cb183a

您还可以将信号提取到第二个自定义行为,就像 Jeremy Danyow 在 中所做的那样。有了这个,你只需要做:

${myData | json & signal:'tick'}