# Apply decorations directly through an editor method?

**URL:** https://discuss.prosemirror.net/t/apply-decorations-directly-through-an-editor-method/2377
**Category:** Uncategorized
**Created:** [November 28, 2019, 10:51am UTC](https://discuss.prosemirror.net/t/apply-decorations-directly-through-an-editor-method/2377 "2019-11-28T10:51:05Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![ericksonc](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/ericksonc/32/1242_2.png) [@ericksonc](https://discuss.prosemirror.net/u/ericksonc)
#### Post date: [November 28, 2019, 10:51am UTC](https://discuss.prosemirror.net/t/apply-decorations-directly-through-an-editor-method/2377/1 "2019-11-28T10:51:05Z")

</div>

Is there a way to apply decorations directly through an editor method?

For example, let’s say my application knows that it wants to make everything from position 123 to position 456 purple. Assuming the EditorView object is called “editor,” what I’d really like to do is something as simple as:

```auto
editor.applyDecoration(Decoration.inline(123, 456, {style: "color: purple"})

```

Is there any way to do it as simple as that? If not, what’s the simplest way to go about it?

(Apologies if this is a basic question. From the documentation on decorations, I can see how to set them relative to things already in ProseMirror’s state, such as the current selection, but I couldn’t find any simple example of how to invoke them on the fly based on business logic sitting outside of ProseMirror.)

EDIT: I wrote an example plugin + helper method to enact the behavior I describe here, [code is below](https://discuss.prosemirror.net/t/apply-decorations-directly-through-an-editor-method/2377/7).

---

<div class="post-metadata">

### Author: ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)
#### Post date: [November 28, 2019, 11:06am UTC](https://discuss.prosemirror.net/t/apply-decorations-directly-through-an-editor-method/2377/2 "2019-11-28T11:06:49Z")

</div>

No, that doesn’t exist. Decorations are always owned by a plugin, and ProseMirror’s state is only updated through transactions, not with imperative methods.

So you _could_ write a plugin that manages a set of decorations, and write a function `applyDecoration` that fires off a transaction to add a given decoration. But there’s no built-in editor method like that.

---

<div class="post-metadata">

### Author: ![ericksonc](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/ericksonc/32/1242_2.png) [@ericksonc](https://discuss.prosemirror.net/u/ericksonc)
#### Post date: [November 28, 2019, 1:03pm UTC](https://discuss.prosemirror.net/t/apply-decorations-directly-through-an-editor-method/2377/3 "2019-11-28T13:03:28Z")

</div>

Thanks Marjin- makes sense and I do want to write said plugin.

After spending several hours on the docs and testing, though, I’m still not clear on how one can “fire off a transaction to add a decoration.”

I’ve run and tweaked the examples on “Decoration” from the guide (purplePlugin and specklePlugin) but they appear to work by returning a DecorationSet from props, I didn’t see anything about applying transactions there. (The only bit I saw referencing transactions was the apply() method, but that appears to be about allowing the plugin to have a transaction applied to it, not generating one.)

I’ve also looked through the transaction section of the reference guide, and I saw lots of methods that deal with either text or marks, but I didn’t see any that refer to decorations.

Are there any examples that show how to “fire off a transaction to add a decoration?”

---

<div class="post-metadata">

### Author: ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)
#### Post date: [November 28, 2019, 1:29pm UTC](https://discuss.prosemirror.net/t/apply-decorations-directly-through-an-editor-method/2377/4 "2019-11-28T13:29:07Z")

</div>

The view’s `dispatch` method is the usual way to run a transaction. A plugin’s state `apply` method can look for specific metadata properties in a transaction, and update its state (including its decoration set) based on that. So you’d define a metadata property, have a helper function that creates a transaction with that metadata, and a plugin that interprets it to add/remove decorations.

---

<div class="post-metadata">

### Author: ![ericksonc](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/ericksonc/32/1242_2.png) [@ericksonc](https://discuss.prosemirror.net/u/ericksonc)
#### Post date: [November 28, 2019, 4:27pm UTC](https://discuss.prosemirror.net/t/apply-decorations-directly-through-an-editor-method/2377/5 "2019-11-28T16:27:58Z")

</div>

Hmm, so if I understand you correctly, the two pieces I need are:

1. A _helper function_ that calls the view’s `dispatch` method to run a transaction which includes metadata
2. A _plugin_ with an apply method that’s capable of interpreting that metadata, and updating its state (including decoration set) accordingly

Does that sound about right?

I’m starting with piece 1), but before attempt to I trigger a transaction with metadata, I first want to make sure I can successfully trigger any kind of very simple transaction without getting an error message before moving on.

Here’s what I tried:

```
function insertSomeText(state, view) {
      let transaction = state.tr.insertText("abcd", 19,23)
      view.dispatch(transaction)
    }

```

However, this gives me the following error:

```
vue.runtime.esm.js?2b0e:1888 TypeError: field.apply is not a function
    at EditorState.applyInner (index.es.js?5313:855)
    at EditorState.applyTransaction (index.es.js?5313:819)
    at EditorState.apply (index.es.js?5313:795)
    at Editor.dispatchTransaction (tiptap.esm.js?cd42:1293)
    at EditorView.dispatch (index.es.js?576a:4703)
    at insertSomeText (Transcript.vue?8397:70)
    at VueComponent.triggerTransaction (Transcript.vue?8397:192)
    at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
    at HTMLButtonElement.invoker (vue.runtime.esm.js?2b0e:2179)
    at HTMLButtonElement.original._wrapper (vue.runtime.esm.js?2b0e:6911)

```

I’m not sure what this means, “`field.apply is not a function`”?

I get this same error message if I omit the “19,23” arguments, so I assume that means it’s not related to the pos values, and I’ve tried a few other types of transactions in place of insertText and received the same error as well. Any idea what am I doing wrong here?

---

<div class="post-metadata">

### Author: ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)
#### Post date: [November 28, 2019, 7:54pm UTC](https://discuss.prosemirror.net/t/apply-decorations-directly-through-an-editor-method/2377/6 "2019-11-28T19:54:40Z")

</div>

> [@ericksonc](#):
>
> I’m not sure what this means, “ `field.apply is not a function` ”?

That’s not from the code you showed, but from a broken plugin with an invalid `state` property.

---

<div class="post-metadata">

### Author: ![ericksonc](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/ericksonc/32/1242_2.png) [@ericksonc](https://discuss.prosemirror.net/u/ericksonc)
#### Post date: [November 29, 2019, 6:18am UTC](https://discuss.prosemirror.net/t/apply-decorations-directly-through-an-editor-method/2377/7 "2019-11-29T06:18:15Z")

</div>

Thanks, now I’m starting to get it!

I managed to get it to work, code is below.

**Helper Function:**

```
function applyDecoration (state, view, fromPos, toPos) {
  let transaction = state.tr.setMeta("directDecoration", {fromPos: fromPos, toPos: toPos})
  view.dispatch(transaction)
}

```

**Plugin:**

```
let directDecoration= new Plugin({
  state: {
    init() {
      // No decorations set by default
    },
    apply(tr, value) {
      if (tr.getMeta("directDecoration")) {
        const {fromPos, toPos} = tr.getMeta("directDecoration")
        return DecorationSet.create(tr.doc, [
          Decoration.inline(fromPos, toPos, {style: "color: purple"})
        ])
      } else {
         // map "other" changes so our decoration "stays put" 
         // (e.g. user is typing so decoration's pos must change)
        return value.map(tr.mapping, tr.doc)
      }
    }
  },
  props: {
    decorations(state) {
      return directDecoration.getState(state)
    }
  }
})
```
