# How to modify Node Attribute without replacing it and causing it to re-render

**URL:** <https://discuss.prosemirror.net/t/how-to-modify-node-attribute-without-replacing-it-and-causing-it-to-re-render/2510>\
**Category:** Uncategorized\
**Created:** [February 5, 2020, 1:24pm UTC](https://discuss.prosemirror.net/t/how-to-modify-node-attribute-without-replacing-it-and-causing-it-to-re-render/2510 "2020-02-05T13:24:35Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![turigeza](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/turigeza/32/1275_2.png) [@turigeza](https://discuss.prosemirror.net/u/turigeza)\
**Post date:** [February 5, 2020, 1:24pm UTC](https://discuss.prosemirror.net/t/how-to-modify-node-attribute-without-replacing-it-and-causing-it-to-re-render/2510/1 "2020-02-05T13:24:35Z")

</div>

So I know how to modify a nodes attribute with [`setNodeMarkup`](https://prosemirror.net/docs/ref/#transform.Transform.setNodeMarkup). But that will create a brand new node and causes the dom to re-render it’s content. This is fine if all you have is a paragraph.

But in my case I have put content in there which ProseMirror is not aware of and I would like to avoid destroying that content when I change the attribute.

Is there a way to do this ?

**Why do I need this:**

I have carousel node which inside of lots of dom modification happens and I don’t want to reinitialise the carousel every time I change its html attribute. It causes really annoying jumps in the editor. Everything else works great.

But maybe I am approaching this problem the wrong way ?

**Schema:**

```auto
    carousel: {
        group: "block",
        defining: true, // node is considered an important parent node during replace operations
        selectable: true,
        atom: true, // though this isn't a leaf node, it doesn't have directly editable content and should be treated as a single unit in the view.
        draggable: false,
        attrs: {
            class: {
                default: null
            },
            html: {
                default: ''
            }
        },
        parseDOM: [{
            tag: 'div.tg_subwidget_carousel',
            getAttrs: dom => {
                return {
                    'class': dom.getAttribute("class"),
                    html: dom.innerHTML
                };
            }
        }],
        toDOM(node) {
            let newDiv = document.createElement("div");
            newDiv.innerHTML = node.attrs.html;
            if(node.attrs){
                newDiv.setAttribute('class', node.attrs.class);
            }

            return newDiv;
        }
    },

```

**Node View:**

```auto

export default class CarouselView {

    constructor(node, view, getPos) {
        this.node = node
        this.view = view
        this.getPos = getPos

        this.dom = document.createElement('div');
        this.dom.innerHTML = node.attrs.html;

        if(node.attrs.class){
            this.dom.setAttribute("class", node.attrs.class);
        }

        // this where we need to reapply the carousel but not always
        if(view.$d_listeners && typeof view.$d_listeners.afterCarouselConstruct === 'function'){
            view.$d_listeners.afterCarouselConstruct(this.dom, node, view, getPos);
        }
    }

    update(node, decorations) {
        console.log('UPDATE --- CarouselHtmlView');
    }

    ignoreMutation() {
        return true;
    }

    destroy() {
        this.dom.remove();
        console.log('destroy --- CarouselHtmlView');
    }

}

```

---

<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:** [February 5, 2020, 3:00pm UTC](https://discuss.prosemirror.net/t/how-to-modify-node-attribute-without-replacing-it-and-causing-it-to-re-render/2510/2 "2020-02-05T15:00:52Z")

</div>

The node view `update` method is what you should be looking at.

---

<div class="post-metadata">

**Author:** ![turigeza](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/turigeza/32/1275_2.png) [@turigeza](https://discuss.prosemirror.net/u/turigeza)\
**Post date:** [February 5, 2020, 11:01pm UTC](https://discuss.prosemirror.net/t/how-to-modify-node-attribute-without-replacing-it-and-causing-it-to-re-render/2510/3 "2020-02-05T23:01:04Z")

</div>

Thank you for that. Adding

```auto
update(node, decorations) {
        return true;
    }

```

to the node view indeed does the job and the dom does not get updated.

But now I have an other issue.

If the update was triggered by a history step I would like node view update to `return false`. So that the history back and forth steps are handled by ProseMirror. Anyway to know in the node view update what transaction caused the update to trigger ?

Or any other suggestion ?

---

<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:** [February 6, 2020, 7:39am UTC](https://discuss.prosemirror.net/t/how-to-modify-node-attribute-without-replacing-it-and-causing-it-to-re-render/2510/4 "2020-02-06T07:39:11Z")

</div>

Definitely don’t just `return true` from your `update` method. You’ll at the very least want to check whether the node you’re given is still of the right type, and often you’ll also need to check its attributes or content to make sure your DOM content accurately reflects the node—and then either update the DOM or return false if it doesn’t.

I think that should also cover your history issue—you can’t know what transaction caused the change, in the `update` method, since it’s not handling a transaction, it’s just getting a new node to display. If you make sure it does that properly, ProseMirror’s history transactions should also just work.

---

<div class="post-metadata">

**Author:** ![turigeza](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/turigeza/32/1275_2.png) [@turigeza](https://discuss.prosemirror.net/u/turigeza)\
**Post date:** [February 6, 2020, 6:42pm UTC](https://discuss.prosemirror.net/t/how-to-modify-node-attribute-without-replacing-it-and-causing-it-to-re-render/2510/5 "2020-02-06T18:42:50Z")

</div>

" DOM content accurately reflects the node "

This was the key to this. Thank you! I ended up writing a function which gets the original html out of the carousel like if the carousel code has never been applied and compared that to the `node.attrs.html` in the update of the node view. If the values don’t match the view is out of sync that is when I have to return false and reinitialise the carousel on the dom.

It seem to work just fine.

This however I do not fully understand but don’t bother explaining it if you are busy … it is not crucial to me just now.

I have seen in the docs as well … [https://prosemirror.net/docs/ref/#view.NodeView.update](https://prosemirror.net/docs/ref/#view.NodeView.update) “It will be given a node (possibly of a different type)” or as per above “You’ll at the very least want to check whether the node you’re given is still of the right type”

**When would this happen ?**

I am kind of expecting it should be the same type all the time (in this case anyway). After all there is no editable content in the node.

Anyway thank you for putting me in the right direction! : )

---

<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:** [February 7, 2020, 8:09am UTC](https://discuss.prosemirror.net/t/how-to-modify-node-attribute-without-replacing-it-and-causing-it-to-re-render/2510/6 "2020-02-07T08:09:11Z")

</div>

You can write node views that are able to display several types of node, and switch to a new type without redrawing.

---

<div class="post-metadata">

**Author:** ![turigeza](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/turigeza/32/1275_2.png) [@turigeza](https://discuss.prosemirror.net/u/turigeza)\
**Post date:** [February 7, 2020, 9:21am UTC](https://discuss.prosemirror.net/t/how-to-modify-node-attribute-without-replacing-it-and-causing-it-to-re-render/2510/7 "2020-02-07T09:21:01Z")

</div>

I see.

In my case this is not needed or wanted so I don’t have to check if type changed it will be same each and every time and only its attributes change.

Thank you.

---

<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:** [February 7, 2020, 9:34am UTC](https://discuss.prosemirror.net/t/how-to-modify-node-attribute-without-replacing-it-and-causing-it-to-re-render/2510/8 "2020-02-07T09:34:54Z")

</div>

Yes, you do have to check to make sure you actually _got_ the same type.

---

<div class="post-metadata">

**Author:** ![turigeza](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/turigeza/32/1275_2.png) [@turigeza](https://discuss.prosemirror.net/u/turigeza)\
**Post date:** [February 7, 2020, 10:10am UTC](https://discuss.prosemirror.net/t/how-to-modify-node-attribute-without-replacing-it-and-causing-it-to-re-render/2510/9 "2020-02-07T10:10:00Z")

</div>

I don’t get it. : ) I am sorry.

It makes no sense to me for this node to be any other type then ‘carousel’. This node view is for the node type ‘carousel’.

But perhaps there are some transactions which would attempt to change the node type to something else that I don’t know of ?

So update should just return true if the wrong type is given ? I guess so because it makes no sense to change the node type to anything else.

---

<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:** [February 7, 2020, 10:22am UTC](https://discuss.prosemirror.net/t/how-to-modify-node-attribute-without-replacing-it-and-causing-it-to-re-render/2510/10 "2020-02-07T10:22:45Z")

</div>

> [@turigeza](#):
>
> So update should just return true if the wrong type is given ?

No, it should return _false_ to indicate that it can not update itself to reflect the node.

---

<div class="post-metadata">

**Author:** ![turigeza](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/turigeza/32/1275_2.png) [@turigeza](https://discuss.prosemirror.net/u/turigeza)\
**Post date:** [February 7, 2020, 10:29am UTC](https://discuss.prosemirror.net/t/how-to-modify-node-attribute-without-replacing-it-and-causing-it-to-re-render/2510/11 "2020-02-07T10:29:53Z")

</div>

Ok. I am just going to put the code in and not try to understand. Thank you for your help. Maybe later I try and wrap my head around this.

---

<div class="post-metadata">

**Author:** ![hitsthings](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/hitsthings/32/1146_2.png) [@hitsthings](https://discuss.prosemirror.net/u/hitsthings)\
**Post date:** [April 8, 2023, 11:02pm UTC](https://discuss.prosemirror.net/t/how-to-modify-node-attribute-without-replacing-it-and-causing-it-to-re-render/2510/12 "2023-04-08T23:02:20Z")

</div>

If anyone happens across this in the future (like I am now), here’s an example case I had to deal with for a node view.

My node view was meant to be for image nodes. So I added the `{ image: myImageNodeViewFactory }` line to my plugin. I _thought_ that meant I’d only have to deal with image nodes. But if I selected an image in the editor and typed a letter, the image would (rightly) be replaced with a paragraph node. My image node view’s `update` method would be called with a _paragraph_ node. I have to return false in that case to let Prosemirror know I can’t handle (and don’t want to handle) paragraphs. Once I’ve done that, Prosemirror uses a different renderer for that paragraph node (presumably the built-in renderer).

So I guess the tl;dr is - your `update` method could be called with _any_ node, not just the type of node you’re trying to handle. If you don’t want to handle it, return false.

---

<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:** [April 12, 2023, 10:12am UTC](https://discuss.prosemirror.net/t/how-to-modify-node-attribute-without-replacing-it-and-causing-it-to-re-render/2510/13 "2023-04-12T10:12:53Z")

</div>

This patch adds a special case to the DOM update algorithm to recognize and optimize wrapper-node-only changes.

> <https://github.com/ProseMirror/prosemirror-view/commit/47be3c32b9fd2238a4bffd7435ada713cee64750>
>
> FIX: Improve performance of changing a parent node (by type or attributes) witho…ut
> modifying its children by reusing the DOM of the child nodes.
> 
> See https://discuss.prosemirror.net/t/how-to-modify-node-attribute-without-replacing-it-and-causing-it-to-re-render/2510
