Skip to content
This repository has been archived by the owner on Jul 30, 2018. It is now read-only.

Functional Factory Injector #910

Merged
merged 6 commits into from
Apr 18, 2018
Merged

Conversation

agubler
Copy link
Member

@agubler agubler commented Apr 16, 2018

Type: feature

The following has been addressed in the PR:

  • There is a related issue
  • All code has been formatted with prettier as per the readme code style guidelines
  • Unit or Functional tests are included in the PR
  • Any required updates included in the readme

Description:

It has been identified that the ergonomics around using an Injector class as the base type when defining an injector in a registry can be awkward.

  • It requires consumers to deal with Evented.emit(), unlike everywhere else in Dojo 2, where we tend to provide abstractions on top of listening and emitting events.
  • Additionally it was awkward to just provide a static payload that never needed to be reset.
  • It encouraged consumers to extend the Injector class and make it stateful which was never the intention.

This change moves to accepting a functional factory that gets provided an invalidator and returns a function that when called will return the intended payload to be injected into the registered widgets.

registry.defineInjector('state', (invalidator: () => void) => {
    const applicationContext = new ApplicationContext(invalidator);
    return () => applicationContext;
});

If the payload never changes then the invalidator function can just be ignored.

registry.defineInjector('state', () => {
    return () => ({ foo: 'bar' });
});

Resolves #911

@agubler agubler added this to the 2.0.0 milestone Apr 16, 2018
@agubler agubler requested review from devpaul and maier49 April 16, 2018 18:09
Copy link
Member

@dylans dylans left a comment

Choose a reason for hiding this comment

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

A few minor readme updates, very much looking forward to this change landing, thanks!

README.md Outdated
@@ -851,18 +854,32 @@ class MyClass extends WidgetBase {

### Containers & Injectors

There is built-in support for side-loading/injecting values into sections of the widget tree and mapping them to a widget's properties. This is achieved by registering a `@dojo/widget-core/Injector` instance against a `registry` that is available to your application (i.e. set on the projector instance, `projector.setProperties({ registry })`).
There is built-in support for side-loading/injecting values into sections of the widget tree and mapping them to a widget's properties. This is achieved by registering an injector factory with a `registry` and setting the registry as a property on the application's `projector` to ensure that is available to your application.
Copy link
Member

Choose a reason for hiding this comment

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

"to ensure that is available" please be more specific than "that is"

README.md Outdated

Create an `Injector` instance and pass the `payload` that needs to be injected to the constructor:
The injector factory gets passed an `invalidator` function that can be called when something has changed that requires connected widgets to `invalidate`.
Copy link
Member

Choose a reason for hiding this comment

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

can be called -> can get called

README.md Outdated
registry.defineInjector('my-injector', injector);
registry.defineInjector('my-injector', (invalidator) => {
// This could be a store, but for this example is simply an instance
// that accepts the injector and calls it when any of it's internal
Copy link
Member

Choose a reason for hiding this comment

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

it's -> its

Copy link
Contributor

@maier49 maier49 left a comment

Choose a reason for hiding this comment

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

Nice 👍 . Saw one typo and had one small question/suggestion.

README.md Outdated

`getProperties` receives the `payload` from an `injector` and `properties` from the container HOC component. These are used to map into the wrapped widget's properties.
`getProperties` receives the `payload` return from the injector function and the `properties` passed to the container HOC component. These are used to map into the wrapped widget's properties.
Copy link
Contributor

Choose a reason for hiding this comment

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

return -> returned

src/Registry.ts Outdated
@@ -152,7 +157,7 @@ export class Registry extends Evented<{}, RegistryLabel, RegistryEventObject> im
}
}

public defineInjector(label: RegistryLabel, item: Injector): void {
public defineInjector(label: RegistryLabel, item: InjectorFactory): void {
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this is no longer the item that actually ends up in the registry, maybe it'd be clearer to just name this injectorFactory, or injector?

Copy link
Member Author

Choose a reason for hiding this comment

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

I can defo change that

@agubler
Copy link
Member Author

agubler commented Apr 18, 2018

@maier49 Think i've addressed you're feedback 👍

if (!this._injectorRegistry || !this.hasInjector(label)) {
return null;
}

return this._injectorRegistry.get(label) as T;
return this._injectorRegistry.get(label)!;
Copy link
Member

Choose a reason for hiding this comment

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

In the return were InjectorItem<T> | undefined wouldn't we be able to avoid the !?

Copy link
Member Author

@agubler agubler Apr 18, 2018

Choose a reason for hiding this comment

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

We already check whether the item exists, so we know at this point it is not undefined and I wanted to avoid changing the API any more than required.

Copy link
Member Author

Choose a reason for hiding this comment

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

const registeredInjectors = registeredInjectorsMap.get(this) || [];
if (registeredInjectors.length === 0) {
registeredInjectorsMap.set(this, registeredInjectors);
}
if (registeredInjectors.indexOf(injector) === -1) {
if (registeredInjectors.indexOf(injectorItem) === -1) {
Copy link
Member

Choose a reason for hiding this comment

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

Can we use a WeakSet<injectorItem> here?

Copy link
Member

@devpaul devpaul left a comment

Choose a reason for hiding this comment

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

This is a marked improvement over extending Injector 💯 Had a couple questions related to implementation. The architecture is sound

@agubler agubler merged commit 9d9c2ee into dojo:master Apr 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants