New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Attach multiple decorators #399
Comments
I vote for this feature too (I also assumed you could have multiple decorators per element) :) |
I agree with @browniefed as well, but I think the syntax should be different. It's strange to have 2 decorator attributes. |
@MartinKolarik Yeah I think having multiple decorator attributes but you are passing in data and other attributes of various formats you can't exactly comma delimit them. |
@browniefed I was wondering about |
This is an interesting thread. I agree that this would probably be a worthwhile feature. The syntax question is tricky, and I don't think there's a perfect solution, but one thing that I think is important is that decorators should be ordered. It's not hard to imagine a situation where decorator x has to initialise before decorator y, because if decorator y goes first it will mutate the DOM in such a way that x breaks. For that reason I'm a bit hesitant about solutions that use object notation or attribute names, since these are (conceptually at least) unordered lists. Maybe that's just my implementer's hat obscuring my vision, but it feels like a bit of a red flag (attributes could be forced to maintain their order with a bit of parser re-engineering, but it would be trickier with object notation). For that reason, my current inclination is towards semi-colons: <div decorator='edit;validate'>edit decorator runs first, then decorator</div>
<!-- with parameters -->
<div decorator='edit:1,2,3;validate:{{foo}},{{bar}},{{baz}}'>edit decorator runs first, then decorator</div> Thoughts? |
What happens in the event that a simple string getting passed in contains a semicolon? That's why I'm always hesitant to use basic delimiters and even complex delimiters. |
@Rich-Harris Good point! I've been considering semicolons as well, but objects felt more natural and just like @browniefed I'm not sure what would happen if there was a semicolon in the parameter. |
The parser would have to accommodate semicolons, it wouldn't be a simple The question is whether |
If that's the case then I'm happy with it. If somehow someones data happens to be setup so perfectly that the parser identifies something as a decorator then so be it. Same sacrifices being made in that you couldn't technically observer on the key * since this would register as a pattern observer thus just don't use an asterisk as a key for your data. |
My third idea was |
IMO, two order dependent decorators should be wrapped under a single decorator. Don't design the syntax around that. It's beginning to look like a JSON DSL for javascript. (And what about the decorator teardown on argument change, does the whole line of decorators need to be recreated?) I'd rather see the decorator syntax become more simplified by doing something similar to events in making the attribute name more meaningful, e.g. My .02 from other side of things... |
@Rich-Harris , I would say use same behavior as Events.
@MartinKolarik , with that it wouldnt feel natural with the current template syntax, I feel it is like an exception. :P Maybe we can have |
@martypdx makes some good points. Particularly now that decorators get updated/reapplied when their arguments change (#429) there is scope for all kinds of weird and hard-to-debug behaviour. The idea of combining decorators is a good one: <div decorator='edit_and_validate:[1,2,3],[{{foo}},{{bar}},{{baz}}]'></div> Ractive.decorators.edit_and_validate = function ( node, editParams, validateParams ) {
var editDecorator = Ractive.decorators.edit.apply( this, editParams ),
validateDecorator = Ractive.decorators.edit.apply( this, validateParams );
return {
teardown: function () {
validateDecorator.teardown();
editDecorator.teardown();
}
};
}; This could be modified to accommodate decorators that support the @codler Decorator directives do actually use the exact same process as |
Allthough combining decorators like in the post above could be nice, I can imagine a real hell when/if you got a large list of generic and reusable decorators to combine into various combinations of 2 to x number of decorators per element.. So at least this shouldn't be the only way to attach multiple decorators to an element. I would prefer the |
@cfenzo I really like the In the meantime, this will probably help 90% of people on this thread. Here is a generic multi-decorator. Example template is:
First, I've notice a common pattern for updating decorators with no teardown, so I created this function:
Which can be invoked like so:
The multi decorator is like so:
I used this pattern in the template: And it gets passed the decorators like they get passed to Ractive:
Check out full example here: http://jsfiddle.net/jWYv8/1/ I would change it to an array if we wanted to guarantee order and a few other details (needs to handle the update case) Let me know if this is of interest and I'll set it up as a proper plugin. |
This version handles updates and teardowns
|
Wow, @martypdx ! that's just beautiful! 😃 Beeing able to set the order of the decorators would be nice :) |
Created a plug-in, demo at http://martypdx.github.io/ractive-decorators-helpers/ EDIT: I recommend using newer plugin mentioned below: https://github.com/JonDum/ractive-multi-decorator |
@martypdx the plugin is great! |
@martypdx how do I get a reference to Ractive inside of the decorator? |
@MartinKolarik: For the
For the |
Thanks @martypdx, actually I modified your plugin a bit (and was about to post it when your comment appeared) so that:
|
@martypdx seems you accidentally dropped a PDF file into |
I might be missing a major point here, but that what I understand. Each decorator "constructor" have access to its "parent" ractive-instance, which exposes all accessible decorators, using This version, inspired from @martypdx , will use combined decorators out of the box, no need to pass a special "combined" decorator to each ractive instance, or the call a The usage in the template is still the same: // some global decorator
Ractive.decorators.globaldecorator = function() {/* ... */ return { teardown: function( ) { }, update: function() { }; } };
var ractive = new Ractive({
el: 'target',
template: '<div decorator="multi:{ localdecorator: [ {{ dynamicArg1 }}, arg2, arg3 ], globaldecorator: {{singleArg}}, anotherdecorator: true } " ></div>',
// combined with local decorators
// no need to "pre-combine" anything
decorators: {
localdecorator: function() { /* .... */, return { teardown: function() {}; } },
anotherdecorator: function() {/* ... */, return { teardown: function() { }, update: function() {} }; }
}
}); The global multi decoratorRactive.decorators.multi = function(node, args) {
var decorators = {};
Object.keys(args).forEach(function(name) {
if (typeof this.decorators[name] === 'function') {
decorators[name] = this.decorators[name].apply(this, [node].concat(args[name]));
}
}.bind(this));
return {
update: function(args) {
Object.keys(args).forEach(function(name) {
if (decorators[name]) {
decorators[name].update.apply(this, [].concat(args[name]));
}
}.bind(this));
},
teardown: function() {
Object.keys(args).forEach(function(name) {
if (decorators[name]) {
decorators[name].teardown.apply(this);
}
}.bind(this));
}
};
}; usage<div
id="myelement"
decorator="multi:{
localdecorator: [ {{ dynamicArg1 }}, arg2, arg3 ],
globaldecorator: {{singleArg}},
anotherdecorator: true
}"
></div> |
@akhoury 👍 I thought of this after I wrote it, but I haven't needed to combine decorators in a long while :) |
Just searched for this after I ran into the same issue. Perhaps a format of |
I second @briancray 's suggestion - the |
+1 for |
Although this is a relatively old topic, I have to agree that this proposed change is at least worth discussing. Perhaps this can be readdressed after the 0.8 release. |
Until the use of multiple decorators is supported by Ractive natively, I've create a "Meta"-Decorator, for combining multiple decorators on one element. In contrast to Ractive-decorator-helpers you can use my solution out of the box with your existing decorators, because you don't have to change the way how to create your decorators in JS (which I don't like about Ractive-decorator-helpers). Usage <div decorator="combine:{decorator1:[param1, param2], decorator2:param, decorator3:{{myValue}}}"> Text </div> Nothing else to do! Here it is: /**
* Meta-Decorator to use multiple decorators on a single HTML-element
* usage: decorator="combine:{decorator1:[param1, param2], decorator2:param}"
*/
Ractive.decorators.combine = function (node, args) {
var name, decorator;
var decorators = {};
args = _.clone(args, true);
for (name in args) {
if ((decorator = this.decorators[name])) {
decorators[name] = decorator.apply(this, [node].concat(args[name]));
}
}
return {
teardown: function () {
for (var name in decorators) {
decorators[name].teardown.apply(this);
}
},
update: function (args) {
var name, decorator;
for (name in decorators) {
decorator = decorators[name];
decorator.update && decorator.update.apply(this, [].concat(args[name]));
}
}
};
}; EDIT / Bugfix: I've changed this line in the code above: |
@LeJared brilliant!! |
To use the multi decorate from above or Ractive-decorator-helpers you have to change the way you create and assign your decorators to your Ractive instance. I don't like that, because you can't use exiting decorators out of the box, but have to create special combined versions of your decorators, to use them togethe. This also means, You have to create as create a new "combined decorator" for every combination separately! Using my solution, you only have to change the way you assign your decorators in then templates and you can use any combinations of any decorators on the fly by just adding them in the template. Benefit: once, Ractive supports multiple decorators natively, you only have to change your templates (you'll have to do this anyway!) but you don't need to change your decorators them selfs. BTW: I've fixed a bug in the code above. |
I guess the initial idea of @martypdx that was true, but see my comment above, which basically was a slight improvement, you don't have to pre-combine them that's how you use it in the template - all other decorators remain the same, and you don't have to create a combination before hand.
|
Yeah, after I wrote that I realized that you could just look them up from global registry. What I find interesting is that I have yet to need to double up decorators on an element. |
The only situation where I've needed to double up a decorator is for a 'truncate' decorator, where I also want to have a 'tooltip' decorator on the element. I didn't need to have a multi-decorator plugin, though. I just instantiated the tooltip decorator from the truncate decorator manually. I'm not sure if that strategy is generally applicable however. |
@LeJared: I haven't needed a multi decorator. |
For ease of access, I slapped up @akhoury's solution as a repo and put it up on npm as |
@JonDum 👍 Maybe it should be <div
id="myelement"
decorator="each:{
localdecorator: [ {{ dynamicArg1 }}, arg2, arg3 ],
globaldecorator: {{singleArg}},
anotherdecorator: true
}"
></div> |
hey @browniefed, may i ask why is this being closed? I thought it was labeled as a future enhancement. |
@akhoury ah sorry I assumed it was already implemented for some reason haha, was cleaning up all my old open issues. Will keep thsi open |
This now possible in edge with multiple |
BOOYAH. What version will it be released in? Is Edge 0.8, 0.9, or even farther out? |
Edge is 0.8. I'm planning on cutting an alpha week after next. |
I was under the assumption that you could attach more than one decorator.
We are attempting to have 2 decorators. One for editing, and one for validating.
Although it appears that you can only have one decorator per element.
So I guess this is a feature request to have more than one decorator per element.
http://jsfiddle.net/M3MkH/
The text was updated successfully, but these errors were encountered: