调试Aurelia ViewModel类似于ko.toJson

时间:2015-09-03 02:07:20

标签: javascript aurelia aurelia-binding

在knockoutjs中你可以输出一个漂亮的json格式的ViewModel进行调试

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

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

3 个答案:

答案 0 :(得分:15)

您可以创建自定义元素。

以下是一个例子: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);
  }
}

<强>结果

result

答案 1 :(得分:3)

我最接近的是定义一个值转换器。所以在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之间缺乏实时绑定,我现在很难过,所以这可能无法完全回答你的问题?

答案 2 :(得分:2)

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

首先定义一个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在this SO answer中所做的那样。有了这个,你就会这样做:

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