I have a custom HTML tag <fancy-foo> that I would like to extend the functionality of. Some of the <fancy-foo> elements would be extended using the pretty-bar custom element, so that I can use them in my HTML as
<fancy-foo is="pretty-bar">
<!-- content -->
</fancy-foo>
so, I define classes FancyFoo and PrettyBar, define the fancy-foo element and extend it using pretty-bar, like so:
class FancyFoo extends HTMLElement {
constructor() {
super();
}
}
class PrettyBar extends FancyFoo {
constructor() {
super();
}
}
window.customElements.define('fancy-foo', FancyFoo);
window.customElements.define('pretty-bar', PrettyBar, {extends: 'fancy-foo'});
Sadly, Google Chrome spits out the error
Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry': "fancy-foo" is a valid custom element name
That's an odd error. Strangely, it says "fancy-foo" is a valid custom element name; I know that, but why should that throw an error?
What's going on here?
You cannot extend Custom Elements that way (with {extends: '...'}). You can only extend buit-in (= standard) HTML elements.
If you want to design PrettyBar as an extension of FancyFoo, you'll need to define it as an autonomous custom element:
class PrettyBar extends FancyFoo {...}
window.customElements.define('pretty-bar', PrettyBar)
Same thing for the HTML tag:
<pretty-bar></pretty-bar>
This way it is possible to create correct inheritance chain. Extended built-in element's class is further extensible:
class FancyFoo extends HTMLDivElement {
constructor() {super();}
}
class PrettyBar extends FancyFoo {
constructor() {super();}
}
window.customElements.define('fancy-foo', FancyFoo, {extends: 'div'});
window.customElements.define('pretty-bar', PrettyBar, {extends: 'div'});
<div is="fancy-foo"></div>
<div is="pretty-bar"></div>
customElements.define determines the is-name, constructor, and built-in's tag-name, if used this way. It does not need to know the exact constructor chain, provided it leads to the call of the appropriate built-in's constructor. You can establish the inheritance by extending one class by another.
Style it to override the div behavior, or use a more appropriate built-in element as base.
Related
I want to do this:
class Parent {
static myMethod1(msg) {
// myMethod2 is undefined
this.constructor.myMethod2(msg);
}
}
class Child extends Parent {
static myMethod2(msg) {
console.log('static', msg);
}
}
Child.myMethod1(1);
But it doesn't work. Is this possible some other way? I don't want to hard code Child.myMethod2 in Parent which I know would work since I want random child classes to be able to define/override the static method but call that method from the parent without prior knowledge of which class is the child.
myMethod2 is undefined because the code is wrong. this is class constructor in static methods, and this.constructor is the constructor of a constructor, i.e. Function. It should be:
class Parent {
static myMethod1(msg) {
this.myMethod2(msg);
}
}
This is antipattern, because Parent doesn't have myMethod2, and Parent.myMethod1() will result in error. It should either contain no-op myMethod2, or be labeled as abstract class to never be accessed directly.
I am new to Dart and I wonder if I can, for example, extend the DivElement class to create custom elements in one line of code. I am looking for something like this;
class RedBox extends DivElement {
RedBox(text) {
this.text = text;
this.style.background = "red";
}
}
RedBox myBox = new RedBox("Hello World");
document.body.append(myBox);
Of course I will have much more complex elements with custom functions. But just in general, is this possible?
When I try to run this, i get:
implicit call to super constructor 'DivElement()'
You can extend HTML elements, but there are a few requirements. The one you're running into now is that you need a RedBox.created constructor, and it can only redirect to its super class. created must be the only generative constructor, though you can add factory constructors.
Another requirement is that the element is registered with document.registerElement.
Try adding this:
class RedBox extends HtmlElement {
RedBox.created() : super.created() {
style.background = "red";
}
factory RedBox(text) => new Element.tag('my-redbox')..text = text;
}
document.registerElement('my-redbox', RedBox);
Some note on extending HtmlElement.
Example:
https://api.dartlang.org/1.14.1/dart-html/HtmlDocument/registerElement.html
Pitfalls:
Extending non HtmlElement(e.g. PreElement) throws:
HierarchyRequestError: Custom element XXX is a native PreElement
should be derived from HtmlElement or SvgElement.
Using extendsTag option with registerElement suppresses the above error but causes "new Element.tag('xxx')" to return an instance of HtmElement.
document.registerElement('xxx', XXX, extendsTag:'pre');
Solution(Assuming extending PreElement):
Use 'document.registerElement('xxx', XXX, extendsTag:'pre');' and 'new Element.tag('pre','xxx');'
void main{
document.registerElement('xxx',
XXX,extendsTag: 'pre');
querySelectior('body').append(new XXX()..text = 'hello');
}
class XXX extends PreElement{
XXX.created():super.created(){}
factory XXX(){
return new Element.tag('pre','xxx');
}
}
Dart does not currently support library initialization. You must call document.registerElement in the main.
Tested with 1.14.0
When I extend a class I want to override methods and change their accessibility like a protected method should be public in a certain class. When I compile it says: "Incompatible override". I can't reduce nor can I increase the visibility.
Reducing wouldn't make sense and I don't need it but I was able to increase method visibility in Java. Why not in ActionScript 3 ?
public class OldClass
{
protected function doStuff() : void
{}
}
public class NewClass extends OldClass
{
override public function doStuff() : void
{}
}
Am I doing something wrong ?
No, you're not doing anything wrong. That's just how the language works. From the documentation (emphasis added):
Static methods are not inherited and cannot be overridden. Instance methods, however, are inherited by subclasses and can be overridden as long as the following two criteria are met:
...
The override method must have the same level of access control as the base class method. Methods marked as internal have the same level of access control as methods that have no access control specifier.
The override method must have the same number of parameters as the base class method.
The override method parameters must have the same data type annotations as the parameters in the base class method.
The override method must have the same return type as the base class method.
I am trying to create a spark datagrid item renderer. This item renderer extends a checkbox, and implements IGridItemRenderer
public class CellCheckBoxItemRenderer extends CheckBox implements IGridItemRenderer
When I implement IGridItemRenderer, I need to implement the interface methods, I am having a problem with the following methods:
public function get hovered():Boolean
{
}
public function set hovered(value:Boolean):void
{
}
since the methods are inherited as well from the checkbox
EDIT
The signatures of the functions
//spark checkbox signature
protected function get hovered():Boolean
protected function set hovered(value:Boolean):void
and the signature above belongs to the interface IGridItemRenderer
I guess the implementation of IGridItemRenderer is the more important part, so you can use it in a datagrid. The CheckBox provides just the functionality, you don't have to extend it if there are conflicts in my opinion.
public class CellCheckBoxItemRenderer implements IGridItemRenderer {
private var checkBox:CheckBox;
public function getCheckBox {
return checkBox;
}
//...
}
If CheckBox would implement any useful interfaces, you could also implement them in your renderer and delegate the methods to the checkbox, which may let you encapsulate the whole checkbox. That's not the case here though.
The problem is that interfaces, by design, only specify the signature for public functions, whereas the function in Checkbox is set as protected.
The only solutions:
remove the interface/Checkbox class from CellCheckBoxItemRenderer
remove the declaration from the interface
change Checkbox so hovered is a public property
it might be possible to change the accessor dynamically using the as3 commons bytecode project (http://www.as3commons.org/as3-commons-bytecode/emit.html), but I'm not 100% sure.
I would like to modify an Accordion class to suit my needs.
Instead of simply extending Accordion, I would like to copy and paste the whole class as a start, with the new class name "MyAccordion", into the src folder; to gain the maximum freedom(I assume).
However, several problems encountered. For the "include "../core/Version.as";" error, I had solved by replacing it with a explicit Version static const string. But for the problems lead by the inheritance, e.g. AccordionHeader, etc, I found that there would be too many files to be edited when going down the stream. I suspect I mis-understand the whole logic of editing the class.
Would anyone give me some help? May be some reference for me to read, or even just some keywords for me to search. Thanks in advance.
Well - for all the reasons your discovering, you actually don't have flexibility when leveraging "boilerplate" code like this. Use Extend and Override to properly modify existing classes:
package com.yourSite.src
{
public class Foo
{
public function Foo
{
}
public function foo():void
{
trace("foo");
}
}
}
package com.yourSite.src
{
public class Bar extends Foo
{
public function Bar
{
}
override public function foo():void
{
trace("bar");
}
}
}
So, write a class that Extends Accordion, and override anything that you want to work differently. Any other functionality you may need can be added as required. OOP 101 :D
Check out the link above for a more cohesive discussion.
Cheers!