Explanation:
As I'm working on the development
of a contentEditable based editor,
I make use of the dataset
attribute intensively.
Mostly I work with the
DOM tree directly but there are situations that I have to collect the elements.
For that I use
document.getElementsByTagname (this wrapped in a method,called 'getTagNames()').
It's okay and I get things
done with it. Just sometimes it would be more handy if could collect a bunch of elements with different tag names, at once!. Sure I can use document.getElementsByClassname but that also has its pitfalls.
Therefor I began
to think, why is there not
something like
'*.getElementsByDatasetNameValue'?
Because then you can give a group of elements a related dataset name/value and collect them with one call, regardless of their 'tagnames'.
As it kept me busy, I gave it a closer look.
I began with reading about those built-inn HTML methods and how they are built first. For this I had a look at whatwg.org#concept-getelementsbytagname / 4.5. Interface Document. Interesting to get some idea of how they are built but that's it.
Then I asked myself, can I create something like that with js and I gave it a try?
The steps:
One:
I created a class and
a related export function for it 'GetElemsByDataset \ getElemsByDataset' \
"I have kept 'NameValue' left out of it because this is clear and long enough."
Two:
☛ Find a way to
collect the elements for it first and this I did by creating this method.
/*
* @action: collecting the tags.
* @notice: It is possible to omit a parent element
but not recommended because that could become a huge list of elements.
*/
get_tag_names = async (...args) => {
const [prt_el = null, log = false] = args
let el;
if(prt_el !== null)
el = prt_el.getElementsByTagName('*');
else
el = document.getElementsByTagName('*');
if(log === true)
console.log('getTagNames(*)',el);
return el;
}
Three:
☛ Creating from this obtained values a 'for of loop', and collect the elements based on 'dataset names and values' within the class constructor.
constructor(...args){
const [prt_el,data_name, data_val,log = false] = args;
this.#dn = data_name;
this.#dv = data_val ?? null;
this.#prt_el = prt_el ?? null;
this.#get_tags = [];
(async()=> {
if(this.#prt_el !== null){
/*
* @action: collecting the tags.
* @description: this method is using the '*' to collect all the available elements from the parent element and are placed in a 'for of'.
*/
const tags = await this.get_tag_names(this.#prt_el,log);
for(const tag of this.unique_array(tags)){
/*
* @action: collecting the elements based on a dataset 'name' or 'name/value pair'.
*/
if(tag.dataset[this.#dn] !== undefined){
if(this.#dv === null){
tag.dataset[this.#dn];
this.#get_tags.push(tag);
}else if(tag.dataset[this.#dn] === this.#dv){
tag.dataset[this.#dn] = this.#dv;
this.#get_tags.push(tag);
}
}
}
const gt = this.unique_array(this.#get_tags);
if(log === true)
console.log('elems: ', gt );
}
})();
}
How to use:
- just copy/paste it, place it in your script folder and use 'import' to connect to it (how you do that is up to you).
- it accepts four arguments.
- parent_el: ☛ This is the nearest element that holds the sub elements with the desired dataset names.
- data_name: ☛ Here you pass the dataset name like this 'fooBar' but not 'data-foo-bar' or 'foo-bar'!
- data_val: ☛ Here you can pass a dataset value! This is optional.
- log: ☛ standard value is 'false', when set to true it shows the relevant data in your dev tools.
Example/Use Case:
☛ This is a class of a new project that I just started last Wednessday. This class uses also some other methods but the focus here is getting the elements by dataset 'name/value'.
/*
* @action: creates & collects objects for later use elsewhere.
* @description:
*/
constructor(obj_args){
const {get_prts} = obj_args;
const create_obj = MH.createObjects;
const remove_obj = MH.removeObjects;
const ctb = MH.createTreeBlock;
const gb = MH.getBoundings;
//where I focus on.
const gebd = MH.getElemsByDataset;
(async()=> {
const dom_data = await create_obj('dom_obj',{...obj_args});
await remove_obj(['grant_data','get_prts'],dom_data);
if(get_prts.length > 0){
for(const prt_ctn of get_prts){
//where the magic happens!
this.layers = await gebd(prt_ctn,'topLayer');
if(this.layers.length > 0){
const layers = this.layers;
for(const layer of layers){
const prefs = layer.dataset.prefix;
//another magical method but not the focus here!
await ctb(gb,layer,dom_data,`${prefs}_ctn_data`,prefs,3,true);
}
await DE.dataTopLayer(dom_data);
await DE.dataMainLayer(dom_data);
await DE.dataBtmLayer(dom_data);
}
}
}
})();
console.table({'DTLS': obj_args});
}
This results in:
(3) ➜ top_ctn
<section class="relative" data-top-layer="df-top-ctn" data-prefix="top">
(3) ➜ main_ctn
<main class="relative" role="presentation" data-top-layer="df-main-ctn" data-prefix="main">
(3) ➜ btm_ctn
<section data-top-layer="df-bottom-ctn" data-prefix="btm">
The goal of this method!
top_ctn_data
Object { top_ctn: section.relative, top_ctn_dims: DOMRect }
main_ctn_data
Object { main_ctn: main.relative, main_ctn_dims: DOMRect }
btm_ctn_data
Object { btm_ctn: section, btm_ctn_dims: DOMRect }
Top comments (0)