Deno: Learn how to use Ogone
Tags: ogone, deno, javascript, typescript
Published: 2020-07-10 09:01:55

# Intro
Hey! I'm Rudy Alula, and I work as Front-end Developer for [Stanley Robotics](https://www.youtube.com/watch?v=Wo1OmfoufmQ), which is solding the first outdoor robot parking vallet in automobile industry.

with this article, you're about to learn more on **Ogone** but first you need to understand what's happening and to [README](https://github.com/SRNV/Ogone)

Those who are familiar with Front-End tools will recognize some of the next features.

# Installation
First you need to download [Deno](https://deno.land/#installation). And then run: `deno --version`

at this moment Ogone is built under `deno 1.1.3`
so please `deno upgrade` if your version is under.

**for this tutorial we will follow this architecture:**
```
- components
  |__root-component.o3
  |__greeting-component.o3
- deps.ts
- mod.ts
```

this is the moment to load Ogone. in your `deps.ts` start by importing Ogone:
```typescript
// ./deps.ts
export { default as o3 } from 'https://x.nest.land/Ogone@0.18.0-rc.0-4/mod.ts';

// ./mod.ts
import { o3 } from './deps.ts';

o3.run({
  entrypoint: '/root-component.o3',
  modules: '/modules',
  port: 8080, // dev port
});
```
this file will configure the compilation of your application. 

------
# Getting Started

In the `root-component`, import another component like this with the `use ... as` statement.

```haml
// ./components/root-component.o3
use ./greeting-component.o3 as 'greeting-component';
<greeting-component />
```

let's see what we can do in the **greeting-component**.
```haml
// ./components/greeting-component.o3
<p>Hello World</p>
```
> write the hello world inside an element
> unwrapped textnodes throw an error

yup ok, not so cool but this is like every tools has to present a *Hello world* example.

## Require data from the parent component
hmm, let's say Hello Deno instead but through the root-component. open your `greeting-component.o3` and start using the `require ... as` statement.
```haml
// ./components/greeting-component.o3
require name as String;
<p>Hello ${name}!</p>
```

As you can see the first part of the component is the configuration of the component. you can see the first statement `require <property> as <constructors>`
> if empty, name will throw an error. so you need to provide  the *Deno* to the greeting-component.

```haml
// ./components/root-component.o3
use ./greeting-component.o3 as 'greeting-component';
<greeting-component :name="'Deno'" />
```
## List of name

now you have seen two statements `use ... as` and `require ... as`.
#### what if our component has to present a list of random names ?

First, define the names, by using protocol element and `def` statement, follow this example:
```haml
// ./components/greeting-component.o3
require name as String;
<proto>
  def:
    people:
      - Mary Grey
      - Sam Lee
      - Christopher Van Sperso
   index: 0
</proto>
<p>Hello ${name}!</p>
```
here to understand the [protocol](https://github.com/SRNV/Ogone) element.
So we got now an index and a list, but nothing change. hmm let's use the *mounted/onMounted* feature of Ogone, we will use setInterval to see all the list. 
inside the protocol element, use `default` statement like following:

```haml
// ./components/greeting-component.o3
require name as String;
<proto>
  def:
    people:
      - Mary Grey
      - Sam Lee
      - Christopher Van Sperso
    index: 0
    actual: null
  default:
    setInterval(() => {
      this.actual = this.people[this.index];
      this.index++;
      if (this.index > this.people.length) this.index = 0;
    }, 1000);
</proto>
<p>Hello ${actual || name}!</p>
```

`default` comes from the switch statement. It's the initialization case used by Ogone. this `default` statement is used when the component is mounted.  
Now that the presentations are made, we have one problem. one loop is running until the user exit the window.

let's save this interval.
```haml
// ./components/greeting-component.o3
require name as String;
<proto>
  def:
    people:
      - Mary Grey
      - Sam Lee
      - Christopher Van Sperso
    index: 0
    actual: null
    interval: null
  case 'destroy':
    clearInterval(this.interval);
  break;
  default:
    this.interval = setInterval(() => {
      this.actual = this.people[this.index];
      this.index++;
      if (this.index > this.people.length) this.index = 0;
    }, 1000);
</proto>
<p>Hello ${actual || name}!</p>
```
> as you can see all properties has to be defined in `def`
> setting an property during the runtime will throw an error

ok that's better like this. you can spot the case `case 'destroy'`. this case is selected when the component is removed.

#### what if I want to use user events instead of an interval ?
You can use the flag `--click`. to test it, write a button element, set the flag attribute **'--click:caseName'**, this will say to Ogone, select this case when there is a click.
example:
```haml
<proto>
case 'click:caseName':
  // do things
break;
</proto>
<button --click:caseName />
```
apply this inside the greeting-component. btw you can also use `before-each` statement:
```haml
// ./components/greeting-component.o3
require name as String;
<proto>
  def:
    people:
      - Mary Grey
      - Sam Lee
      - Christopher Van Sperso
    index: 0
    actual: null
  before-each:
     const update = () => {
       this.actual = this.people[this.index];
      if (this.index > this.people.length) this.index = 0;
     };
  case 'click:prev':
    this.index--;
    update();
  break;
  case 'click:next':
    this.index++;
    update(); 
  break;
</proto>
<p>Hello ${actual || name}!</p>
<button --click:prev>-</button>
<button --click:next>+</button>
```
`before-each` is selected before all cases, including the default case. this allows you to define vars that you can use in every cases.

## use Reflections
Ogone comes out with few new features. one of those is the **reflection**. this act like a `computed: {...}` in Vue or the `$:` in Svelte, for those who knows.
the syntax `this.reflect => value;` or 
```tsx
this.reflect => {
  // do things
  return value;
}
```
#### how can I use it inside the greeting-component ?
good question. you can write it under the `before-each` statement like this:
```haml
// ./components/greeting-component.o3
require name as String;
<proto>
  def:
    people:
      - Mary Grey
      - Sam Lee
      - Christopher Van Sperso
    index: 0
    actual: null
  before-each:
     this.actual => {
        if (this.index > this.people.length) this.index = 0;
        return this.people[this.index];
     };
  case 'click:prev': this.index--; break;
  case 'click:next': this.index++; break;
</proto>
<p>Hello ${actual || name}!</p>
<button --click:prev>-</button>
<button --click:next>+</button>
```
> reflections outside the `before-each` statement are not parsed

## For and If flags

#### what if I want to see all the names ?

there is the flag `--for="array as (value, key)"` where array is a property or a new array.
erase the useless statements. and insert the paragraph element with the flag.

```haml
// ./components/greeting-component.o3
require name as String;
<proto>
  def:
    people:
      - Mary Grey
      - Sam Lee
      - Christopher Van Sperso
</proto>
<p --for="people as (person)">Hello ${person || name}!</p>
```

#### I don't want to see Mary Grey in the list, what can I do ?

there is two solutions. using `.filter()` inside the flag `--for`
```haml
// ./components/greeting-component.o3
require name as String;
<proto>
  def:
    people:
      - Mary Grey
      - Sam Lee
      - Christopher Van Sperso
</proto>
<p --for="people.filter(n => n!== 'Mary Grey') as (person)">Hello ${person || name}!</p>
```

or using the `--if` flag:
```haml
// ./components/greeting-component.o3
require name as String;
<proto>
  def:
    people:
      - Mary Grey
      - Sam Lee
      - Christopher Van Sperso
</proto>
<p --for="people as (person)" --if="person !== 'Mary Grey'">Hello ${person || name}!</p>
```

sometimes you will have a long list of name to write, this is annoying inside a component that we want to keep small. Ogone lets you download ressources inside the protocol. assuming that we have a file `names.yaml` inside a folder `sources`.
```haml
// ./components/greeting-component.o3
require name as String;
<proto def="./sources/names.yaml" />
<p --for="people as (person)" --if="person !== 'Mary Grey'">Hello ${person || name}!</p>
```
inside `./sources/names.yaml`
```yaml
  people:
      - Mary Grey
      - Sam Lee
      - Christopher Van Sperso
```


---
# Store

```
- components
  |__stores
     |__names.stores.o3
  |__root-component.o3
  |__greeting-component.o3
- deps.ts
- mod.ts
```

in Ogone, everything is a component. To create a store, start by creating a `names.store.o3` file. 
> names is for our example and '.store' is not required.

this component will looks like this:

```haml
// ./components/stores/names.store.o3
<proto type="store" namespace="names">
  def:
    people:
      - Mary Grey
      - Sam Lee
      - Christopher Van Sperso
</proto>
```
inject this store component inside your greeting-component

```haml
// ./components/greeting-component.o3
use ./stores/names.store.o3 as 'store-names';
require name as String;
<store-names namespace="names" />
<proto>
  def:
     people: []
</proto>
<p --for="people as (person)" --if="person !== 'Mary Grey'">Hello ${person || name}!</p>
```
> the type of the component has to start the name of the component, if it's not starting you will get an error

#### how can I add one name to the store

you can use the object `Store`, that you can only access if the component uses a store component.
First create an action inside your store component:
```haml
// ./components/stores/names.store.o3
<proto type="store" namespace="names">
  def:
    people:
      - Mary Grey
      - Sam Lee
      - Christopher Van Sperso
  case 'action:setName':
    this.people.push(ctx.name);
  break;
</proto>
```
> all actions case have to start with 'action:'

now inside the component use the `Store` object. like following:
```haml
// ./components/greeting-component.o3
use ./stores/names.store.o3 as 'store-names';
require name as String;
<store-names namespace="names" />
<proto>
  def:
     people: []
  default:
    Store.dispatch('names/setName', {name: 'Ogone is Cool'});
</proto>
<p --for="people as (person)" --if="person !== 'Mary Grey'">Hello ${person || name}!</p>
```

now if you want to update this name, start writing a mutation inside the store:
```haml
// ./components/stores/names.store.o3
<proto type="store" namespace="names">
  def:
    people:
      - Mary Grey
      - Sam Lee
      - Christopher Van Sperso
  case 'action:setName':
    this.people.push(ctx.name);
  break;
  case 'mutation:UPDATE_NAME':
    this.people[ctx.id] = ctx.name;
  break;
</proto>
```
> as the actions, the mutations have to start with 'mutation:'

Now, use it inside the component. For this, you need to use the flag `--bind` on an input. like `<input --bind="property" />` but in our greeting-component we are going to use the property name.

```haml
// ./components/greeting-component.o3
use ./stores/names.store.o3 as 'store-names';
require name as String;
<store-names namespace="names" />
<proto>
  def:
     people: []
     name: Ogone
  case 'update:name':
    Store.commit('names/UPDATE_NAME', {
      id: this.people.length -1,
      name: this.name,
    });
  break;
  default:
    Store.dispatch('names/setName', {name: 'Ogone is Cool'});
</proto>
<p --for="people as (person)" --if="person !== 'Mary Grey'">Hello ${person || name}!</p>
<input --bind="name" />
```

# Conclusion

with this article you learnt few features from Ogone:
* `use ... as 'component-name'`
* `require <props> as <constructors>`
* `<proto [type="store"[ >`
* `def: <yaml>`
* `default:`
* `before-each:`
* `case 'destroy'`
* `case 'update:property'`
* `--click:...`
* `--for="array as (item, key)"`
* `--if`
* `--bind="property"`
* `Store.dispatch('namespace/action')`
* `Store.commit('namespace/mutation')`

that's a good list for a start. 
keep playing with it and mind that Ogone is still open for [Pull requests](https://github.com/SRNV/Ogone/pulls) or [issues](https://github.com/SRNV/Ogone/issues), and it still under development.