-
-
Notifications
You must be signed in to change notification settings - Fork 103
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
Inherited bindable properties in custom elements #507
Conversation
It looks my antique JS-fu is not as good as it used to be. function Frob() { }
var x = new Frob();
x.constructor; // Frob
Object.getPrototypeOf(x).constructor; // Frob So I guess everything is fine 🙂 |
Boop. |
Re-boop. Is this still being worked on? This would greatly reduce code and maintenance in our codebase as we now have to copy and maintain all attributes for similar components (for instance our form plugin) |
I'm not working on it because it's done. Waiting for @EisenbergEffect to decide if he wants to merge that. |
@jods4 Thanks. I guess I'm at the mercy of @EisenbergEffect then :) |
It needs a solid code review and unfortunately I've had to spend time on
other areas of the framework recently. Maybe @jdanyow can review?
…On Feb 21, 2017 2:57 AM, "Wesley Overdijk" ***@***.***> wrote:
@jods4 <https://github.com/jods4> Thanks. I guess I'm at the mercy of
@EisenbergEffect <https://github.com/EisenbergEffect> then :)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#507 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAIBnXHDtez9qjcce9iwJ8x9elvns6jcks5resMjgaJpZM4LP91D>
.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jods4, thanks for the PR, I'm not an expert on internals of Aurelia to do proper CR, but i added one comment
dist/aurelia-templating.d.ts
Outdated
@@ -908,8 +908,6 @@ export declare class SlotCustomAttribute { | |||
constructor(element?: any); | |||
valueChanged(newValue?: any, oldValue?: any): any; | |||
} | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jods4, i think You should revert all changes to generated code (last time i checked, generating code was part of release process)
Yes, when I opened this PR two months ago I did not know what the policy for |
Did this get merged in? I have a whole slew of CustomElements extending a base element that aren't playing nice in 0.26.1 |
@icegnome nope. As per the status of this PR and the comments above it's still awating review. |
It's my fault really. I'm just a little hesitant due to the caveats. @jods4 Maybe you and I can do a quick meeting some time to discuss in detail. |
@EisenbergEffect we can. Note that the main caveat was TS inheritance not working in ES5 but this has been fixed in TS 2.2. |
It's been fixed! Nice. |
See microsoft/TypeScript#12488, I'm really glad this one finally landed. 🎉 |
After about half a year I reviewed my old StackOverflow-question regarding this topic: http://stackoverflow.com/questions/38607571/how-to-inherit-bindable-properties-in-aurelia I am also one of those desperately looking for inheriting the bindable properties. @jods4 Is there any chance that you publish this "fix" as an addon that can override the default behavior? |
@Spontifixus I'm sorry this is rather deep inside Aurelia, I don't think I can cleanly extract it. In the meantime, if you don't want to repeat each class ParentResource {
@bindable propA;
@bindable propB;
}
@extendBehavior(ParentResource)
class DerivedResource extends ParentResource {
@bindable propC;
} This is rather neat and shouldn't be hard to do. |
@jods4 Thank you for the quick reply! Creating a decorator should not be that hard, but do you have a tipp for me on how to extend a class with decorated properties? |
Has this PR been merged in the meantime? I have tried the following:
Is this intended or is this just one of the glitches @EisenbergEffect mentioned above? |
Sure! You don't need to walk the inheritance chain and all that shit as you get the class to copy from in a parameter. Then you can get it's metadata with help from Then you can look at its metadata Doing so should be the automatic equivalent of re-declaring and decorating every property in the derived class. |
That might be the TS glitch in action. |
I am using the following setup: Work is done by Webpack (2.1.0-beta.25) with ts-loader (^0.8.2), using Typescript ^2.2.1. The tsconfig.json looks as follows:
|
@Spontifixus I'm not sure, it's strange. Maybe it's the That seems unlikely, though. Can you check your |
@jods4 where do I find that? There is no tslib to be seen anywhere near that project. All typescript related things I see are the typescript package and the ts-loader package. (The binding to |
Should be in your output JS code somewhere (top of file normally) |
Took me awhile to find it - because I looked in the wrong file. But eventually I found it. It looks exactly as in the code you referenced. |
@jods4 I am a bit stuck right now in applying your code to what I have intended. I now went for extending the class using decorators instead of inheriting them. I cannot however figure out how to use the BindableProperty class correctly. There is a StackOverflow-question regarding this by another user. Could you have a look there? http://stackoverflow.com/questions/43918811/how-to-add-bindable-attributes-or-any-other-decorators-to-a-typescript-class-via |
@Spontifixus sorry I wanted to have a look at this again but just could not find the time to. Can you post your |
@jods4 I have a base component which offers a generic view that is configurable. I'd like to extend the component with hard coded configurations in a minimalistic manner, inheritance suits this approach. On the contrary, had I used decorators to do the job, I'd still have to replicate the @bindable definitions as well as make an implementation class(ViewModel) that gets decorated that I could pull into a View. Composition by properties could work, though I'd have to include the property path when binding (assuming the following would work my.composed.property.bind="hello bindable"), otherwise I would have to remap the bindings from the class intended to use inheritance to the class being composed. |
@jods4 Thank you for the reply. I have a whole bunch of other stuff to do at the moment, so I am not continuously working on this. At the moment I have no working copy at hand, but it seems getting the DI container working in a decorator is far from trivial, as @EisenbergEffect stated here. But as I understand from the code you reference the DI container is essential in getting the behavior initialized which I need for both the |
@jods4 @Spontifixus @EisenbergEffect I have reviewed your PR and find it quite minimal as an addition to the framework (and the steps are well documented). I have further used this PR in conjunction with HEAD (master), and it seems to be running flawlessly. @EisenbergEffect I would say this is a good solution for inheritance with binding, but you may have bigger intentions for fully inheritable components? Thanks a lot @jods4! UPDATE: |
+1 for merging this |
Hello. I have stumbled into an issue designing my Aurelia application that partially seems to relate to this pull request (which seems to solve my issue when merged). I have created a stackoverflow question explaining my situation. It seems that having this pull request resolved will allow me to design my Aurelia application the way I planned. My stack overflow question - https://stackoverflow.com/questions/44680903/aurelia-issue-with-using-a-shared-class-specification-for-properties-in-parent +1 for merging this |
I would also really like to see this merged, inheritance appears to work until you have multiple things inheriting from it, which of course is the whole point :) Definitely burned a few hours on it. |
@EisenbergEffect, @jods4, @Spontifixus Re: inheritance of particular annotations strategy, would it be possible to add some meta data to the annotation definition that the framework could handle all these annotations(@useview, @viewResources, @containerless, @bindable etc) in a similar manner to this PR. Perhaps the user could override this metadata setting on startup if they opt not to have the inheritance (though I think this would be a rare case) Otherwise the option for creating "Inhertiable components" would provide for micro optimizations. |
@tjad We can then think about demand for more inheritable features. I think one should be very cautious here and look at them on a case by case basis and not generalize too much. For example, I purposefully did not patch custom attributes (only custom elements), because the interaction of inherited Another example from your list: |
Is this now done and in aurelia framework? |
@Infuser PR is still open... |
Thanks @jods4 for the quick response sounds like the work is done any idea when it will be released |
Nope. If you look up you'll see that this has been ready for a while now. :( |
@Infuser, I guess You should ping @EisenbergEffect about merging this PR. As i understand, the last comment from @EisenbergEffect
could have been a reaction based on misunderstanding @jods4 comment that said that inheritance ( I'd also like to see it merged even if custom decorator could sometimes be used to achieve similar result. @jods4, @EisenbergEffect, could You add Your comments & thoughts? |
My comment above is related to the fix in TypeScript. I'm glad that's worked out. Generally speaking, I'm very hesitant about adding support for inheritance because I think inheritance is bad ;) However, I'd be willing to merge this PR in and add support on the condition that @jods4 or someone else write a new article for our documentation, explicitly covering inheritance with components. The article should show how, explain the limitations and constraints, and provide some guidance, along with examples. If we can have that, I'll merge this in and release it shortly thereafter. I really don't want to put this feature out there without clear documentation though. |
@EisenbergEffect Does this mean that you are not inevitably looking at an "inheritable component"? Re the docs: This PR wont particularly sit well(look good) if you want documentation on the explicit use of inheritance with components. This is only 1 of the required parts, hence currently the limitations/nuances are immense regarding inheritance - little things the Aurelia team seem to neglect (More than likely due to oversight) @EisenbergEffect Honestly, being the leader of this project, your non-support for such an integral feature of ES6, which is in fact obscured by your framework (WHICH I LOVE USING!) doesn't instil confidence. At the least, I was hoping you could schedule some team support around this issue and help us with a bit of direction. Apart from community support, @jods4 seems to be the only help with direction. I was keen to get helping with the necessary to fully enrich the extensibility of Aurelia, but you have a biggish project and without direction and no support from the core team this proves difficult. |
I have agreed to merge in the initial core support for inheritance, pending documentation. After that, we can continue to improve this feature going forward based on concrete use cases from the community. @tjad You are welcome to join the other 542 contributors to Aurelia by helping out in this effort. |
Thanks @EisenbergEffect, this being the case, it should be worth my time helping with documenting the usage/nuances. Thanks for the prompt response. |
Absolutely. We want to take feedback from the community and use the real-world use cases to help drive framework evolution. Just consider this as a first, non-breaking step towards inheritance support. It will enable some new scenarios, but maybe not everything we want just yet. So, we iterate on it and continue to improve it over time. |
@jods4 In trying to comply with the contribution guides, could you please amend the git message with a body as well as make the subject more elaborate, I believe the footer can be omitted. https://github.com/DurandalProject/about/blob/master/CONTRIBUTING.md#subject As a first draft, (Based on your opening comment of this PR) " Ability for @bindable properties to be inherited from a base class of custom elements |
I'm going to make some tweaks to the documentation. After that, we'll get this out in the next release. |
Thanks everyone for getting this done very much appreciated |
Thank you for merging this! For those of you looking for answers to the suggestion to solve this using composition rather than inheritance, I have written up how to achieve that over on StackOverflow: https://stackoverflow.com/a/45361429/1521227 |
Just being curious here, any timeline on when we could expect this feature to be released? |
Just a heads up, I may have found an oversight with the merged fix. In a template, when I include 2 custom elements having the same inherited parent that has a common https://gist.github.com/tjad/4414b3517f71112c0f49de59afb443a9 when I remove the commonBindable property, the resources load fine. - hence why I am logging this issue here. I picked this issue up in my application, and though I get a UPDATE: Will try do some further digging into the issue, but wont be too soon. ├── aurelia-dialog@1.0.0-beta.3.0.1 |
@tjad Please read the PR description above, in particular the restrictions:
|
Overview
This PR adds support for
@bindable
properties inherited from a base class in a custom element.This has been asked for several times, the open issue for that being #463.
The way
HtmlBehaviorResource
is used by Aurelia is unfortunately not inheritance-friendly. For this reason, this PR is very narrow in scope:@bindable
properties. No other aspect from the baseHtmlBehaviorResource
is propagated to descendant classes.value
property would works precisely.Additionally, the following restrictions apply:
HtmlBehaviorResource
metadata. So be sure to have at least one@bindable
or@customElement
or something like that on the derived class. Note that@useView
is not stored there.constructor
remark in the review section below.Usage
Here's a trivial example of what is now possible. A base class provides some common behavior, with exposed bindable properties and two descendant classes create actual custom elements with some customizations.
calculator.ts
calculator.html
app.html
Tests
I included new tests to demonstrate the changes in metadata.
That said, this is clearly not enough to check that everything works properly in practice and in all browsers, as the restrictions described above show.
I tested that the sample above works properly in ES6, and TypeScript ES5 (with patched
__extends
copied from Babel).Review
The changes are small but this is a tricky part of Aurelia. To make reviewing easier I split the implementation and
dist
in two commits.For the most part, the changes have no impact on code that doesn't use inheritance.
For people who already use inheritance by repeating the
@bindable
metadata, this is supported (last declaration wins).And then there's
bindable-property.js
, which you'll want to review carefully.I had to change the way
getObserver
install itself and especially how it finds the correct behavior. That was one part that was clearly not inheritance friendly.Previously it found its behavior by capturing it and passing it around. I am now doing it by looking at metadata.
This is all fine, but it assumes
prototype.constructor
is properly set. This is the case with ES6, Typescript or Babel generated code. I don't know if Aurelia supports people writing plain ES5 for everything and not properly settingprototype.constructor
. That kind of code would break.That's all folks! 🎉
/cc @EisenbergEffect @jdanyow