最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - debug Aurelia ViewModel similar to ko.toJson - Stack Overflow

programmeradmin3浏览0评论

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

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

Share Improve this question edited Nov 2, 2016 at 23:26 Nerdroid asked Sep 3, 2015 at 2:07 NerdroidNerdroid 14k5 gold badges61 silver badges71 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 16

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

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?

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'}
发布评论

评论列表(0)

  1. 暂无评论