JS: How to create child class from a parent class in Javascript? - javascript

How to avoid circular references at the same time create some child classes from the parent class? And keep the constrain that each class need to reside in a different file.
//Parent.mjs:
import Sub from "/.Sub.mjs"
export default class Parent {
static createSomething(){
new Sub();
}
}
//Sub.mjs:
import Parent from "/.Parent.mjs"
export default class Sub extends Parent {
contructor(){}
}
This question was originally posted here. But there is no solution under that question. If I really want to create a subclass from the superclass what code should I write?

The parent class should not need to know anything about subclass(es).
I don't see why the parent class would need a static method for creating a subclass,
but if you feel you really, really need that, then extend the Parent class object from within the Sub.mjs file:
Parent.mjs:
export default class Parent {
}
Sub.mjs:
import Parent from "/.Parent.mjs"
Parent.createSomething = function () {
return new Sub();
}
export default class Sub extends Parent {
constructor(){} // fixed typo here
}
Still, I think it is a bad idea to define such a function on the parent class. This looks like an XY problem. The original reason that made you look for such a function in the first place, certainly has a better way to be solved that doesn't involve a parent class that needs to know about a subclass.

Related

JavaScript - Create elements using web component class

I have a web component that only works when some properties are set, when I create the component with Document.createElement() I can't pass properties then an error happens in my component.
Is it possible to create the component by creating an instance of the component class or something similar and be able to pass parameters to it's constructor?
customElements.define('x-card', class extends HTMLDivElement {
//...
}, { extends: 'div' });
You can create a new instance using new WCard. This requires having access to the class though.
Please note that custom element names preferrably should not start with x-.
So change your code:
export class WCard extends HTMLDivElement {
//...
}
customElements.define('w-card', WCard, { extends: 'div' });
window.WCard = WCard;
This allows you to call new on the class globally, or if your code imports the class.
const wcard = new WCard(...args);

Access parent class code in custom ESLint rule

Scenario:
I want to check that a child class method calls a super class method using super keyword if parent class has such a method.
Example:
// parent.ts
class Parent {
a {
// super class method
}
}
// child.ts
class Child extends Parent {
a {
// I want to check if parent class has method a
// then the child class should call super.a(). else show a warning
super.a();
}
}
This felt like a use case for writing a custom ESLint rule. I am not able to check if the parent class has a method with name a so far.
Is this possible with ESLint rules? Is custom ESLint rule a good thing to do this or should i use a different approach?

Why do propTypes live on the class but not other methods?

I read that using static for propTypes puts the it on the class instead of the instance of the React component. I don't get the difference between putting something on the class vs. the instance though. Why is propTypes on the class but not methods like render and componentDidMount, or other custom made methods inside the component?
It's for the same reason as the keyword static. This is un-changing static metadata that helps describe your class. It can be accessed without needing to instantiate your class (accessed without calling the constructor).
class example extends Component {
static propTypes = {
something: PropTypes.object,
}
static displayName = "ExampleDisplay";
render() {
return <div />;
}
}
// I can access static properties here directly
var types = example.propTypes;
var name = example.displayName;
// I can NOT access the render method without instantiating the class.
var instance = new example(); // <- this calls the constructor and creates an instance.
var renderFn = instance.render;
The question is really: why should I need to create the class just to read the propTypes or displayName? you shouldn't need to. that's why you have static.

Create New Instance of Derived Class From Parent Class Javascript es6

Im getting the following error when doing this.
Super expression must either be null or a function, not undefined
What I'm trying to do in javascript which I can do in c# is have the child class be able to call the parent class and use functions that instantiate the base class again. Say for instance you have a navbar on a page and each icon takes you to a different page but the navbar is always visible. By inheriting from the parent page I would be able to keep the code dry like we do in c# but for some reason javascript is flipping out when trying to do the same thing even if I just pass null into the super.
Doing this would allow me to havenew Support(browser).someMethod().cb().someMethod()
import { Support } from "./community/Support";
export class NavigationController {
constructor(browser){
this.browser = browser;
}
cb(){
this.browser.cool()
return new Support(this.browser);
}
import { NavigationController } from "../navigation_controller";
export class Support extends NavigationController {
constructor(browser){
super(browser);
this.browser = browser;
}
someMethod(){
this.browser.blah()
return this;
}

Custom element's Binding Context - what is it exactly, how to access parent VM

I couldn't find the answer in the docs, so I'm asking here. What exactly is the binding context passed to the bind method of custom element. Is it simply equal to router's currently active ViewModel? At least, that's what I've found out so far.
Why isn't it the element's parent (in the terms of DOM) VM?
with this code
#customElement("myelem")
#inlineView("<template><content></content></template>")
export class MyElem{
bind(ctx){
console.log(ctx);
}
}
// welcome.html
<myelem>
<h3>inside myelem</h3>
<myelem>
<h4>inside inside ... </h4>
</myelem>
</myelem>
the output in the console is just current viewmodel (Welcome) printed twice.
I'd expect it to be Welcome for the first (outer) myelem, but MyElem for the second (inner) occurance...
Please explain why am I wrong here, and how can the inner custom element be aware of it's actual context (by which I mean the outer one in the case above), without using ugly hacks like creating secret property in the "shared" context (the one which actually gets passed to both of them)
In terms of data-binding, both elements are bound to the same binding context. Consider this example:
<div foo.bind="bar">
<div foo.bind="bar"></div>
</div>
You would expect both <div> elements to have the same binding context right? Both element's foo property should be bound to the same model's bar property. The same holds true in this scenario:
<myelem foo.bind="bar">
<myelem foo.bind="bar"></myelem>
</myelem>
Both instances of <myelem> are bound to the same binding context / model.
If I understand the question correctly, you would like an elegant way to give the inner MyElem class instance a reference to the outer MyElem class instance. Luckily, you're using Aurelia so there is a very nice way to do this... declare it as a dependency using the inject decorator:
import {inject, Parent} from 'aurelia-dependency-injection';
import {customElement} from 'aurelia-framework';
#customElement("myelem")
#inject(Parent.of(MyElem))
export class MyElem {
constructor(parent) {
this.parent = parent;
}
...
}
There's one caveat however...
The Aurelia dependency-injection container's default behavior is to create an instance of the requested item if an instance is not found in the container. This means that #inject(Parent.of(MyElem)) is not quite what we want. In situations where there is no parent MyElem instance the container will create one for us instead of returning null. Normally we'd use #inject(Optional.of(MyElem)) to tell the container to give us the instance, only when it exists in the container. I don't know of a way to combine Parent.of and Optional.of. I'll create an issue in the aurelia dependency-injection repository so we can get this feature added.
In the meantime, we can easily create our own Resolver that combines the behavior of Parent.of and Optional.of:
import {resolver} from 'aurelia-dependency-injection';
#resolver()
export class OptionalParent {
constructor(key) {
this.key = key;
}
get(container) {
if (container.parent && container.parent.hasResolver(this.key, false)) {
return container.parent.get(this.key)
}
return null;
}
static of(key) {
return new OptionalParent(key);
}
}
So the new version of our MyElem class would look like this:
import {inject} from 'aurelia-dependency-injection';
import {customElement} from 'aurelia-framework';
import {OptionalParent} from './optional-parent';
#customElement("myelem")
#inject(OptionalParent.of(MyElem))
export class MyElem {
constructor(parent) {
this.parent = parent;
}
...
}
Here's a working example. Check the console for log messages showing the result:
https://gist.run/?id=1a84e0a466fb928aa075

Categories