Saving a created element with multiple atttributes

I’m using javascript to create elements. I’m wanting to save the created elements with all of their attributes.

I’ve looked into JSON as well as outerhtml. It seems a json or even a regular object save key value pairs. Which is fine but there are more attributes.

I know I can save and create a json but when the page reloads or you return to the page, I can’t seem to figure out how to recreate all of the elements exactly as they were. Including there ids, class name, value, text content and other HTML markup.

These elements are created dynamically by users. So I wouldn’t know what to reference or how many times to reference it. If using json parse.

It seems you can add a function to at least an object which I could use to create the element but I don’t like this approach.

For example say you have a button with an Id of button, a class of my-button, text that says my button. How can I save this element in the database and recreate it exactly as is when the page is loaded again.

When they are dynamically created by the user, you must record everything that the user has done for the purpose of recreation.

Otherwise you will be needing to save hundreds and sometimes thousands of pieces of information for each and every element, which is not a viable solution.

1 Like

Do you have a solution for this? How do you record everything the user has done?

If I figure out how to track/record the actions the user takes, how then do I re-create the same page with the same elements?

Can you provide any additional details or a resource to where I might find additional information?

document fragment could be your answer
I use this to copy elements when dragging them into another element

const docFragment = str => {
    let frag = document.createDocumentFragment();
    let temp = document.createElement('div');
    temp.innerHTML = str;
    while(temp.firstChild) {
        frag.appendChild(temp.firstChild);
    }
    return frag;
}

let div = docFragment(divStr);
tgt.appendChild(div);

divStr is the outerHTML of the element that was being dropped.
You could use localstforage to save the data.
The outerHTML is already a string, so it can be saved into localStorage.
The localStorage persists in the users browser so will only have their own data
Now I haven’t tried this but you should be able to research it by yourself as the api documentation is well written.

2 Likes

I’ll take a closer look. Thanks for sharing.

Do you know if you can save the document Fragment into a database without converting its syntax?

This might be the answer if I can just save the entire document fragment as-is with each element and then append it back to the DOM on new page reloads or visits.

To clarify json has to be converting using stringify.

Can I just insert the created elements into document fragment and then save the document fragment as is without having to use something like stringify?

Hope that makes sense.

An example of what you want to save would be a help.
I am assuming that when a customer logs in you want to recreate his view of the page to what was showing when they logged off.
Is this correct?

I’m not sure if that is possible, and it doesn’t sound very practical to me.

For instance here is simple fragment with a heading. You can copy this into your browser console and see the output.

const fragment = new DocumentFragment()
const heading = document.createElement('h1')
heading.textContent = 'Read all about it!'
fragment.appendChild(heading)

console.dir(fragment)

This is just a small portion of that fragment logged out

baseURI: "chrome://new-tab-page/"
childElementCount: 1
childNodes: NodeList(1)
0: h1
length: 1
[[Prototype]]: NodeList
  entries: ƒ entries()
  forEach: ƒ forEach()
  item: ƒ item()
  keys: ƒ keys()
  length: (...)
  values: ƒ values()
  constructor: ƒ NodeList()
  Symbol(Symbol.iterator): ƒ values()
  Symbol(Symbol.toStringTag): "NodeList"
  get length: ƒ length()
  [[Prototype]]: Object
children: HTMLCollection(1)
  0: h1
  length: 1
  [[Prototype]]: HTMLCollection
    item: ƒ item()
    length: (...)
    namedItem: ƒ namedItem()
    constructor: ƒ HTMLCollection()
    Symbol(Symbol.iterator): ƒ values()
    Symbol(Symbol.toStringTag): "HTMLCollection"
    get length: ƒ length()
    [[Prototype]]: Object
...

Well it certainly rules out json, as json only copies array, objects and primitives values, no functions e.g. entries, forEach etc.

You then have built in prototypes NodeLists, HTMLCollection and symbols, getters and setters.

I am not sure it would even be possible to store this in a database.

That is as opposed to storing maybe a string template and parsing it.

'<h1>Read all about it!</h1>'

Alternative?
Another thought, if you want to stick to explicitly creating elements, is to possibly represent the process in object form.

If you look at React’s createElement it maybe gives us an idea.

React.createElement(
  "div",
  { className: "red" },
  React.createElement("div", { className: "blue" }) <-- child element
)

You could store a nested object, a basic representation of your Dom elements and then loop through it later creating your actual DOM elements.

Store just the data instead?
This is what I would go with. I know I sound like a broken record here, but then on retrieval I would feed that data into html template strings.

I would save that as a single string comprising the CSS for the class, a delimiter, and the outerHTML.

I can’t see your point. You have logged the browser created object used by the DOM not the html. You do not need to save that DOM object as the browser generates it as it creates the DOM. Think of the html file, the browser will generate a similar object for every tag in the file and include the objects in the DOM. You only need to save the html, not the DOM object.
Until we see a sample of what needs to be saved we are flying blind.
Saving html to me seems weird. Normally one just saves data not the presentation of the data.

@dennisjn

Was responding to this, maybe should have been clearer.

You’ve lost me there, I’m sorry. What html are you referring to? Could you elaborate?

So what are views in the MVC pattern? ejs, handlerbars etc. or even React components.

Yes I agree with you data should be separate and that is what should be going to the database or storage.

Could be me who has got the wrong end of the stick here, wouldn’t be the first time, but I am confused with your response.

Saving HTML (including CSS) does not seem at all weird to me. There’s nothing wrong with saving presentational inforrmation: in fact presentational information is data :grinning:. If you don’t store the presentational information you want to keep, how are you gong to avoid losing it?

Whether you save the data (including presentational information) as HTML or JSON it’s essentially serialisation of data. When you read the data it’s much easier to display it on a web page if it’s stored as HTML.

1 Like

Yes, that’s correct.

So a user logs in creates various elements.

User logs out and logs back in, the same elements are still there.

I still will store values into json but that will be used for when I just need the value and already know the keys.

As far as an example, literally just something simple like saving a button tag, a button class for that button, an id that increments itself with each new button, and text that say my button.

I figure it I knew how to properly store this and recreate it, I can do that for other elements that are created.

I have opted out of use template literals for this project. One I’m new to javascript and had already written 1000 lines of js before you made the suggestion to use template literals.

1 Like

How would I save it as a string and the add the string back to the page? Just save the string into a database table and add it back?

So you are allowing a user to create elements and render them.
How are you going to prevent them from inserting script elements which could do anything.
Fun things like making all text white on a white background.

The elements are predefined.

How exactly are you suggesting saving it as a string?

document.documentElement.innerHTML

Save that and then add it back?

How would you add back the id? Maybe I’m missing something but this doesn’t have an id or a class.

So how would you make sure the correct id is assigned to this element if you have multiple h1’s?

To my knowledge you can save the a key value pair but there’s on key and one value. So if the key is h1 and the value is read all about it, how would I add the correct id to this element. You mentioned checking the data.

See it seems saving as a string is the only solution. Unless I’m missing something.

@cssissimple

No you are not missing anything, it was just to illustrate the big difference in complexity between a simple string and it’s equivalent Dom element.

As you know I would go with my template string approach, I know you’re going down another path :slight_smile:

// template
const heading = function({id, className, text}) {
    return `<h1 id='${id}' class='${className}'>${text}</h1>`
}

and the data to store

{ id: 'myHeading', className: 'heading', text: 'Read all about it!' }

Something like that.

Here is a very basic demonstration:

Instead of reading from an actual database, I have assumed that the following string is read from a database:

.btn{background-color:cyan;}\t&lt;button class='btn'&gt;My Button&lt;/button&gt;

The \t is a tab character that serves as a delimiter to be used to separate the CSS and HTML element parts. Some other character or sequence of characters could be used instead of tab provided it cannot appear in the HTML/CSS

It’s unconventional placing a style element in this way but it works!

You need to ensure that the button’s class name cannot be the same as a class name used elsewhere.