# Keep preexisting custom attributes on nodes

**URL:** https://discuss.prosemirror.net/t/keep-preexisting-custom-attributes-on-nodes/1581
**Category:** Uncategorized
**Created:** [October 16, 2018, 3:40pm UTC](https://discuss.prosemirror.net/t/keep-preexisting-custom-attributes-on-nodes/1581 "2018-10-16T15:40:11Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![bit-less](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/bit-less/32/1010_2.png) [@bit-less](https://discuss.prosemirror.net/u/bit-less)
#### Post date: [October 16, 2018, 3:40pm UTC](https://discuss.prosemirror.net/t/keep-preexisting-custom-attributes-on-nodes/1581/1 "2018-10-16T15:40:11Z")

</div>

Using the dino example from [https://prosemirror.net/examples/dino/](https://prosemirror.net/examples/dino/), I can’t figure from the documentation how I can preserve any custom attributes added to the nodes before parsing.

So if I were to add attributes and values to the dino nodes (in the content), they would get removed when the content gets parsed. I need this meta data for an existing workflow. Mostly data attributes. [This](https://discuss.prosemirror.net/t/preserving-custom-attributes/204) article seemed to have the same question, but the solution’s parse function doesn’t fire, so maybe the spec as changed.

Any help would be very welcomed. Thanks!

---

<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: [October 16, 2018, 3:58pm UTC](https://discuss.prosemirror.net/t/keep-preexisting-custom-attributes-on-nodes/1581/2 "2018-10-16T15:58:19Z")

</div>

Your parse rule(s) for the node will have to read the values from the DOM and add them as attributes.

---

<div class="post-metadata">

### Author: ![bit-less](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/bit-less/32/1010_2.png) [@bit-less](https://discuss.prosemirror.net/u/bit-less)
#### Post date: [October 16, 2018, 4:47pm UTC](https://discuss.prosemirror.net/t/keep-preexisting-custom-attributes-on-nodes/1581/3 "2018-10-16T16:47:27Z")

</div>

Which object/method is that under? It looks like the [DOMParser](https://prosemirror.net/docs/ref/version/0.18.0.html#model.DOMParser)?

---

<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: [October 16, 2018, 8:32pm UTC](https://discuss.prosemirror.net/t/keep-preexisting-custom-attributes-on-nodes/1581/4 "2018-10-16T20:32:37Z")

</div>

For nodes that you define, you’d usually store them in the [`parseDOM` spec](http://prosemirror.net/docs/ref/#model.NodeSpec.parseDOM). See for example the way the basic schema’s [image node](https://github.com/ProseMirror/prosemirror-schema-basic/blob/master/src/schema-basic.js#L86) constructs document node attributes from DOM attributes.

---

<div class="post-metadata">

### Author: ![bit-less](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/bit-less/32/1010_2.png) [@bit-less](https://discuss.prosemirror.net/u/bit-less)
#### Post date: [October 17, 2018, 3:48pm UTC](https://discuss.prosemirror.net/t/keep-preexisting-custom-attributes-on-nodes/1581/5 "2018-10-17T15:48:14Z")

</div>

Thank you for helping. I tried that approach with no success, and many other variations. I feel like there’s just a fundemental piece I’m missing. I’ve built a WYSIWYG with the same behavior as you see in the dino example, but it was done with DOM manipulation/watching, but ProseMirror wrote it the way I would if I were to do it again. While I agree with the complete modularization of ProseMirror, I’m struggling to put the pieces together for these dino nodes, let alone in my own company’s implementation.

So in part desperation, I have _really_ avoided doing this ever, but could you kindly adjust this dino demo, and comment on what you changed and why?

This is the dino demo from the PM website, and I’ve included a `data-some="thing"` attribute on the tyrannosaurus node in the pre-existing content that I want persisted when PM parses it. (In my real application, we’ll have multiple data attributes with unknown/variable values, and style attributes for those that have to work in Outlook for desktop).

```
    <!doctype html>
    <head>
    <title>Dinos in the Document</title>
    <meta charset="utf8">
    <link rel="stylesheet" href="https://prosemirror.net/css/editor.css">
    <script src="https://prosemirror.net/examples/prosemirror.js"></script>
    <script src="require-pm.js"></script>

    <script src="index.js" defer></script>
    <base href="http://prosemirror.net/">

    <style>
      img.dinosaur { height: 40px; vertical-align: bottom; border: 1px solid #0ae; border-radius: 4px; background: #ddf6ff }
    </style>

    </head>
    <body>

    <div id="editor"></div>

    <div id="content" style="display: none">
      <p>This is your dinosaur-enabled editor. The insert menu allows you
      to insert dinosaurs.</p>
      <p>This paragraph <img class="dinosaur" dino-type="stegosaurus">, for example,
      <img class="dinosaur" dino-type="triceratops">
      is full <img class="dinosaur" dino-type="tyrannosaurus" data-some="thing"> of
      dinosaurs.</p>
      <p>Dinosaur nodes can be selected, copied, pasted, dragged, and so on.</p>
    </div>

    <script type="text/javascript">

      // The supported types of dinosaurs.
      const dinos = ["brontosaurus", "stegosaurus", "triceratops",
                     "tyrannosaurus", "pterodactyl"]

      const dinoNodeSpec = {
        // Dinosaurs have one attribute, their type, which must be one of
        // the types defined above.
        // Brontosaurs are still the default dino.
        attrs: {type: {default: "brontosaurus"}},
        inline: true,
        group: "inline",
        draggable: true,

        // These nodes are rendered as images with a `dino-type` attribute.
        // There are pictures for all dino types under /img/dino/.
        toDOM: node => ["img", {"dino-type": node.attrs.type,
                                src: "/img/dino/" + node.attrs.type + ".png",
                                title: node.attrs.type,
                                class: "dinosaur"}],
        // When parsing, such an image, if its type matches one of the known
        // types, is converted to a dino node.
        parseDOM: [{
          tag: "img[dino-type]",
          getAttrs: dom => {
            let type = dom.getAttribute("dino-type")
            return dinos.indexOf(type) > -1 ? {type} : false
          }
        }]
      }

      const {Schema, DOMParser} = require("prosemirror-model")
      const {schema} = require("prosemirror-schema-basic")

      const dinoSchema = new Schema({
        nodes: schema.spec.nodes.addBefore("image", "dino", dinoNodeSpec),
        marks: schema.spec.marks
      })

      let content = document.querySelector("#content")
      let startDoc = DOMParser.fromSchema(dinoSchema).parse(content)

      let dinoType = dinoSchema.nodes.dino

      function insertDino(type) {
        return function(state, dispatch) {
          let {$from} = state.selection, index = $from.index()
          if (!$from.parent.canReplaceWith(index, index, dinoType))
            return false
          if (dispatch)
            dispatch(state.tr.replaceSelectionWith(dinoType.create({type})))
          return true
        }
      }

      const {MenuItem} = require("prosemirror-menu")
      const {buildMenuItems} = require("prosemirror-example-setup")

      // Ask example-setup to build its basic menu
      let menu = buildMenuItems(dinoSchema)
      // Add a dino-inserting item for each type of dino
      dinos.forEach(name => menu.insertMenu.content.push(new MenuItem({
        title: "Insert " + name,
        label: name.charAt(0).toUpperCase() + name.slice(1),
        enable(state) { return insertDino(name)(state) },
        run: insertDino(name)
      })))

      const {EditorState} = require("prosemirror-state")
      const {EditorView} = require("prosemirror-view")
      const {exampleSetup} = require("prosemirror-example-setup")

      window.view = new EditorView(document.querySelector("#editor"), {
        state: EditorState.create({
          doc: startDoc,
          // Pass exampleSetup our schema and the menu we created
          plugins: exampleSetup({schema: dinoSchema, menuContent: menu.fullMenu})
        })
      })

    </script>
</body>
</html>
```

---

<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: [October 19, 2018, 7:56am UTC](https://discuss.prosemirror.net/t/keep-preexisting-custom-attributes-on-nodes/1581/6 "2018-10-19T07:56:24Z")

</div>

> [@bit-less](#):
>
> I’ve included a `data-some="thing"` attribute on the tyrannosaurus node in the pre-existing content that I want persisted when PM parses it.

I don’t see any attribute corresponding to this in your dino node spec. In ProseMirror, the document as represented by the schema is the _entire_ model of your document, so if something can’t be represented there, it’ll be dropped. You’ll need to add another attribute to the node that can store your extra information, and make sure that’s parsed and serialized properly in the node’s `toDOM` and `parseDOM` specs.
