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:
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").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
<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 class="card">
<form>
<div id="notifications">
<div class="card-header">
<fieldset id="title">...
</div>
<div class="card-body">
<input>...
<input>...
<fieldset id="section1">...
<script>...
<input>...
<input>...
<fieldset id="section2">...
<input>...
<input>...
</div>
<div class="card-footer">
<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
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);
bonus, if you want to collect all inputs of each section and create another form
let bootstrap_form = '<form><div class="card-header">$1</div><div class="card-body">$2</div><div class="card-footer">$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);