Why?
- The 'document.querySelector()' has many downfalls.
- There are many articles on the web to read more about it!
- As I work the Javascript OOP way, I don't need it.
What I do instead and what I want to share here is this:
Connecting to the DOM directly.
What I do is making use of already available object keys in the dom tree:
- document.activeElement (in callbacks and aside of event.target)
- firstElementChild
- lastElementChild
- children
- length
- nextElementSibling
- parentElement
- previousElementSibling
Some Wisdom first:
If a parent element has just one child element.
The values of 'firstElementChild' and 'lastElementChild' are equal.
This means that 'lastElementChild' can be used too!
☛ Bad practice, because if there is a new element to be added at a later stage then things are broken.
☛ Good practice is just to stick to 'firstElementChild' and leave 'lastElementChild' free for future use.
How do I do that?
It's about creating a central point to work from.
Next is to create the objects out of them.
For this I use a Map() based function, called 'createObjects('obj_name',{})'.
Working it out:
First a reflection of my used html body structure:
<body>
<div class='wrap container display-flex relative'>
<section class='top relative'>
<header class='relative'>
<h3 class='relative'>example heading.</h3>
</header>
</section>
<main class='relative'>
<main-content class='workbench-ctn absolute'>
<content-item class='wb-content relative display-flex'>
Dynamic content
</content-item>
</main-content>
</main>
<div class='controls-ctn relative display-flex'>
<aside class='sidebar-ctrl top relative display-flex'>
Some other elements
</aside><!--sidebar-ctrl top-->
<aside class='open-close-block absolute'>
<details id='toolbar_toggle' class='toggle toolbar relative' open>
<summary class='tb caret-up-uc relative' title='close toolbar'></summary>
</details><!--toggle toolbar -->\
<details id='menubar_toggle' class='toggle menubar relative' open>\
<summary class='mb caret-left-uc relative' title='close menubar'></summary>
</details><!-- toggle menubar -->
</aside><!--open-close-block -->
<aside class='sidebar-ctrl left relative display-flex'>
Other elements, dynamically added or used for callbacks
</aside><!--sidebar-ctrl left-->
</div><!-- controls-ctn -->
</div><!--div.wrap.container-->
</body>
Then a file that I've created for this and is called 'get_dom_objects.js'.
There are two functions in this file:
- getDomObjects() (for elements that have been created already)
- getDomObjectsExtended(obj_args) (for elements that not have been created yet or elements that will be used at a later stage).
import * as FT from './functions.js';
export async function getDomObjects(){
const get_objects = await FT.createObjects('base_obj',{
//1. Obtaining the document.body
body_elem: document.body,
//other objects
});
//2. Creating a const for further use.
const {body_elem} = get_objects;
//3. Obtaining the very first element after the body
/**
* It's easy, each body element has a firstElementChild
and what that is?
* As I'm using the given example here,
it is the _'div.container'_ element.
*/
get_objects.wrap_ctn = body.firstElementChild;
//4. For this I create another const and also for
further use.
const {wrap_ctn} = get_objects;
//5.
/**
* For getting the elements after the 'div.container',
there are different ways to do that.
* A. by using (not recommended!)
'first/last' - 'ElementChild' &
'next/previous' - 'ElementSibling'.
* B. by using (recommended) 'children.length'.
*/
// This way
if(wrap_ctn.children.length > 0){
const wrap_children = wrap_ctn.children;
get_objects.top_ctn = wrap_children[0];
get_objects.main_elem = wrap_children[1];
}
//6. Creating consts from that.
const {top_ctn,main_elem} = get_objects;
(I skipp the 'top_ctn' as there is no need for)
//7. Getting the elements inside the 'main_elem'
get_objects.workbench_ctn = main_elem.firstElementChild;
get_objects.controlls_ctn = main_elem.lastElementChild;
return get_objects;
});
Now I have all the objects that I'm going to use in getDomObjectsExtended(obj_args) function.
export async function getDomObjectsExtended(obj_args){
const {body_elem,wrap_ctn,top_ctn,main_elem,
workbench_ctn,controlls_ctn} = obj_args;
const get_objects = await FT.createObjects(('ext_obj',{
//1. Including the previously created objects
body_elem,main_elem,workbench_ctn,
controlls_ctn,top_ctn,
});
//2. Moving on with creating the objects!
get_objects.wb_content = workbench_ctn.firstElementChild;
if(controlls_ctn.children.length > 0){
const controls = controlls_ctn.children;
get_objects.ctn_top = controls[0];
get_objects.open_close_block = controls[1];
get_objects.ctn_left = controls[2];
}
const {open_close_block} = get_objects;
get_objects.toggles = {
//toolbar_toggle
tb_toggle: open_close_block.firstElementChild,
//menubar_toggle
mb_toggle: open_close_block.lastElementChild,
};
return get_objects;
};
Using those created objects:
In my modules folder I have a file called modules_collect.js, this contains one function modulesCollect() and this is the file passed to my index.js.\
Within that file:
- I Collect all the imports from the sub folders.
- I'm passing the objects to the classes & functions within those sub folders. #### The steps:
☛ In 'index.js' this:
const dom_elems = await getDomObjects();
await modulesCollect(dom_elems);
☛ In 'modulesCollect' this:
export const modulesCollect = async (obj_args)=>{
const obj_args_ext = await getDomObjectsExtended(obj_args);
//Passing obj_args_ext to the _classes_ and _functions_
//This could be as a whole or partially {destructed}
};
Freedom for all:
It's about of how I do things.
If you're open to what I've presented, go for it!
If you're happy with the way you work already, stick to it!
Top comments (0)