How I talk with the DOM?

posted Originally published at aadswebdesign.github.io 4 min read

Intro.

In the past I made use of the "document.querySelector(All) " all over the place and what often resulted in "undefined" errors.

To be honest, it took me a long time to find a solution for this.

  • At first I began with creating a function for the "document.querySelector(All) (that I to date still use!)"
export async function elQuery(...args){
  const [elem,el_all=false,el_parent] = args;
  let el;
  if(true === el_all){
    if(el_parent) el = el_parent.querySelectorAll(elem);
    else el = document.querySelectorAll(elem);
  }else{
    if(el_parent) el = el_parent.querySelector(elem);
    else el = document.querySelector(elem);
  }
  return await el;
}
  • Swapping function calls up and down within my index.js.

  • Using "setTimeout()" and so on!

There were some improvements with this steps but it was still struggling to get my queries right.

A Quantum Leap forward.

Finally I found a way to get this done by using Map() and that is what I want to share with you.

First this.

I use javascript with a module approach, working with a folder/file structure and a bunch of custom (reusable) functions, aside of that I use classes too.

The given example here is a reflection of that!

1 structure:
assets/
  scripts/
    factory/
     dom_objects.js
     functions.js
     generals.js
     handlers.js
    modules/
     actions/
      set_actions_1.js
      set_actions_2.js
      set_default_action.js
      get_actions.js
     callbacks/
      sub_callbacks_1.js
      sub_callbacks_2.js
     defaults/
      set_defaults.js
     mdl_factory/
      //module specific files
     templates/
      sub_templates_1.js
      sub_templates_2.js

    index.js
2 dom_objects.js:

That's the file where I collect my dom objects and it holds two functions, called getBaseObjects and getExtendedObjects.

// assets/scripts/factory/dom_objects.js */
import * as FT from './functions.js';
export const getBaseObjects = async()=>{
  const map = new Map([['base_objects',{
    vvp: window.visualViewport,
    location_base: window.location.origin,
    body: document.body,
    wrap_ctn: await FT.elQuery('div.wrap.container', false, self.body),
    main_elem: await FT.elQuery('main', false, self.wrap_ctn), 
    actions_block: await FT.elQuery('.actions-block_ctn',false,self.wrap_ctn),
     //other base objects
  }]]);
  return map.get('base_objects');
}
 
export const getExtendedObjects = async (base_dom)=>{
  const {vvp,location_base,body,main_elem,actions_block} = base_dom;
  const map = new Map([['ext_objects',{
    vvp,location_base,body,main_elem,actions_block,
    main_sub_ctn: await FT.elQuery('div.main_sub_ctn',false,self.main_elem),
    //option 1 (not recommended), is just to show that you can group objects
    action_items:{
      action_item_1: await FT.elQuery('.action-item-1',false,self.actions_block),
      action_item_2: await FT.elQuery('.action-item-2',false,self.actions_block),
      action_item_3: await FT.elQuery('.action-item-3',false,self.actions_block),
      action_item_4: await FT.elQuery('.action-item-4',false,self.actions_block),
    },
    //option 2 (if your actions_block isn't going to change)
    action_items: await FT.elQuery('.action-item',true,self.actions_block),
    //option 3 (if your actions_block has live events and is going to change)
    action_items: await FT.getClassHelper('action-item',self.actions_block), 
    // uses 'getElementsByClassName'
    //-----------------------------
    //other ext objects
  }]]);
  return map.get('ext_objects');
}
explanation:

I have created two functions here but for a reason.

The getBaseObjects have values that are available as soon as the website loads and will never give an undefined error:

//assets/scripts/index.js
 import {getBaseObjects} from './factory/dom_objects.js';
 import {getActions} from './modules/actions/get_actions.js';
 (async ()=>{
   const base_elems = await getBaseObjects();
   await getActions(base_elems);
   //sure, there are more functions and classes that I call here.
 })();
The steps here:
  1. 'getBaseObjects' is imported from 'dom_objects.js'.
  2. this function is called and applied to a const 'base_elems'.

  3. 'getActions' is called from 'get_actions.js'.

  4. the values of step2 are passed as an arg to the 'getActions(base_elems)' function.

From here, the objects{keys:values} of 'base_elems' are available in the getActions function.

The getExtendedObjects might have values that has not been created yet and could give an undefined error if so?

/** modules/actions/get_actions.js */
import {getExtendedObjects} from './../../factory/dom_objects.js';
import * as SA1 from './set_actions_1.js';
export const getActions = async(base_elems)=>{
 const ext_elems = await getExtendedObjects(base_elems);
 await setActions1(ext_elems);
}
The steps here:
  1. 'getExtendedObjects' is imported from 'dom_objects.js'.
  2. SA1.setActions1 is imported from 'set_actions_1.js'.
  3. function 'getActions' has been created together with a param 'base_elems'.
  4. within that function, 'getExtendedObjects' is called and args 'base_elems' are applied to it. Then this function is applied to a const 'ext_elems'.
  5. 'SA1.setActions1' is called and has args 'ext_elems' applied to it.

From here all objects are available when called.

In a real situation.

In a real situation you only want the objects you need for a certain part of your webpage.

Let say:

  • 'header' related objects for in the header.
  • 'main' related objects for in the main.
  • 'footer' related objects for in the footer.

The best way to do that is to create nested object groups in your Map().

const map = new Map([['ext_objects',{
  header_objects:{
    //header objects here
  },
  main_objects:{
    //main objects here
  },
  footer_objects:{
    //footer objects here
  },
})    

Then in your 'getActions', you are doing this:

export const getActions = async(base_elems)=>{
  const ext_elems = await getExtendedObjects(base_elems);
  //note: this is called 'destructuring', for objects it is {} and for arrays []
  const {header_objects,main_objects,footer_objects} = ext_elems;
  await headerAction(header_objects);
  await mainAction(main_objects);
  await footerAction(foot_objects);
}

Now, each action get it's own objects.

Enough for now!
There is way more to say about it but I think this is enough for now!

Cheers!

0 votes
0 votes

More Posts

How I load javascript?

Aad Pouw - Sep 7

What is Javascript and How It Powers Modern Websites

Sangy K - Aug 12

How I Process things?

Aad Pouw - Aug 31

Learning Object Destructuring in JavaScript

ypdev19 - Oct 4

I Tested the Top AI Models to Build the Same App — Here are the Shocking Results!

Andrew Baisden - Feb 12
chevron_left