debug Aurelia ViewModel similar to ko.toJson

天大地大妈咪最大 提交于 2020-01-03 07:21:33

问题


in knockoutjs you can output the ViewModel in a nice json format for debugging

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

if there is a way to accomplish the same in Aurelia


回答1:


You could create a custom element.

Here's an example: 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




回答2:


The closest I've got is to define a Value Converter. So in json.js I have

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

then in my view-model index.js I have my data:

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

and finally the view index.hml binds and uses the converter:

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

However, I'm stumped at the moment by the lack of live binding between the model and the HTML so this may not fully answer your question?




回答3:


As an addendum to the answer of Jeremy Danyow, you can also use a custom binding behavior on a particular attribute of your view model, instead of the whole view model. This has the advantage that you have control over the elements you want to see, therefore you can avoid the problem with circular dependencies (if you watch only those elements you know to be non-circular...)

First define a JsonValueConverter (same as the one in Phil's answer):

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

Then the binding behavior. Note that the binding notifies itself via a custom signal to cope with deep model updates.

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);
    }
}

You can put both classes in the same file, e.g. json.js. Then require it in your template:

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

... or make it available as a global resource.

Here's an example: https://gist.run/?id=bde01135fa85f76202c72c11d3cb183a

You could also extract the signalling to a second custom behaviour, just as Jeremy Danyow did in this SO answer. With this in place, you would just do:

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


来源:https://stackoverflow.com/questions/32365884/debug-aurelia-viewmodel-similar-to-ko-tojson

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!