# Migrating to v4

In v3 the Angular docs handed you a directive to copy into your own project. v4 replaces that with the official [`@foresightjs/angular`](/docs/angular/installation.md) package. Install it, delete your copied directive, and import the standalone directive from the package.

```
npm install @foresightjs/angular js.foresight
```

```
- import { ForesightDirective } from "./directives/foresight.directive"
+ import { ForesightDirective } from "@foresightjs/angular"
```

The directive selector is `[fsForesight]`:

```
<a href="/pricing" [fsForesight]="prefetchPricing">Pricing</a>
```

For reactive state, export the directive as `foresight` and read its signal:

```
<button [fsForesight]="prefetchCheckout" #foresight="foresight">
  {{ foresight.state().isPredicted ? "Ready" : "Checkout" }}
</button>
```

## Core changes[​](#core-changes "Direct link to Core changes")

The core `js.foresight` library also has a few breaking changes. The package handles most of these for you, but they matter if you call `register()` or listen to events directly.

The `register()` call itself is unchanged, but element data is now an immutable state snapshot you can subscribe to - the foundation the wrapper packages are built on:

* **`ForesightElementData` is now `ForesightElementState`.** Your callback receives the flat state snapshot: `callback: (state: ForesightElementState) => void`. See [TypeScript](/docs/getting-started/typescript.md).
* **`register()` returns the state plus `unregister`, `subscribe` and `getSnapshot`.** `isTouchDevice` is gone from the result; touch devices are handled internally by the configured `touchDeviceStrategy` global setting.
* **The `elementDataUpdated`, `elementOptionsUpdated` and `elementReactivated` events are removed.** Per-element changes are now observed through the `subscribe`/`getSnapshot` pair returned by `register()`. The remaining events carry the state in a `state` field instead of `elementData`.
* **Detached elements are parked, not unregistered.** Removing an element from the DOM no longer emits `elementUnregistered` with reason `disconnected`; the element stays registered but inactive and resumes when it reconnects.
* **New `enabled` element option.** Set it to `false` to keep an element registered but excluded from prediction.
