diff --git a/guides/release/services/index.md b/guides/release/services/index.md index e9daa7e421..404dae0d35 100644 --- a/guides/release/services/index.md +++ b/guides/release/services/index.md @@ -140,3 +140,145 @@ Note `cart` being used below to get data from the cart. ``` + +### Accessing services from native classes + +If you want to access a service from a plain JavaScript class, you'll need to get a reference to the "[owner](https://api.emberjs.com/ember/release/modules/@ember%2Fowner)" object, which is responsible for managing services. + +First, we can define a class that accesses services as described above: + +```javascript {data-filename=app/components/cart-contents/vanilla-class.js} +import { service } from '@ember/service'; + +export class VanillaClass { + @service shoppingCart; + + someMethod() { + // Now you can use the service + this.shoppingCart.add(/* ... */); + } +} +``` + +And then to wire up `VanillaClass` to work with `@service`, you'll need to implement a ceremony: + +```javascript {data-filename=app/components/cart-contents/index.js} +import { getOwner, setOwner } from '@ember/owner'; +import { VanillaClass } from './vanilla-class'; + +export default class CartContentsComponent extends Component { + @cached + get vanillaClass() { + const instance = new VanillaClass(); + + setOwner(instance, getOwner(this)); + + return instance; + } +} +``` + +In reality, this could be any framework-construct: a service, route, controller, etc -- in this case we use a component, but this could also be done in another vanilla class that's already be wired up. +The pattern here is to use a [`@cached`](https://api.emberjs.com/ember/5.3/functions/@glimmer%2Ftracking/cached) getter to ensure a stable reference to the class, and then using [`setOwner`]( https://api.emberjs.com/ember/5.3/functions/@ember%2Fowner/setOwner) and [`getOwner`](https://api.emberjs.com/ember/5.3/functions/@ember%2Fowner/getOwner), we finish the wiring ceremony needed to make native classes work with services. + + +