GitXplorerGitXplorer
s

ember-functional-modifiers

public
40 stars
6 forks
0 issues

Commits

List of commits on branch master.
Verified
7875c834c5451a634b54b028c4b9c2c651a9d482

Merge pull request #19 from buschtoens/patch-1

sspencer516 committed 5 years ago
Verified
39552e2f960381978f150e2e5e40b83c7f22235c

docs(README): add deprecation notice

bbuschtoens committed 5 years ago
Unverified
667473cc394bf30fef9eb597408d030ba268dc8b

Release 0.5.0

sspencer516 committed 5 years ago
Verified
b4a5c7a62761a614640e6900900c2a5baf1f9ef3

Merge pull request #18 from rwjblue/update-try-config

sspencer516 committed 5 years ago
Verified
b7ed687b4dd9abe26b92b84f109234a734c934c0

Merge pull request #17 from rwjblue/prevent-issues-in-3-13

sspencer516 committed 5 years ago
Unverified
77d742f4079075c4e6c09e49ff35459ad711c0b7

Add Ember 3.8 and 3.12 to ember-try config.

rrwjblue committed 5 years ago

README

The README file for this repository.

ember-functional-modifiers

āš ļø šŸ‘‰ This addon has been deprecated in favor of the official ember-modifier addon. See the upgrade guide.

This addon provides a useLayoutEffect-like API for adding modifiers to elements in Ember.

For more information on modifiers, please check out @pzuraq's wonderful blog post.

Compatibility

This is currently compatible with:

  • Ember.js v2.18 or above
  • Ember CLI v2.13 or above

Installation

ember install ember-functional-modifiers

Usage

This addon does not provide any modifiers out of the box; instead (like Helpers), this library allows you to write your own.

Generating a Functional Modifier

To create a modifier (and a corresponding integration test), run:

ember g functional-modifier scroll-top

Example without Cleanup

For example, if you wanted to implement your own scrollTop modifier (similar to this), you may do something like this:

// app/modifiers/scroll-top.js
import makeFunctionalModifier from 'ember-functional-modifiers';

export default makeFunctionalModifier((element, [scrollPosition]) => {
  element.scrollTop = scrollPosition;
})

Then, use it in your template:

<div class="scroll-container" {{scroll-top @scrollPosition}}>
  {{yield}}
</div>

Example with Cleanup

If the functionality you add in the modifier needs to be torn down when the element is removed, you can return a function for the teardown method.

For example, if you wanted to have your elements dance randomly on the page using setInterval, but you wanted to make sure that was canceled when the element was removed, you could do:

// app/modifiers/move-randomly.js
import makeFunctionalModifier from 'ember-functional-modifiers';

const { random, round } = Math;

export default makeFunctionalModifier(element => {
  const id = setInterval(() => {
    const top = round(random() * 500);
    const left = round(random() * 500);
    element.style.transform = `translate(${left}px, ${top}px)`;
  }, 1000);

  return () => clearInterval(id);
});
<button {{move-randomly}}>
  {{yield}}
</button>

Example with Cleanup (on destroy)

By default, a functional modifier that returns a cleanup method will trigger the cleanup on each change ā€” the reason for this is similar to the reason for the same behavior with useEffect in React.

If, however, unsubscribing/resubscribing on every change is a particularly expensive action, you may only want to cleanup when the element is about to be removed, not when it updates. (An aside: Because you have to track some state between modifier calls, a better solution may be to use ember-oo-modifiers instead).

But you can do it with a functional modifier. For example, let's imagine that we're using an RxJS observable-like thing that lets us hot-swap the action it fires. That may look something like:

// app/modifiers/my-rx-thing.js
import makeFunctionalModifier from 'ember-functional-modifiers';
import subscribe from './my-rx-js-observer';

const OBSERVERS = new WeakMap();

export default makeFunctionalModifier((element, [action]) => {
  const observer = OBSERVERS.has(element) ? OBSERVERS.get(element) : subscribe(element);

  observer.updateAction(action);

  OBSERVERS.set(element, observer);

  return (isRemoving) => {
    if (isRemoving) {
      observer.unsubscribe();
    }
  };
});
<button {{my-rx-thing (action "handleAction")}}>
  Click Me!
</button>

Example with Service Injection

You may also want to inject a service into your modifier.

You can do that by supplying an injection object before the the modifier function. For example, suppose you wanted to track click events with ember-metrics:

// app/modifiers/track-click.js
import makeFunctionalModifier from 'ember-functional-modifiers';

function trackClick(metrics, element, [eventName], options) {
  const callback = () => metrics.trackEvent(eventName, options);

  element.addEventListener('click', callback, true);

  return () => element.removeEventListener('click', callback);
}

export default makeFunctionalModifier(
  { services: ['metrics'] },
  trackClick
);

Then, you could use this in your template:

<button {{track-click "Clicked the THING!"}}>
  Click Me!
</button>

NOTE: Because we are not observing the properties in the service in any way, if we are reading a property on a service, the modifier will not recompute if that value changes. If that's the behavior you need, you probably want to pass that value into the modifier as an argument, rather than injecting it.

Contributing

See the Contributing guide for details.

Releasing

yarn release

License

This project is licensed under the MIT License.