Code Monkey home page Code Monkey logo

ember-macro-helpers's Introduction

ember-macro-helpers

Greenkeeper badge npm version Build Status Ember Version

Ember macro helpers for making your own fancy macros!

Check out the following projects to see this addon in use:

Contents

API

computed

computed behaves like Ember.computed with some extra benefits.

It will pass you resolved values:

import Ember from 'ember';
import computed from 'ember-macro-helpers/computed';

export default Ember.Component.extend({
  key: 'my value',

  result: computed('key', {
    get(value) {
      console.log(value); // 'my value'
      // do something else
    },
    set(newValue, value) {
      console.log(newValue); // 'new value'
      console.log(value); // 'my value'
      return newValue;
    }
  }),

  actions {
    doSomething() {
      this.set('result', 'new value');
    }
  }
});

You can compose using any of Ember's built-in macros:

import Ember from 'ember';
import computed from 'ember-macro-helpers/computed';

export default Ember.Component.extend({
  key1: false,
  key2: true,

  result: computed(Ember.computed.or('key1', 'key2'), value => {
    console.log(value); // true
    // do something else
  })
});

or you can compose using a macro library like ember-awesome-macros:

import Ember from 'ember';
import computed from 'ember-macro-helpers/computed';
import conditional from 'ember-awesome-macros/conditional';
import sum from 'ember-awesome-macros/sum';
import difference from 'ember-awesome-macros/difference';

export default Ember.Component.extend({
  key1: 345678,
  key2: 785572,

  result: computed(conditional(gt('key1', 'key2'), sum('key1', 'key2'), difference('key1', 'key2')), value => {
    console.log(value); // -439894
    // do something else
  })
});

It respects enumerable helpers:

import Ember from 'ember';
import computed from 'ember-macro-helpers/computed';

export default Ember.Component.extend({
  key1: [{ key2: 1 }, { key2: 2 }],

  computed1: computed('key1.[]', value => {
    console.log(value); // [{ key2: 1 }, { key2: 2 }]
    // do something else
  }),
  computed2: computed('[email protected]', value => {
    console.log(value); // [{ key2: 1 }, { key2: 2 }]
    // do something else
  }),
});

It resolves property expansion for you:

import Ember from 'ember';
import computed from 'ember-macro-helpers/computed';

export default Ember.Component.extend({
  key1: { key2: 1, key3: 2 },

  result: computed('key1.{key2,key3}', (value1, value2) => {
    console.log(value1); // 1
    console.log(value2); // 2
    // do something else
  })
});

This is also your best friend if you want to make your own macros that support composing out-of-the-box.

For example, here is an implementation of a macro that adds two numbers together:

// app/macros/add.js
import computed from 'ember-macro-helpers/computed';

export default function(key1, key2) {
  // The incoming keys can be key strings, raw values, or other macros.
  // It makes no difference to you.
  // `computed` will resolve them for you.
  return computed(key1, key2, (value1, value2) => {
    // At this point, the keys no long matter.
    // You are provided the resolved values for you to perform your operation.
    return value1 + value2;
  });
}

Then you can use it like this:

import Ember from 'ember';
import add from 'my-app/macros/add';

export default Ember.Component.extend({
  key1: 12,
  key2: 34,
  key3: 56,

  result: add(add('key1', 'key2'), add('key3', 78)) // 180
});
createClassComputed

This creates a class-based computed. This is useful when not the value, but the key being watched is variable. It rewrites your computed property when needed.

See ember-classy-computed for the inspiration source.

If you want an array macro that will respond when someone changes the array property they want to watch:

// app/macros/filter-by.js
import createClassComputed from 'ember-macro-helpers/create-class-computed';
import computed from 'ember-macro-helpers/computed';

export default createClassComputed(
  // the first param is the observer list
  // it refers to incoming keys
  // the bool is whether a value change should recreate the macro
  [
    // the array key
    false,

    // the array property is dynamic, and is responsible for the macro being rewritten
    true,

    // any static properties after the last dynamic property are optional
    // you could leave this off if you want
    false
  ],
  // the second param is the callback function where you create your computed property
  // it is passed in the values of the properties you marked true above
  (array, key, value) => {
    // when `key` changes, we need to watch a new property on the array
    // since our computed property is now invalid, we need to create a new one
    return computed(`${array}.@each.${key}`, value, (array, value) => {
      return array.filterBy(key, value);
    });
  }
);

And then we consume this macro like normal:

import Ember from 'ember';
import filterBy from 'my-app/macros/filter-by';

export default Ember.Component.extend({
  myArray: Ember.A([
    Ember.Object.create({ myProp: 0 }),
    Ember.Object.create({ myProp: 1 })
  ]),

  // this could change at any time and our macro would pick it up
  myKey: 'myProp',

  result: filterBy('myArray', 'myKey', 1)
});
curriedComputed

This is a shorthand version of computed. It allows you to create macros like this:

// app/macros/add.js
import curriedComputed from 'ember-macro-helpers/curried-computed';

export default curriedComputed(function(value1, value2) {
  // At this point, the keys no long matter.
  // You are provided the resolved values for you to perform your operation.
  return value1 + value2;
});
lazyComputed

This is the lazy resolving version of computed. The difference is instead of being provided the resolved values, you are provided the unresolved keys and a resolving function. This is useful if you want to optimize your macros and have early returns without calculating every key eagerly.

The API differs only slightly from computed:

// app/macros/and.js
import lazyComputed from 'ember-macro-helpers/lazy-computed';

export default function(key1, key2) {
  return lazyComputed(key1, key2, (get, key1, key2) => {
    // Where normally you get the values, now you have to calculate yourself.
    // The second key won't calculate if the first resolved value is falsy.
    return get(key1) && get(key2);
  });
}
lazyCurriedComputed

This is the combination of lazyComputed and curriedComputed.

literal

alias for raw

raw

This allows you to escape string literals to be used in macros.

Normally, a string means it will look up the property on the object context:

import Ember from 'ember';
import computed from 'ember-macro-helpers/computed';

export default Ember.Component.extend({
  key: 'value',

  result: computed('key', value => {
    console.log(value); // 'value'
    // do something else
  })
});

But if you just want to use the value without making an object property, you can use the raw macro:

import Ember from 'ember';
import computed from 'ember-macro-helpers/computed';
import raw from 'ember-macro-helpers/raw';

export default Ember.Component.extend({
  key: 'value',

  // Even though we are using a string that is the same name as a property on the object,
  // the `raw` macro will ignore the object property and treat the string as a literal.
  result: computed(raw('key'), value => {
    console.log(value); // 'key'
    // do something else
  })
});

The usefulness is more apparent when using complex macros, for example, when using the string split macro from ember-awesome-macros:

import Ember from 'ember';
import raw from 'ember-macro-helpers/raw';
import split from 'ember-awesome-macros/array/split';

export default Ember.Component.extend({
  key: '1, 2, 3',

  result: split('key', raw(', ')) // [1, 2, 3]
});
reads

alias for writable

writable

This is a setting API for read-only macros.

Given the following read-only macro called sum:

import computed from 'ember-macro-helpers/computed';

export default function(key1, key2) {
  return computed(key1, key2, (value1, value2) => {
    return value1 + value2;
  }).readOnly();
}

and its usage:

key1: 1,
key2: 2,
result: sum('key1', 'key2')

If you try and set result, you will get a read-only exception.

If you want to bring back the setting functionality, you can wrap it in the writable macro:

key1: 1,
key2: 2,
result: writable(sum('key1', 'key2'))

Now, setting result will remove the macro and replace it with your value.

If you want to do something unique when setting, you can provide a set callback:

key1: 1,
key2: 2,
result: writable(sum('key1', 'key2'), {
  set() {
    // do something
    return 'new value';
  }
}), // setting this will not overwrite your macro

or:

key1: 1,
key2: 2,
result: writable(sum('key1', 'key2'), function() {
  // do something
  return 'new value';
}) // same as above, but shorthand

Setting result here will not remove your macro, but will update result with the return value.

Custom macros

The addon provides a way of creating your own custom macros. The easiest way is to use the blueprint generator:

ember generate macro my-custom-macro

This will generate an example macro and its associated test. The comments in these files will get you started.

More explanation is given in the introduction video.

ember-macro-helpers's People

Contributors

clekstro avatar ember-tomster avatar greenkeeper[bot] avatar lolmaus avatar mriska avatar mwpastore avatar shamcode avatar turbo87 avatar yoranbrondsema avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.