调试 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'}
在 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'}