I am using Angular 1.6 with ES6. Until now I implemented inheritence with the extend keyword on ES6 classes
export default class myChildService extends myBaseService {
constructor(someDependency){
'ngInject'
super();
someDependency.doStuff();
}
}
and registered the child-class as angular-service
import myChildService from ./myChildService
angular.module('myApp', [])
.service('myChildService', myChildService)
This works well so far!
However I would like to split my application into smaller modules. This means I will have several different angular-modules which will need access to myBaseService in order to inherit the functionality.
I could just import the file containing myBaseService, but this seems not very angulary. It basically means I disregard angular-modules and DI everytime I use inheritance.
Question:
Is there any way to export an ES6-class from an angular-module base so that I can reuse it on an angular-module child which depends on base?
Maybe I am just looking at this the wrong way - if you have other suggestions to implement inheritance of angular-services/ factories using ES6-classes, please go ahead.
Why importing is not angulary? If you would like to use base service functionality, the module should know it's definition.
Related
I have a typical Glimmer "base" component:
import Component from '#glimmer/component';
export default class BaseComponent extends Component { ... }
It has a template like normally, but the actual implementations of that component are child componenents, that override some of the template getters and parameters so that it works with various different data types.
export default class TypeAComponent extends BaseComponent { ... }
export default class TypeBComponent extends BaseComponent { ... }
etc.
My question is: How do I specify that all the child components should use the parent class template, so I don't have to duplicate the same fairly complex HTML for all child components? Visually the components are supposed to look identical so any changes would have to be replicated across all child component types. Therefore multiple duplicated templates isn't ideal.
In Ember Classic components there was layout and layoutName properties so I could just do:
layoutName: 'components/component-name'
in the base component and all child components did automatically use the defined template.
Now that I'm migrating to Glimmer components I can't seem to figure out how to do this. I have tried:
layout property
layoutName property
template property
Using the child components without a template in hope that they would automatically fall back to the parent class template.
Only thing that seems to work is creating Application Initializer like this:
app.register('template:components/child1-component', app.lookup('template:components/base-component'));
app.register('template:components/child2-component', app.lookup('template:components/base-component'));
But that feels so hacky that I decided to ask here first if there is a proper way to do this that I have missed?
How to specify template for Glimmer Component?
tl;dr: you should avoid this.
There are two answers to two, more specific, questions:
What is the recommended way to manage complex components with shared behaviors?
Typically, you'll want to re-work your code to use either composition or a service.
Composition
<BaseBehaviors as |myAPI|>
<TypeAComponent #foo={{myAPI.foo}} #bar={{myAPI.bar}} />
<BaseBehaviors>
Where BaseBehaviors' template is:
{{yield (hash
foo=whateverThisDoes
bar=whateverThisBarDoes
)}}
Service
export default class TypeAComponent extends Component {
#service base;
}
and the service can be created with
ember g service base
then, instead of accessing everything on this, you'd access everything on this.base
Ignoring all advice, how do I technically do the thing?
Co-located components (js + hbs as separate files), are combined into one file at build time, which works like this:
// app/components/my-component.js
import Component from '#glimmer/component';
export default class MyComponent extends Cmoponent {
// ..
}
{{! app/components/my-component.hbs }}
<div>{{yield}}</div>
The above js and hbs file becomes the following single file:
// app/components/my-component.js
import Component from '#glimmer/component';
import { hbs } from 'ember-cli-htmlbars';
import { setComponentTemplate } from '#ember/component';
export default class MyComponent extends Cmoponent {
// ..
}
setComponentTemplate(hbs`{{! app/components/my-component.hbs }}
<div>{{yield}}</div>
`, MyComponent);
So this means you can use setComponentTemplate anywhere at the module level, to assign a template to a backing class.
Why is this not recommended over the other approaches?
All of this is a main reason the layout and related properties did not make it in to Octane.
Formally supported Component inheritance results in people getting "clever"
this in of itself, isn't so much of a problem, as it is what people can do with the tool. Bad inheritance is the main reason folks don't like classes at all -- and why functional programming has been on the rise -- which is warranted! Definitely a bit of an over-correction, as the best code uses both FP and OP, when appropriate, and doesn't get dogmatic about this stuff.
Component Inheritance is harder to debug
Things that are a "Foo" but are a subclass of "Foo" may not actually work like "Foo", because in JS, there aren't strict rules around inheritance, so you can override getters, methods, etc, and have them provide entirely different behavior.
This confuses someone who is looking to debug your code.
Additionally, as someone is trying to do that debugging, they'll need to have more files open to try to under stand the bigger picture, which increases cognitive load.
Component inheritance allows folks to ignore boundaries
This makes unit testing harder -- components are only tested as "black boxes" / something you can't see in to -- you test the inputs and outputs, and nothing in between.
If you do want to test the in-between, you need to extract either regular functions or a service (or more rendering tests on the specific things).
I would say this is the classic case for a composition, where TypeAComponent and TypeBComponent use the BaseComponent.
So you have your BaseComponent with all the HTML, that basically is your template. I think its important here to think a bit more of Components also as possible Templates, not only full Components. So lets call this the TemplateComponent.
So you have your TemplateComponent which could also be a template-only component. Then you have as template for TypeAComponent and TypeBComponent:
<TemplateComponent
#type={{#title}}
#title={{#title}}
#onchange={{#onchange}}
#propertyThatIsChanged={{this.propertyThatIsChanged}}
...
/>
this allows you to have a getter propertyThatIsChanged to overwrite pieces. Common behaviour can also be placed on the TemplateComponent, or, if its common code, maybe on a BaseCodeComponent, that only contains shared code, while I would rather not do this.
For areas you want to replace this also opens the possibility to use Blocks.
The TemplateComponent, for example, could use has-block to check if a :title exists, use this block then ({{yield to="default"}}), and if not just use {{#title}}.
So, to the only obvious downside of this: you have to proxy all params. This seems ugly at first, but generally I think its better for components not to have too many arguments. At some point an options or data argument could be better, also because it can be built with js when necessary. It should also be mentioned that there is an open RFC that would address this issue. With the upcoming SFCs, I think this is the much more future-proof solution overall.
Problem Statment
I am learning Angular 4 and I have stumble upon a code where #Inject is being used in a constructor and I am not able to figure out why...
Code and Source
I am using Angular 4 Material
Code Source: https://material.angular.io/components/dialog/overview
In the code, they are injecting MAT_DIALOG_DATA
constructor(public dialogRef: MatDialogRef<DialogOverviewExampleDialog>,
#Inject(MAT_DIALOG_DATA) public data: any
) { }
Can anyone please elaborate what does it mean and when/where should we do this?
#Inject() is a manual mechanism for letting Angular know that a
parameter must be injected.
import { Component, Inject } from '#angular/core';
import { ChatWidget } from '../components/chat-widget';
#Component({
selector: 'app-root',
template: `Encryption: {{ encryption }}`
})
export class AppComponent {
encryption = this.chatWidget.chatSocket.encryption;
constructor(#Inject(ChatWidget) private chatWidget) { }
}
In the above we've asked for chatWidget to be the singleton Angular
associates with the class symbol ChatWidget by calling
#Inject(ChatWidget). It's important to note that we're using
ChatWidget for its typings and as a reference to its singleton.
We are not using ChatWidget to instantiate anything, Angular does
that for us behind the scenes
From https://angular-2-training-book.rangle.io/handout/di/angular2/inject_and_injectable.html
If MAT_DIALOG_DATA is a non-factory/class dependency (like string for your configs), you usually use #Inject.
Also check InjectionToken: https://angular.io/guide/dependency-injection#injectiontoken
One solution to choosing a provider token for non-class dependencies is to define and use an InjectionToken
Here's a plunker: http://plnkr.co/edit/GAsVdGfeRpASiBEy66Pu?p=preview
if you remove #Inject in these cases you will receive a
Can't resolve all parameters for ComponentName: (?)
IoC container in Angular uses the type declarations in the constructor to determine the objects to be injected to the constructor parameters.
In your example, "public data: any" parameter could not be determined by its type declaration because it's defined as "any". In order to solve this problem, you have to use "#Inject(MAT_DIALOG_DATA)" decorator to inform the IoC container about the object that must be injected to "data" parameter.
Also in your example, "#Inject" decorator is used with an InjectionToken to complicate things a little more :)
An InjectionToken is actually a class which is used to name the objects to be used by IoC container to inject in to other classes. Normally you could use any classes name as a token for IoC injection (like "MatDialogRef<DialogOverviewExampleDialog>" in your example) and this works fine. But when you start writing your UnitTests you realize that you need to use Mock objects instead of real objects to be injected into your classes and when you use real class names as your tokens, you could not do that.
To solve this problem you could use Interfaces as token names and this is actually the right solution, but since JavaScript does not support interfaces you could not use Interface names as tokens, because transpiled code does not contain Interface definitions.
As a result of all this, you need to use InjectionToken. An InjectionToken allows you to inject any object into your constructor. You just need to declare it in your modules and map to the real class that you want to be injected. This way you could use different classes for your production and test codes.
The documentation around Microsoft's recently released ReactXP doesn't have much information about the RX.Component class at the moment.
Here's an example from the documentation:
class HelloWorld extends RX.Component<void, void> {
render() {
return <RX.Text>Hello World</RX.Text>;
}
}
What are the features offered by RX.Component over React.Component?
How does it influence the life-cycle of the base Component class?
This is an important consideration for me because best practices for React components typically encourage composition over inheritance, except for very basic scenarios like PureComponent. Would the features provided by RX.Component justify the inheritance?
I believe it's the same:
https://github.com/Microsoft/reactxp/blob/master/src/web/ReactXP.ts#L131
Maybe they just want to make everything under the RX namespace so you only need to import RX = require('reactxp');
I'm using ECMAScript6 modules. What is the correct way to export/import multiple methods from a module from the options below?
Single class of static methods:
//------ myClass.js ------
export default class myClass {
static myMethod1() {
console.log('foo');
}
static myMethod2(args...) {
console.log('bar');
}
}
//------ app.js ------
import myClass from 'myClass';
myClass.myMethod1(); //foo
Multiple exported methods:
//------ myMethods.js ------
export function myMethod1() {
console.log('foo');
}
export function myMethod2() {
console.log('bar');
}
//------ app.js ------
import {myMethod1, myMethod2} from 'myMethods';
myMethod1() //foo;
//OR
import * as myMethods from 'myMethods';
myMethods.myMethod1() //foo;
1) Exporting:
A class of just static methods feels like a bit of a 'code smell' but similarly exporting everything individually does feel a bit verbose. Is it simply developer preference or are there performance implications here?
2) Importing:
'* as' syntax is my preferred method as it allows you to use the dot notation (referencing both the module AND the method) aiding code readability. Does this have performance implications though when I may only be using 1 of the methods?
A class of just static methods feels like a bit of a 'code smell'
Yes indeed. You don't need a class structure here! Just export a normal "module" object:
//------ myMethods.js ------
export default {
myMethod1() {
console.log('foo');
},
myMethod2(args...) {
console.log('bar');
}
};
I do recommend your second approach with multiple exports, though.
exporting everything individually does feel a bit verbose
Well, you don't need any wrapper structure, so I'd say it's less boilerplate. You just have to explicitly tag everything that you want to be exported, which is not a bad thing.
* as syntax is my preferred method as it allows you to use the dot notation (referencing both the module AND the method) aiding code readability.
That's very much personal preference, and does depend on the type of code you are writing. Sometimes conciseness is superior, but the ability to explicitly reference the module can be helpful as well. Notice that namespace imports using * as and default-imported objects are very similar here, though only named exports allow you to directly reference them via import {myMethod1, myMethod2}. So better leave the choice to those that import your module.
Does this have any performance implications?
Not much. Current ES6 implementations are not yet aiming for performance optimisations anyway.
In general, static identifiers are easier to resolve and optimise than property accesses[1], multiple named exports and partial imports could theoretically make JIT faster, and of course smaller files need less time to load if unused exports are removed during bundling. See here for details. There hardly will be noticeable performance differences, you should use what is better maintainable.
[1]: module namespaces (import * as ns) are static as well, even if ns.… looks like a dynamic property access
TLDR; Use multiple exported methods and explicit import.
#Bergi is right about not needing a class with static fields, only an object in your first case. However, this option is discouraged by Axel Rauschmayer:
Note that default-exporting objects is usually an anti-pattern (if you want to export the properties). You lose some ES6 module benefits (tree-shaking and faster access to imports).
Devs at Airbnb recommend named exports and explicit wildcrad import, see this thread: https://github.com/airbnb/javascript/issues/710#issuecomment-297840604
I am new to Ember.js and Javascript in general. I am using ember-cli to create an app that could use a DateUtil class to perform some date manipulation. I noticed that ember-cli has a utilities generator to produce the following boilerplate code in app/utils/date-util.js:
export default function dateUtil() {};
I am wondering how to write a utility so that I can use it across my application. Specifically, as an example, in a controller:
export default Ember.ObjectController.extend({
startDate: dateUtil.thisMonday()
});
where thisMonday() would return the date of this Monday using moment.js like:
moment({hour:0}).day(1);
There would be many others similar to thisMonday() as part of dateUtil.
You simply need to import the ES6 module that exports your utility function, in each of the controllers that want to use it, like so:
import dateUtil from 'app/utils/date-util';
export default Ember.ObjectController.extend({
startDate: dateUtil().thisMonday()
});
Note that the path is not necessarily app/utils/... though, you must replace app with the name of the app that you used when initially generating the app. You can verify what this is by looking in app/app.js, and looking for the value of modulePrefix within Ember.Application.extend().
Just import your class using the ES6 module syntax.
import dateUtil from 'app/utils/date-util.js';
References:
ES6 modules
ember-cli guide on modules