adriatic / screenshots

repository serving as the storage for screenshots
0 stars 0 forks source link

QR Code related questions #12

Closed adriatic closed 8 years ago

adriatic commented 8 years ago

_I would like to use this text (with your answers) as a part of the online help for app developers_

Issue 1

How to get the QR Code rendered initially A simple way to do that is to use the "literal bind" like this

<div k-qrcode="k-widget.two-way: qrcode; k-size.bind: 200; k-value.bind = 'Hello World' "></div>

However, the original example uses this JavaScript "structure" to define the initial values of all settings for all components on this page - not just the QR Code

  initialData = {
    qrValue: "Hello World",
    qrOptions: {
        errorCorrection: "L",
        encoding: "ISO_8859_1",
        background: "#FFFFFF",
        color: "#000000",
        size: 200,
        border: {
            color: "#FFFFFF",
            width: 0
        }
    }
  };

Can you please "transcribe" the jQuery code from the original sample into ES6 code by correcting this attempt I wrote

import {bindable} from 'aurelia-templating';

export class Api {

  viewModel = {
    qrValue: "Hello World",
    qrOptions: {
        errorCorrection: "L",
        encoding: "ISO_8859_1",
        background: "#FFFFFF",
        color: "#000000",
        size: 200,
        border: {
            color: "#FFFFFF",
            width: 0
        }
    }
  };

  @bindable qrValue = viewModel.qrValue;

  errorCorrectionDataSource = [
    { errorCorrection: 'L', value: 'L' },
    { errorCorrection: 'M', value: 'M' },
    { errorCorrection: 'Q', value: 'Q' },
    { errorCorrection: 'H', value: 'H' }

  ];

  encodingDataSource = [
    { encoding: 'ISO_8859_1', value: 'ISO_8859_1' },
    { encoding: 'UTF_8', value: 'UTF_8' }
  ];

  setOptions() {
    let validValue = this.validValue;

    try {
      this.qrcode.setOptions({
        value: this.qrValue,
        errorCorrection: this.errorCorrection,
        encoding: this.encoding,
        size: this.size
      });

      validValue.innerHTML = '';
    } catch (error) {
      validValue.innerHTML = error.message;
    }
  }

  propertyChanged() {
    this.setOptions();
  }

}

Here is my HTML which I believe is fine (with the exception that I did not pepper each UI element with "event handler" as I do not want to for example redraw the whole widget after each click on the numeric text box

<template>
  <require from="./api.css"></require>
  <div id="example">

    <div class="demo-section k-content">
      <div k-qrcode="k-widget.two-way: qrcode; k-size.bind: 200; k-value.bind = qrValue "></div>
    </div>

    <div class="box wide" id="qrConfig">
      <div class="box-col">
        <h4>Value</h4>
        <ul class="options">
            <li>
                <textarea id="qrValue" class="k-textbox" data-bind="value: qrValue" rows="5" cols="20"></textarea>
            </li>
        </ul>
      </div>

      <div class="box-col">
        <h4>Options</h4>
        <ul class="options second-col">
            <li>
                <label for="errorCorrection">Error correction level:</label>
                <k-drop-down-list k-data-source.bind="errorCorrectionDataSource"
                                  k-on-change.delegate="setOptions()"
                                  k-value.two-way="errorCorrection"
                                  k-data-text-field="errorCorrection"
                                  k-data-value-field="errorCorrection"
                </k-drop-down-list>
            </li>

            <li>
              <label for="encoding">Encoding:</label>
              <k-drop-down-list k-data-source.bind="encodingDataSource"
                                k-on-change.delegate="setOptions()"
                                k-value.two-way="encoding"
                                k-data-text-field="encoding"
                                k-data-value-field="encoding"
                </k-drop-down-list>
            </li>

            <li>
              <label for="size">Size:</label>
              <input id="size" k-numerictextbox="k-value.bind: 120;
                               k-format.bind: n0;
                               k-min.bind: 60;
                               k-max.bind: 200;
                               k-step.bind: 10" />

            </li>

            <li>
              <label for="borderWidth">Border width:</label>
              <input id="borderWidth" k-numerictextbox="k-value.bind: 5;
                                      k-format.bind: n0;
                                      k-min.bind:0;
                                      k-max.bind:20;
                                      k-step.bind:1" />
            </li>
        </ul>
      </div>

      <div class="box-col">
          <h4>Colors</h4>
          <ul class="options">
              <li>
                <label for="bordercolor">Border color</label>
                <input id="bordercolor" k-color-picker="k-widget.two-way: colorPicker;
                                        k-value.bind: qrOptions.border.color"
                 />
              </li>

              <li>
               <label for="backgroundColor">Background color</label>
                <input id="backgroundColor" k-color-picker="k-widget.two-way: colorPicker;
                                        k-value.bind: qrOptions.background"
                 />
              </li>

              <li>
               <label for="moduleColor">Module color</label>
                <input id="moduleColor" k-color-picker="k-widget.two-way: colorPicker;
                                        k-value.bind: qrOptions.color"
                 />
              </li>
          </ul>
      </div>

  </div>

</template>
JeroenVinke commented 8 years ago

Right so Telerik's API sample uses MVVM framework stuff of Kendo. We need to translate stuff like kendo.observable into Aurelia which isn't a straight forward thing to do.

What I would do is create @bindable variables for all properties (background, bordercolor, border width etc) and bind each control to these properties. For example with the background color:

                <input id="backgroundColor" k-color-picker="k-value.two-way: background."/>

Because every property is @bindable, you can create a change handler for each of these properties:

@bindable background = '#FFFFFF';

backgroundChanged() {
  // update the qrcode
}

Note the <propname>Changed convention. But you'll notice that it would be quite a lot of code to create a change handler for every property, so I recommend using the global propertyChanged handler instead:

@bindable background = '#FFFFFF';

propertyChanged(prop, newValue, oldValue) {
  // where prop = background if the background property has changed
}

In the propertyChanged function you need to refresh the qrcode. You do this by passing all these properties to setOptions:

propertyChanged(prop, newValue, oldValue) {
  this.qrcode.setOptions({
    background: this.background
 });
}

because you use the change event handlers of the @bindable decorator, you won't need some of the k-on-change event handlers anymore

adriatic commented 8 years ago

The code

propertyChanged(prop, newValue, oldValue) {
  this.qrcode.setOptions({
    background: this.background
 });
}

seems wrong - it does not use any of its parameters and has a very specific code (that handles onlu background property)

I would think that the method's code should have a switch statement (assuming that JavaScript has that statement) on prop and then set each option based on prop value. As I know that you know that, I will assume that you just write a "symbol" for real propertyChanged method :-)

JeroenVinke commented 8 years ago

Yes, but you don't have to use those parameters at all:

propertyChanged() {
  this.qrcode.setOptions({
    background: this.background
 });
}

The propertyChanged is our signal that something has changed and that we have to redraw the QR code. I only added the background property to demonstrate how it would work

JeroenVinke commented 8 years ago

Note that instead of the initial value object you used:

  viewModel = {
    qrValue: "Hello World",
    qrOptions: {
        errorCorrection: "L",
        encoding: "ISO_8859_1",
        background: "#FFFFFF",
        color: "#000000",
        size: 200,
        border: {
            color: "#FFFFFF",
            width: 0
        }
    }
  };

you can now put the initial values per @bindable property: @bindable background = '#FFFFFF'

adriatic commented 8 years ago

After all this jostling :-) - checked in an incomplete QR code into 0.6.0 branch, simply to get this process going.

There are three open issues:

  1. I did not create the event handlers for either numeric text boxes nor color choosers as I could not strike a reasonable balance between getting the widget refreshed to often and never. I would be very interested in seeing what will you do to fix this.
  2. The widget does not show initially - because of the issue 1 above.
  3. The color choosers have no effect

Also note that I (by copying the Barcode wrapper) got stuck with that validValue think which I can see the purpose off (show the KendoUI error) but obviously do not know how to use in the context of this sample