7.0.1850-testing

Gui Input

Web components comme with a number of inputs to handle all GreyCat types, but they also work well with js types.

You can specify the the exact input component you want, for example:

  • gui-input-string will create a input of type text
  • gui-input-number will create a input of type number

But you don’t have to, by passing the value internally we will infer the type and return the appropriate component

  • <gui-input value="[1,2,3]"> will return a gui-input-array

This also works by specifying the greycat type

  • <gui-input type="core::time"> will return a gui-input-time

Reflexivity, Shared Types Front <-> Back

One of the most annoying parts of fullstack development is having to define the same types and forms twice — once for the backend and then again on the frontend. That’s where our abi really comes in handy. It’s built to cut out that duplication and make it way easier to keep everything in sync, so you’re not constantly switching between layers fixing mismatches or re-writing the same logic.

Adding a new attribute to the gcl type requires no extra changes to any of the front end code.

The following example leverages <gui-object> to display the result returned by the greycat server, a more in depth explanation here

const el = document.createElement('div');
el.className = 'list';
const form = document.createElement('gui-input-object');
// Add the typed structure specified in gcl, currently all field are empty but we could prefill them with default values
form.value = new gc.project.Entry('One');

// You cold also build the input from the arguments of the function in gcl
// el.value = new gc.project.updateEntry$args();
const button = document.createElement('sl-button');
button.textContent = 'Execute';
const result = document.createElement('gui-object');
result.header = true; // Will display the qualified name of the type as module::type

button.onclick = async () => {
  if (form.validate()) {
    try {
      const res = await gc.project.updateEntry.apply(null, [form.value]);
      result.value = res;
    } catch (err) {
      result.value = err;
    }
  }
};
el.append(form, button, result);
enum EntryStatus {
  good;
  bad;
  none;
}
type Entry {
  name: String;
  date: time;
  status: EntryStatus;
  open: bool;
  value: float;
}

@expose
fn updateEntry(entry: Entry) {

  // Here typically you would store it in the graph
  return entry;
}

String

el = document.createElement('gui-input-string');
el.value = 'Hello, GreyCat!';

Number (int/float)

const el = document.createElement('gui-input-number');
el.value = 3.1415;

Boolean

const el = document.createElement('gui-input-bool');
el.value = true;

core::time

const el = document.createElement('gui-input-time');
el.value = gc.core.time.fromMs(Date.now());

core::duration

const el = document.createElement('gui-input-duration');
el.value = gc.core.duration.from_days(1);

Arrays

el = document.createElement('gui-input-array');
el.value = [1, 2, 3, 4, 5];

Js Map

const el = document.createElement('gui-input-map');
el.value = new Map([
  ['name', 'Bob'],
  ['age', 42],
]);

Enums

const el = document.createElement('gui-input-enum');
el.value = gc.core.TimeZone['Europe/Luxembourg'];

Objects

const el = document.createElement('gui-input-object');
el.value = new gc.project.Sensor(40, 2);
type Sensor {
  valA: int;
  valB: int;
}

Functions

const el = document.createElement('div');
el.className = 'list';

const fn = document.createElement('gui-input-fn');
fn.value = new gc.project.addTwoNumbers$args(40, 2);

const btn = document.createElement('sl-button');
btn.textContent = 'Execute';
btn.onclick = async () => {
  try {
    const res = await gc.project.addTwoNumbers.apply(null, fn.args);
    result.textContent = `Result: ${res}`;
  } catch (err) {
    result.textContent = `${err}`;
  }
};

const result = document.createElement('div');

el.append(fn, btn, result);
// in project.gcl
@expose
fn addTwoNumbers(a: int, b: int) {
  return a + b;
}