Skip to content
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

mixin and components #491

Merged
merged 3 commits into from
Oct 30, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions _data/sidebars/lb4_sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@ children:
url: Crafting-LoopBack-4.html
output: 'web, pdf'

- title: 'Language-related Concepts'
url: Language-related-concepts.html
output: 'web, pdf'
children:

- title: 'Mixin'
url: Mixin.html
output: 'web, pdf'

- title: 'Reference'
url: Reference.html
output: 'web, pdf'
Expand Down
60 changes: 60 additions & 0 deletions pages/en/lb4/Creating-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,66 @@ export class AuthenticationProvider {
}
```

## Extends Application with Mixin

When binding a component to an app, you may want to extend the app with the component's
properties and methods.
This can be achieved by using mixins.

If you are not familiar with the mixin concept, check [Mixin](Mixin.htm) to learn more.

An example of how a mixin leverages component would be `RepositoryMixin`:
Suppose an app has multiple components with repositories bound to each of them,
you can use function `RepositoryMixin` to mount those repositories to application level context.

The following snippet is an abbreviated function
[`RepositoryMixin`](https://github.com/strongloop/loopback-next/blob/master/packages/repository/src/repository-mixin.ts):

{% include code-caption.html content="mixins/src/repository-mixin.ts" %}
```js
export function RepositoryMixin<T extends Class<any>>(superClass: T) {
return class extends superClass {
constructor(...args: any[]) {
super(...args);
... ...
// detect components attached to the app
if (this.options.components) {
for (const component of this.options.components) {
this.mountComponentRepository(component);
}
}
}
}
mountComponentRepository(component: Class<any>) {
const componentKey = `components.${component.name}`;
const compInstance = this.getSync(componentKey);

// register a component's repositories in the app
if (compInstance.repositories) {
for (const repo of compInstance.repositories) {
this.repository(repo);
}
}
}
}
```

Then you can extend the app with repositories in a component:

{% include code-caption.html content="index.ts" %}

```js
import {RepositoryMixin} from 'mixins/src/repository-mixin';
import {Application} from '@loopback/core';
import {FooComponent} from 'components/src/Foo';

class AppWithRepoMixin extends RepositoryMixin(Application) {};
let app = new AppWithRepoMixin({components: [FooComponent]});

// `app.find` returns all repositories in FooComponent
app.find('repositories.*');
```

## Configuring components

More often than not, the component may want to offer different value providers depending on the configuration. For example, a component providing Email API may offer different transports (stub, SMTP, etc.).
Expand Down
13 changes: 13 additions & 0 deletions pages/en/lb4/Language-related-concepts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
lang: en
title: 'Language-related Concepts'
keywords: LoopBack 4.0, LoopBack 4
tags:
sidebar: lb4_sidebar
permalink: /doc/en/lb4/Language-related-concepts.html
summary:
---

A module that exports JavaScript/TypeScript concept related functions.

- [**Mixin**](Mixin.html): Add properties and methods to a class.
124 changes: 124 additions & 0 deletions pages/en/lb4/Mixin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
---
lang: en
title: 'Mixin'
keywords: LoopBack 4.0, LoopBack 4
tags:
sidebar: lb4_sidebar
permalink: /doc/en/lb4/Mixin.html
summary:
---

It is a commonly used JavaScript/TypeScript strategy to extend a class with new properties and methods.

A good approach to apply mixins is defining them as sub-class factories.
Then declare the new mixed class as:

```js
class MixedClass extends MixinFoo(MixinBar(BaseClass)) {};
```

Check article [real mixins with javascript classes](http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/)
to learn more about it.

## Define Mixin

By defining a mixin, you create a mixin function that takes in a base class,
and returns a new class extending the base class with new properties and methods mixed to it.

For example you have a simple controller which only has a greeter function prints out 'hi!':

{% include code-caption.html content="Controllers/myController.ts" %}

```ts
class SimpleController {
constructor() {

}
greet() {
console.log('hi!');
}
}
```

Now let's add mixins to it:

- A time stamp mixin that adds a property `createdAt` to a record when a
controller instance is created.

- A logger mixin to provide logging tools.

Define mixin `timeStampMixin`:

{% include code-caption.html content="Mixins/timeStampMixin.ts" %}

```ts
import {Class} from "@loopback/repository";

export function timeStampMixin<T extends Class<any>> (baseClass: T) {
return class extends baseClass {
// add a new property `createdAt`
public createdAt: Date;
constructor(...args: any[]) {
super(args);
this.createTS = new Date();
}
printTimeStamp() {
console.log('Instance created at: ' + this.createdAt);
}
}
}
```

And define mixin `loggerMixin`:

{% include code-caption.html content="Mixins/loggerMixin.ts" %}

```ts
import {Class} from "@loopback/repository";

function loggerMixin<T extends Class<any>> (baseClass: T) {
return class extends baseClass {
// add a new method `log()`
log(str: string) {
console.log('Prints out a string: ' + str);
};
}
}
```

Now you can extend `SimpleController` with the two mixins:

{% include code-caption.html content="Controllers/myController.ts" %}

```ts
import {timeStampMixin} from 'Mixins/timeStampMixin.ts';
import {loggerMixin} from 'Mixins/loggerMixin.ts';

class SimpleController {
constructor() {

}
greet() {
console.log('hi!');
}
}

class AdvancedController extends loggerMixin(timeStampMixin(SimpleController)) {};

// verify new method and property are added to `AdvancedController`:
let aControllerInst = new AdvancedController();
aControllerInst.printTimeStamp();
// print out: Instance created at: Tue Oct 17 2017 22:28:49 GMT-0400 (EDT)
aControllerInst.logger('hello world!');
// print out: Prints out a string: hello world!
```

## References

Here are some articles explaining ES2015 and TypeScript mixins in more details:

- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Mix-ins

- http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/

- https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html
2 changes: 1 addition & 1 deletion pages/en/lb4/Using-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ In general, components can contribute the following items:
In the future (before the GA release), components will be able to contribute additional items:

- Models
- [Repositories](Repositories.html)
- [Repositories](Repositories.html)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated whitespace change, could you please revert?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weird...I could not see where is the whitespace(difference), I copy paste the original file but diff is still here...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like a character formatting problem (was this file made on Windows or something? :P)