In config/environment.js
:
// config/environment.js
'use strict';
/*
* Mostly this is the stock module config.
*/
const moduleConfiguration = {
types: {
application: { definitiveCollection: 'main' },
component: { definitiveCollection: 'components' },
'component-test': { unresolvable: true },
helper: { definitiveCollection: 'components' },
'helper-test': { unresolvable: true },
renderer: { definitiveCollection: 'main' },
template: { definitiveCollection: 'components' },
/*
* Add service as a type.
*/
service: { definitiveCollection: 'services' }
},
collections: {
main: {
types: ['application', 'renderer']
},
components: {
group: 'ui',
types: ['component', 'component-test', 'template', 'helper', 'helper-test'],
defaultType: 'component',
privateCollections: ['utils']
},
styles: {
group: 'ui',
unresolvable: true
},
utils: {
unresolvable: true
},
/*
* Add services as a collection.
*/
services: {
types: ['service'],
defaultType: 'service',
privateCollections: ['utils']
}
}
};
module.exports = function(environment) {
let ENV = {
modulePrefix: 'bodega-glimmer',
environment: environment,
/*
* Pass the module config here.
*/
moduleConfiguration
};
return ENV;
};
// src/ui/components/apple-pay-button/component.ts
import Online from '../../../services/online';
import Component, { tracked } from '@glimmer/component';
import trackService from '../../../utils/tracked';
/*
* Use `trackService` to both inject the dependency and
* allow it to dirty the property.
*/
@trackService('online')
export default class ApplePayButton extends Component {
/*
* Define the property and type.
*/
online: Online;
/*
* Track the service like any other property.
*/
@tracked('online', 'args')
get isDisabled() {
return !this.online.isOnline || this.args.disabled;
}
};
// src/ui/services/apple-pay.ts
import Service from './-utils/service';
import { tracked } from '@glimmer/component';
export default class ApplePay extends Service {
/*
* If you use this property in a template, ala `{{applePay.tracked}}`,
* you will want to `@tracked` it. However you don't need this for
* dirtying the service where it is injected.
*/
@tracked isAvailable = false;
constructor(options) {
super(options);
if (self.Stripe && self.Stripe.applePay) {
self.Stripe.applePay.checkAvailability((result) => {
/*
* Set the property like normal.
*/
this.isAvailable = result;
/*
* This dirties all properties where this service is injected.
*/
this.notify();
});
}
}
}
Note for consumers of this code, when creating derived properties, you should (and can only) state the service its self as a dependency. Declaring dependencies on properties within the service (i.e.,
@tracked('applePay.isAvailable')
) will not work the wayEmber.computed
does.Also, for those interested in injecting multiple services without making their inheritance chain longer with each injection, here's a class decorator that'll allow use like this