MVCoconut / coconut.ui

Wow, such reactive view! Much awesome!
The Unlicense
89 stars 9 forks source link

A case study about almost similar tabular data #69

Closed grepsuzette closed 4 years ago

grepsuzette commented 4 years ago

With those structures:

typedef Foo = { final a:String; final b:Int; c:Bool; };
typedef Bar = { final ref_foo: Int; final d:Float; final e:String; };
typedef Baz = { final ref_foo: Int; final f:Int; };

enum Fooaraz {
    Foo(v:tink.pure.List<coconut.ds.Updatable<Foo, Foo>>);
    Bar(v:tink.pure.List<coconut.ds.Updatable<Bar, Bar>>);
    Baz(v:tink.pure.List<coconut.ds.Updatable<Baz, Baz>>);
}

And a function getfoo:Int->Foo:

public function getfoo(ref:Int) : Foo 
    return switch foo_collection.get(ref).data {
        case Loading: make_a_dummy_foo();
        case Failed(e): make_another_dummy();
        case Done(v): v;
    }   

final foo_collection : Collection<Int, Foo, Updatable<Foo, Foo>> = ..; 

Is it possible to have a view TableFooBarBazView that would show respectively 3, 5 and 4 columns in a table (depending on the enum), in a not too tortured way?

class TableFooBarBazView extends coconut.ui.View{
    @:attr var enumlist : Promised<Fooaraz>;

    function render() '
        <>?</>
    ';
}

My view presently is working for Foo. Making 3 different views seems easy here.

But can't help thinking, if we have fields like [a,b,c,d,e,f,g,h], then another view adds a mere [x] to that; at some point it has to become a classical problem.

I also don't see very well how to work with my ref and my getfoo(Int) here, but the 2 problems are probably too intertwined in my mind to clearly see a solution.

grepsuzette commented 4 years ago

On the paper, the view should look like either one:

| a | b | c |
| x | x | x |
| x | x | x |

| a | b | c | d | e |
| x | x | x | x | x |
| x | x | x | x | x |

| a | b | c | f |
| x | x | x | x |
| x | x | x | x |

I could imagine an intermediate fourth typedef called Dirty aggregating all three others like a b c ?d ?e ?f. Then, functions Foo->Dirty, Bar->Dirty, Baz->Dirty. Then in the view <if {d != null }><td>{d}</td></if>, etc. Somehow this feels like programming javascript in 1999 but I guess it would be quite easy. I wonder how difficult would be the other ways.

kevinresol commented 4 years ago

I guess you want a generic tabular view that renders a generic column-row data structure rather than a specific one.

back2dos commented 4 years ago

Yeah, something like this:

class TableView<T> extends View {
  @:attribute var rows:List<T>;
  @:attribute var columns:List<Named<T->RenderResult>>;
  function render() '
    <table>
      <thead>
        <for ${c in columns}>
          <td>${c.name}</td>
        </for>
      </thead>
      <tbody>
        <for ${r in rows}>
          <for ${c in columns}>
            <td>${c.value(r)}</td>
          </for>
        </for>
      </tbody>
    </table>
  ';
}

The descriptor for four columns can be derived from that for three columns. I suspect Haxe will have some variance issues with it, but that's nothing a cast can't fix ^^

grepsuzette commented 4 years ago

Cool! It gives me a skeleton, I will see then if it's possible to set callbacks to render particular columns, to add buttons, render dates and what not. (edit: oh, seems already your columns attribute) Thanks :)

grepsuzette commented 4 years ago

Works all perfectly! Such a pleasure to work with this suite, quite unbelievable :) Closing this issue.