Skip to content

This is list of handy ember primitives, created to simplify class-based dom workflow

License

Notifications You must be signed in to change notification settings

yapplabs/ember-ref-bucket

This branch is 6 commits behind lifeart/ember-ref-bucket:master.

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Oct 11, 2023
543c4ce · Oct 11, 2023

History

86 Commits
Jan 9, 2023
Oct 11, 2023
Aug 2, 2023
Oct 11, 2023
Aug 26, 2021
Oct 11, 2023
Aug 4, 2020
Aug 4, 2020
Aug 4, 2020
Aug 26, 2021
Aug 26, 2021
Aug 26, 2021
Aug 26, 2021
Aug 26, 2021
Aug 26, 2021
Aug 26, 2021
Aug 26, 2021
Aug 4, 2020
Aug 26, 2021
Aug 4, 2020
Jul 22, 2023
Aug 26, 2021
Aug 26, 2021
Oct 11, 2023
Aug 26, 2021
Jan 9, 2023

Repository files navigation

ember-ref-bucket

This addon was created as a rethinking of ember-ref-modifier, with a more simplified API and without some of the downsides of the previous implementation.

The addon allows users to get access to DOM nodes inside components, including accessing wrapping/destroying logic.

A simple use case:

  • applying ref modifier with passed name to an element.
<div {{create-ref "FavouriteNode"}}>hello</div>
  • gain access to it inside the component class as a decorated property
import Component from '@glimmer/component';
import { ref } from 'ember-ref-bucket';

export default class MyComponent extends Component {
  @ref("FavouriteNode") node; 
  // this.node === "<div>hello</div>"
}

API differences, comparing to ember-ref-modifier:

In ember-ref-modifier ref modifier accept 2 positional arguments {{ref this "property"}}:

  1. context to set path (this)
  2. path to set on context ("property")

In ember-ref-bucket ref modifier accept 1 positional argument {{create-ref "field"}}:

  1. reference name ("field")

reference name should be passed as an argument to the @ref("field") decorator, to allow it to find the reference by name.

Compatibility

  • Ember.js v3.24 or above
  • Ember CLI v3.24 or above
  • Node.js v14 or above

Installation

ember install ember-ref-bucket

Usage

Examples

Simple player

<audio {{create-ref "player"}} src="music.mp3"></audio>
<button {{on "click" this.onPlay}}>Play</button>
import Component from '@glimmer/component';
import { ref } from 'ember-ref-bucket';
import { action } from '@ember/object';

export class Player extends Component {
  @ref('player') audioNode;
  @action onPlay() {
    this.audioNode.play()
  }
}

Link div to node property.

<div {{create-ref "field"}} ></div>
import Component from '@glimmer/component';
import { ref } from 'ember-ref-bucket';

export default class MyComponent extends Component {
  @ref("field") node = null;
}

Dynamically show div content updates

<div {{create-tracked-ref "field"}}>hello</div>

{{get (tracked-ref-to "field") "textContent"}}

Use div as component argument

<div {{create-ref "field"}}>hello</div>

<SecondComponent @helloNode={{ref-to "field"}} />

Use registerNodeDestructor

This method is very useful if you want to wrap the node and control its lifecycle.

<div {{create-ref "field"}}>
import Component from '@glimmer/component';
import { ref, registerNodeDestructor } from 'ember-ref-bucket';

class NodeWrapper {
  constructor(node) {
    this.node = node;
  }
  destroy() {
    this.node = null;
  }
  value() {
    return this.node.textContent;
  }
}

export default class WrappedNodeComponent extends Component {
  @ref('field', (node) => {
    const instance = new NodeWrapper(node);
    registerNodeDestructor(node, () => instance.destroy());
    return instance;
  }) node = null;
  get value() {
    return this.node?.value();
  }
}

Available decorators:

import { ref, globalRef, trackedRef, trackedGlobalRef } from 'ember-ref-bucket';

/*
  ref - usage: @ref('foo', nodeWrapFn?), ref to bucket with current component context
  globalRef - usage: @globalRef('foo', nodeWrapFn?), ref to global context (app)
  trackedRef - usage: @trackedRef('foo', nodeWrapFn?), tracked ref to local context
  trackedGlobalRef - usage: @trackedGlobalRef('foo', nodeWrapFn?), tracked ref to global context (app)

*/

Available methods:

import { registerNodeDestructor, unregisterNodeDestructor } from 'ember-ref-bucket';

/*
  registerNodeDestructor(node, fn) - to assign any ref-node destructor
  unregisterNodeDestructor(node, fn) - to remove assigned ref-node destructor 

  usage will be like:

  @ref('field', (node) => {
    const item = new InputMask(node);
    registerNodeDestructor(node, () => item.destroy());
    return item;
  });
*/
/* 
  nodeFor - functional low-level primitive to get node access
*/

import { nodeFor } from 'ember-ref-bucket';

const domNode = nodeFor(this, 'field');

Definition of @trackedRef decorators

  • If you use dom node in @tracked chain calculations, you should use trackedRef.

  • If you don't need to rerun the tracked chain (for example, you use ref only for some event-based dom access), you should not use trackedRef.

Definition of {{create-tracked-ref}} modifiers

  • If you need to watch for node changes (resize, content, attributes), you can use the create-tracked-ref modifier. It can add observe resizing and mutations for the associated element and will mark it as "dirty" for any mutation.

Options:

  • resize - default: false, if truthy observes the resizing of the DOM element.
  • attributes - default: false, if truthy observes the changing of any attribute on the DOM element.
  • character - default: false, if truthy observes the change of the innerText of the DOM element. Note that setting innerText can change the children or the character depending on the current content of the element.
  • children - default: false, if truthy observes changes to the list of direct children of the DOM element.
  • subtree - default: false, if truthy observes the above options on the entire DOM subtree, not just the element decorated by the modifier.

Definition of {{tracked-ref-to}} helpers

  • If you need to recalculate helper if some dom node changes (size, children, attributes), you need to use tracked-ref-to helper.
  • If you don't need it (you need to just have ref to dom node), you should choose ref-to helper.

Template-only components

  • create-ref modifier and ref-to helpers will not work in template-only components (because of no context). You should use create-global-ref and global-ref-to instead. You can also provide a bucket param to the create-ref modifier / helper.

The addon provide only 1 modifier (create-ref) and 1 helper (ref-to). Other derivatives will be transformed, and are described below:

Modifiers will be transformed according to this table:

Invocation Will be transformed to
{{create-ref "foo"}} {{create-ref "foo" bucket=this}}
{{create-tracked-ref "foo"}} {{create-ref "foo" bucket=this tracked=true}}
{{create-global-ref "foo"}} {{create-ref "foo" bucket=undefined}}
{{create-tracked-global-ref "foo"}} {{create-ref "foo" bucket=undefined tracked=true}}

Helpers will be transformed according to this table:

Invocation Will be transformed to
{{ref-to "foo"}} {{ref-to "foo" bucket=this}}
{{tracked-ref-to "foo"}} {{ref-to "foo" bucket=this tracked=true}}
{{global-ref-to "foo"}} {{ref-to "foo" bucket=undefined}}
{{tracked-global-ref-to "foo"}} {{ref-to "foo" bucket=undefined tracked=true}}

Contributing

See the Contributing guide for details.

Version matrix:

Ember-Modifier 4 - v5; Ember 3.28 - v4; Ember 3.24 - v3

License

This project is licensed under the MIT License.

About

This is list of handy ember primitives, created to simplify class-based dom workflow

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 92.1%
  • HTML 5.3%
  • Handlebars 2.6%