These are chat archives for ractivejs/ractive

16th
Jul 2018
kouts
@kouts
Jul 16 2018 12:18
I have a component e.g
Ractive.components['foo'] = Ractive.extend({...});
in which I want to add methods like this:
Ractive.components['foo'].prototype['test'] = function(){...};
is there a more elegant way to do it?
I don't want to "hardcode" the methods inside the component's constructor
because depending on where it's used there may be other methods needed
Cerem Cem ASLAN
@ceremcem
Jul 16 2018 13:32
can you provide a real-life example to this?
just curious...
kouts
@kouts
Jul 16 2018 13:42
I'm working on a dataset component influenced by @dagnelies dataset
so I want to have methods that "transform" the data internally so that if for example
a date is in data like 2018-12-24 and in view like 24.12.2018 when you search for 24.12.2018
you have to have results
any way imagine you have a component
that may call some functions that you pass as names like this
<dataset somemethods="{date: datemethod, money: moneymethod}">
where datemethod and moneymethod
are component methods
kouts
@kouts
Jul 16 2018 13:48
these methods (datemethod and moneymethod)
they don't exist inside the component
kouts
@kouts
Jul 16 2018 13:56
so I'm adding them to the prototype
Chris Reeves
@evs-chris
Jul 16 2018 14:44
is it always a methods hash? If so, I'd just Object.assign it to the instance at init
kouts
@kouts
Jul 16 2018 14:45
Nice idea, and if I wanted the same methods available in all instances -as I do now by putting them in the prototype-?
Chris Reeves
@evs-chris
Jul 16 2018 14:47
if you want them on the prototype, I'd distribute the component as a use plugin and handle it there
kouts
@kouts
Jul 16 2018 15:25
I haven't explored how to use the use plugin system yet :blush:
Chris Reeves
@evs-chris
Jul 16 2018 15:37
I've found it quite useful for publishing
kouts
@kouts
Jul 16 2018 18:06
do you have an example of it somewhere, I'm sure I've asked for this before but I can't remember when
Chris Reeves
@evs-chris
Jul 16 2018 18:12
I should probably add a page to the docs for that under concepts
a plugin is just a function ({ Ractive, instance, proto }) => void
Ractive is always the Ractive lib for wherever the call is being invoked
instance and proto change depending on how the plugin is used
for Ractive.use, instance is Ractive and proto is Ractive.defaults (the Ractive prototype)
for Ractive.extend({ use: [...]}), instance is the component constructor and proto is the prototype for the component
for new Ractive({ use: [...] }), instance is the instance and proto is the instance
Chris Reeves
@evs-chris
Jul 16 2018 18:17
This lets you publish just about any extension to ractive as a plugin, since you can add component methods, instance methods, components, events, etc through the same interface
I usually publish my components as a function that returns a plugin function, so
export default function(opts = {}) {
  return function({ Ractive, instance, proto }) {
    instance.components[opts.name || 'MyComponent'] = Ractive.extend({
      ...
    });
  };
}
Chris Reeves
@evs-chris
Jul 16 2018 18:23
just slide a call to the setup function in a use somewhere e.g. import mycmp from 'wherever'; Ractive.use(mycmp()); /* or */ new Ractive({ use: [mycmp()] })
in your case, you want to add methods to the proto, so you could take them in opts and in the plugin function Object.assign(proto, opts.methods)
kouts
@kouts
Jul 16 2018 18:26
Ok so in my example lets say I have this component Ractive.components['foo'] = Ractive.extend({...});
Then to add some methods I could do Ractive.use(Ractive, Ractive.components['foo'], additional_methods_here) ?
kouts
@kouts
Jul 16 2018 18:36
Or does foo have to be instantiated so like Ractive.use(Ractive, foo, additional_methods_here)
Chris Reeves
@evs-chris
Jul 16 2018 18:45
in your case
function foo(opts = {}) {
  return function({ Ractive }) {
    const cmp = Ractive.extend({ ... });
    Object.assign(cmp.prototype, opts.methods || {});
    Ractive.components[opts.name || 'foo'] = cmp;
  };
}

// from code using component
Ractive.use(foo({ methods: {
  someMethod() {},
  otherMethod() {}
} }));
additional methods are added to the component proto when setting it up
you can also make it generic enough to work without requiring a global component
Joe Turner
@JoeTurner-IR
Jul 16 2018 20:43
is there a way I can fire an event when an element is rendered to the page
like this
<div on-render="@this.fire('adsf')"></div>
where the div is inside some kind of condition or loop
I guess this is a backwards way of doing things
but could be handy in edge cases like the one I've got
Cerem Cem ASLAN
@ceremcem
Jul 16 2018 20:50
@JoeTurner-IR I guess you are attempting to assign some default values in a recursive-like tree
anyway, what would be the problem if you created a component for this purpose?
Chris Reeves
@evs-chris
Jul 16 2018 21:03
@JoeTurner-IR try <div>{{@.fire('asdf') && ''}}</div>
slightly hacky, but should get you there
Cerem Cem ASLAN
@ceremcem
Jul 16 2018 21:03
...it's interesting that we can't even define a component that fires an event on render
Chris Reeves
@evs-chris
Jul 16 2018 21:03
another approach that's slightly less hacky would be to use a decorator, where you could also control stuff like only firing once
well, I mean you can always fire an event from the render event, which is also fired on render :)
side-effecting interpolators are not generally encouraged, but sometimes they are ridiculously useful
Joseph
@fskreuz
Jul 16 2018 21:07
Lifecycle events can be listened.
Cerem Cem ASLAN
@ceremcem
Jul 16 2018 21:07
...my mistake, we can absolutely define a component that fires any event on render
also, an empty component can be used for this purpose too Playground
Chris Reeves
@evs-chris
Jul 16 2018 21:10
if there are many (100+) iterations rendered at once, I would discourage component use due to the overhead though
Cerem Cem ASLAN
@ceremcem
Jul 16 2018 21:11
@kouts so you make a component and let me pass my custom function to that component. If that's the case, I also had a similar case and I prefer passing an object to the component with an attribute <mycomp settings="{{somesettings}}" ... and pass appropriate functions with that object. Works like a charm for me.
Cerem Cem ASLAN
@ceremcem
Jul 16 2018 21:20
@evs-chris it's good to know the "hacky" way. I loved it
Chris Reeves
@evs-chris
Jul 16 2018 21:21
bonus is that it doesn't require an element