> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/web/migration-guides/migrating-to-v6.md).

# Migrating to V6 of WebViewer

Migrate smoothly to v6 with these breaking changes: jQuery CoreControls.js dependency removed, new event handling, and updated APIs for annotation management. Learn more here! The Apryse Web SDK strea

There are a few **breaking changes** when migrating to v6 from older versions.

## No more jQuery

CoreControls.js is no longer dependent on jQuery, thus all APIs that use jQuery are changed.

### Event handling

The jQuery `e` isn't passed to event handlers as the first argument anymore. The `imported` property for `annotationChanged` is now accessible on the third argument.

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// Version 5.x and older
docViewer.on('zoomUpdated', (e, zoom) => {
  ...
});
annotManager.on('annotationChanged', (e, annotations, action) => {
  if (e.imported) {
    ...
  }
});

// Version 6.0 and after
docViewer.on('zoomUpdated', zoom => {
  ...
});
annotManager.on('annotationChanged', (annotations, action, info) => {
  if (info.imported) {
    ...
  }
});
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Event trigger for annotationChanged

Since the event handler now takes an `info` object as a third argument, it should be also included when manually triggering an annotationChanged event.

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
const annotations = [...];
const action = 'add';

// Version 5.x and older
annotManager.trigger('annotationChanged', [annotations, action]);

// Version 6.0 and after
const info = {
  imported: false, // optional property
  isUndoRedo: false, // optional property
};

annotManager.trigger('annotationChanged', [annotations, action, info]);
```

{% endcode %}
{% endtab %}
{% endtabs %}

### CreateInnerElement

The innerElement of all widget annotations is now a normal DOM element instead of a jQuery wrapped element. This means that `createInnerElement` should return a normal DOM element now.

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// Version 5.x and older
Annotation.SignatureWidgetAnnotation.prototype.createInnerElement = function() {
  const div = document.createElement('div');

  ...

  return $(div);
}

// Version 6.0 and after
Annotation.SignatureWidgetAnnotation.prototype.createInnerElement = function() {
  const div = document.createElement('div');

  ...

  return div;
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### SetSignatureCanvas

It takes a canvas element instead of a jQuery wrapped canvas element.

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// Version 5.x and older
const signatureTool = docViewer.getTool('AnnotationCreateSignature');
const canvas = document.createElement('canvas');

signatureTool.setSignatureCanvas($(canvas));


// Version 6.0 and after
const signatureTool = docViewer.getTool('AnnotationCreateSignature');
const canvas = document.createElement('canvas');

signatureTool.setSignatureCanvas(canvas);
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Config file

jQuery is no longer accessible inside a config file. The `viewerLoaded` and `documentLoaded` events are triggered on the window instead of the wrapped document object now.

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// Version 5.x and older
$(document).on('viewerLoaded', () => {
  ...
});
$(document).on('documentLoaded', () => {
  ...
});

// Version 6.0 and after
window.addEventListener('viewerLoaded', () => {
  ...
});
window.addEventListener('documentLoaded', () => {
  ...
});
```

{% endcode %}
{% endtab %}
{% endtabs %}

## AnnotationManager getAnnotCommand is asynchronous

Previously this API didn't wait for the resources to be loaded for annotations before exporting them, which may result in an empty ImageData property for stamp annotations. Now this API waits for it internally. This API is deprecated in favor of [exportAnnotCommand](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#exportAnnotCommand__anchor).

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// Version 5.x and older
const annots = instance.annotManager.getAnnotationsList();
Promise
  .all(annots.map(annot => annot.resourcesLoaded()))
  .then(() => {
    const xfdfString = annotManager.getAnnotCommand();
  });

// Version 6.0 and after
annotManager.getAnnotCommand().then(xfdfString => {
  ...
});
```

{% endcode %}
{% endtab %}
{% endtabs %}

## AnnotationManager exportAnnotations is asynchronous

Previously this API didn't wait for the freehand tool to finish drawing before exporting the XFDF, which may result in missing freehand annotations data. It didn't wait for the resources to be loaded as described above. Now the API waits for it internally.

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// Version 5.x and older
const freehandTool = docViewer.getTool('AnnotationCreateFreeHand');
const annots = instance.annotManager.getAnnotationsList();
Promise.all([
  ...annots.map(annot => annot.resourcesLoaded()),
  freeHandTool.complete()
]).then(() => {
  // to make sure that freehand annotations will be in the output XFDF.
  const xfdfString = annotManager.exportAnnotations();
});

// Version 6.0 and after
annotManager.exportAnnotations().then(xfdfString => {
  ...
});
```

{% endcode %}
{% endtab %}
{% endtabs %}

## AnnotationManager importAnnotCommand is asynchronous

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// Version 5.x and older
const xfdfString = '...';
const importedAnnotations = annotManager.importAnnotCommand(xfdfString);

// Version 6.0 and after
const xfdfString = '...';
annotManager
  .importAnnotCommand(xfdfString)
  .then(importedAnnotations => {
    ...
  });
```

{% endcode %}
{% endtab %}
{% endtabs %}

## AnnotationManager importAnnotations is asynchronous

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// Version 5.x and older
const xfdfString = '...';
const importedAnnotations = annotManager.importAnnotations(xfdfString);

// Version 6.0 and after
const xfdfString = '...';
annotManager
  .importAnnotations(xfdfString)
  .then(importedAnnotations => {
    ...
  });
```

{% endcode %}
{% endtab %}
{% endtabs %}

## AnnotationManager importAnnotationsAsync is replaced with importAnnotations

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// Version 5.x and older
const xfdfString = '...';
const options = {...};

annotManager.importAnnotationsAsync(
  xfdfString, 
  importedAnnotations => {
    ...
  },
  options,
);

// Version 6.0 and after
annotManager
  .importAnnotations(xfdfString, options)
  .then(importedAnnotations => {
    ...
  });
```

{% endcode %}
{% endtab %}
{% endtabs %}

## The Annotations.Annotation Custom property

The `Custom` property is mainly used to store a custom property to an annotation. Prior to 6.0 you need to extend Annotations.Annotation's serialize and deserialize methods to make sure that this property shows in the exported XFDF. In 6.0 we replace this property with `CustomData`. The value of it will be serialized to the output XFDF, and even better, be preserved in the downloaded document.

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// Version 5.x and older
const serialize = Annotations.Annotation.prototype.serialize;

Annotations.Annotation.prototype.serialize = function() {
  const el = serialize.apply(this, arguments);

  if (this.Custom) {
    el.setAttribute('custom', this.Custom);
  }

  return el;
};

const deserialize = Annotations.Annotation.prototype.deserialize;

Annotations.Annotation.prototype.deserialize = function(el) {
  deserialize.apply(this, arguments);

  this.Custom = el.getAttribute('custom');
};

annot.Custom = {
  isChecked: false,
};

// Version 6.0 and after
annot.CustomData = {
  isChecked: false,
};
```

{% endcode %}
{% endtab %}
{% endtabs %}

## GetCustomData

Inside a config file, this function is moved to the `readerControl` object.

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// Inside a config file

// Version 5.x and older
const customData = window.ControlUtils.getCustomData();

// Version 6.0 and after
const customData = window.readerControl.getCustomData();
```

{% endcode %}
{% endtab %}
{% endtabs %}

## Document Viewer getCompleteRotation API requires a parameter

[docViewer.getCompleteRotation](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#getCompleteRotation__anchor) now requires a page number as the first parameter.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/web/migration-guides/migrating-to-v6.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
