Home > Software design >  Complex dynamic Section Separation with HTML collections
Complex dynamic Section Separation with HTML collections

Time:03-01

I'm working on a registration form with pagination (multi step form) using js and bootstrap which has a structure similar to SNIPPET 1.

I have added a card, card-header, card-body and card-footer to my form using the JS code below and changes the structure to SNIPPET 2.

However, I think there are better ways of doing this and I want to be able to do a complex dynamic section separation. So what I'm trying to figure out is the following:

  1. For each part of the card (header,body,footer) there are elements from the form which i want to separate. But instead of giving hard-values to select the needed elements (form.children[1-5] etc), I want to be able to select parts of the array (from start to element with id="xxx" or from id="xxx" to id="zzz").
  2. I tried using slice() but it doesn't work let form_header = form.slice(0,11);. It gives the following error: Uncaught TypeError: form.slice is not a function
  3. Dynamic: In the future I want to use this process for another form which might have more sections and inputs instead of having the same structure.
<form>
    <div id="notifications">
    <fieldset id="title">...
    <input>...
    <input>...
    <fieldset id="section1">...
    <script>...
    <input>...
    <input>...
    <fieldset id="section2">...
    <input>...
    <input>...
    <script>...
    <style>...
    <div>
        <button type="submit">...
    </div>
</form>
<div >
    <form>
        <div id="notifications">
        
        <div >
            <fieldset id="title">...
        </div>
        
        <div >
            <input>...
            <input>...
            <fieldset id="section1">...
            <script>...
            <input>...
            <input>...
            <fieldset id="section2">...
            <input>...
            <input>...
        </div>
        
        <div >
            <script>...
            <style>...
            <div>
                <button type="submit">...
            </div>
        </div>
    </form>
</div>
let form = document.getElementById("geodirectory-add-post");
//HAS 10 ELEMENTS
let form_header = [form.children[0], form.children[1], form.children[2], form.children[3]];     
//HAS 70 ELEMENTS
let form_body = [form.children[50], form.children[51], form.children[52], form.children[53]];
//HAS 20 ELEMENTS
let form_footer = [form.children[56], form.children[57], form.children[58], form.children[59]];


var card = document.createElement("div");
card.className = "card";

//Crate Card Header
var card_header = document.createElement("h1");
card_header.className = "card-header";

//Create Card Body
var card_body = document.createElement("div");
card_body.className = "card-body";
card_body.style.maxHeight = "400px";
card_body.style.overflowY= "auto";

var card_footer = document.createElement("div");
card_footer.className = "card-footer text-muted";



for(var i=0; i<form_header.length; i  ){
    card_header.appendChild(form_header[i]);
}
for(var i=0; i<form_body.length; i  ){
    card_body.appendChild(form_body[i]);
}
for(var i=0; i<form_footer.length; i  ){
    card_footer.appendChild(form_footer[i]);
}

// insert wrapper before el in the DOM tree
form.parentNode.insertBefore(card, form);

// move el into wrapper
card.appendChild(form);
form.prepend(card_header);
card_header.after(card_body);
card_body.after(card_footer);

This is how I have done it. However when I try using slide() it gives me a Node error

CodePudding user response:

you could try this approach, i think you can modify it to achieve something more complex

// helper function to wrap single element
var wrap = function(el, wrapper) {
    el.parentNode.insertBefore(wrapper, el);
    wrapper.appendChild(el);
}

// helper function to wrap multiple elements
var wrapAll = function(ary, wrapper) {
    if (ary && ary.length) {
        ary[0].parentNode.insertBefore(wrapper, ary[0]);
        for (var i in ary) {
            wrapper.appendChild(ary[i]);
        }
    }
}

// map sections
var sectionsMap = {
    'title': 'header',
    'section1': 'body',
    'section2': 'footer'
};
// array to store all newly created section: card-header, card-body, card-footer 
var sectionsArr = [];

// create the card main container
var card = document.createElement('div');
card.className = 'card';

// loop mapped stuff
for (const prop in sectionsMap) {
    if (sectionsMap.hasOwnProperty(prop)) {

        // create each section card-header, card-body, card-footer 
        let new_section = document.createElement('div');
        new_section.className = 'card-'   sectionsMap[prop];
      
        // add section to array
        sectionsArr.push(new_section);

        let old_section = document.querySelector('#'   prop);

        wrap(old_section, new_section);
    }
}

// wrap all new section with the main card element
wrapAll(sectionsArr, card);
  • PS: i guess you are receiving an error because you are getting the form chields instead of fieldset chields?

bonus, if you want to collect all inputs of each section and create another form

let bootstrap_form = '<form><div >$1</div><div >$2</div><div >$3</div></form>';
let sections = [];

let fieldsets = document.querySelectorAll("#geodirectory-add-post > fieldset");
fieldsets.forEach((fieldset, fIndex) => {
    sections[fIndex] = [];
    let inputs = fieldset.querySelectorAll("input");
    inputs.forEach((input, iIndex) => {
        sections[fIndex].push(input.outerHTML);
    });
});

bootstrap_form = bootstrap_form
    .replace(/\$1/g, sections[0].join("\n")) // header
    .replace(/\$2/g, sections[1].join("\n")) // body
    .replace(/\$3/g, sections[2].join("\n")); // footer

console.log(bootstrap_form);
  • Related