CUTCODEDOWN
Minimalist Semantic Markup

Welcome Guest
Please Login or Register

If you have registered but not recieved your activation e-mail in a reasonable amount of time, please use our Contact Form for assistance. Include both your username and the e-mail you tried to register with.

Author Topic: Making a gallery what is wrong?  (Read 331 times)

Jason Knight

  • Administrator
  • Sr. Member
  • *****
  • Posts: 405
  • Karma: +62/-1
    • CutCodeDown -- Minimalist Semantic Markup
Re: Making a gallery what is wrong?
« Reply #15 on: 19 Aug 2020, 10:07:35 pm »
There are a lot of ways you can handle this if you think about the structure. For example, all the anchors you want to add your lightbox script to are inside #gallery, hence:

Code: [Select]
var
  gallery = document.getElementById('gallery'),
  anchors = gallery.getElementsByTagName('a');

In newer scripting -- aka if you don't care about IE 8/earlier -- you can use querySelectorAll to hook them using selectors just as you would in CSS.

Code: [Select]
var
  anchors = document.querySelectorAll('#gallery a');

VERY powerful, but beware that on larger DOM targets it can be quite slow compared to getting the ID and then the anchors of that parent element.

Another approach which can be a bit of code but often runs faster is to "Walk the DOM". DOM walking is the process of grabbing a parent element and then using firstElementChild and nextElementSibling to literally "walk across" the document nodes.

If we were to walk all the LI, we know that the anchor is the LI's first-child, thus your attach could be written something like this:

Code: [Select]
var
gallery = document.getElementById('gallery'),
li = gallery.firstElementChild;

if (li) do {
li.firstElementChild.addEventListener('click', lightBoxClickEvent, false);
} while (li = li.nextElementSibling);

Where lightBoxClickEvent is your event handler callback function. Because we walk the DOM instead of gathering up all the elements first, this would actually run faster, and it uses less memory because we aren't creating Arrays or NodeLists.

"walking the DOM" is a tricky thing to understand until you understand how your HTML elements directly correspond to Node objects, and how those various Node point at each-other with firstChild, lastChild, nextSibling, previousSibling, parentNode, and the various "element" equivalents like firstElementChild and nextElementSibling. There's no such thing as parentElementNode since only elements can have child nodes. If you're in a child, its parent must be an ElementNode.

I think I was lucky as by the time I learned HTML and JavaScript, I was already familiar with pointered lists, and more specifically "tree" structures that rely on pointers. That's all those various reference properties of a Node are, pointers. They point at the element (if any) that has said relationship. Years of programming btree (binary tree) sorts made me very familiar with how that works long before JavaScript even existed.

I can't imagine how hard it is to grasp said structure without that background.

In a LOT of cases where people do complex querySelectorAll style code -- such as that encouraged by mental huffing midgetry like jQuery -- would be better served using less memory and executing faster if people would just take the DOM for a walk.

But it often seems like a lot of people talk about "DOM Manipulation" when what they are doing is nothing of the sort, and refuse to leverage the DOM in an effective manner. In fact it oft feels like there's an irrational fear of the DOM, as if she's gonna get up off the floor, rip off the leash, and start chasing you with a whip.

That was a joke.
« Last Edit: 19 Aug 2020, 10:12:34 pm by Jason Knight »
Sorrow hides well in your shell. A fellow man with hurt to spare.
Dear one, here I am to share the fear. An act of kindness, without an amen.
Come in, the fire's warm. Burn the rope and dance some more.

JesseWillWreckYa

  • Junior Member
  • *
  • Posts: 9
  • Karma: +4/-0
  • Call me an idiot, I'm going back there...
Re: Making a gallery what is wrong?
« Reply #16 on: 19 Aug 2020, 10:19:35 pm »
Wait if querySelectorAll exists why does jQuery waste time with its dollar sign method?

Also can you explain this:

Code: [Select]
if (li) do {
li.firstElementChild.addEventListener('click', lightBoxClickEvent, false);
} while (li = li.nextElementSibling);

do, then while? I havent seen that before I thought while had to go first. Also why the if if you just got the elements.

The first code also does getElementsByClassName on the element you got by id. I thought that only worked on document. I just checked MDN as you often suggest and sure enough its a method of Node and not document. Document inherits from Node. So when you do that it is only returning the ones inside div.gallery and not all of them? Thats handy! Why do I see so much code where people do all of them off document and then loop through them looking for classes, data or checking the parent?
Thought I knew enough. Now I have to relearn it all.

Jason Knight

  • Administrator
  • Sr. Member
  • *****
  • Posts: 405
  • Karma: +62/-1
    • CutCodeDown -- Minimalist Semantic Markup
Re: Making a gallery what is wrong?
« Reply #17 on: 19 Aug 2020, 10:40:28 pm »
Wait if querySelectorAll exists why does jQuery waste time with its dollar sign method?
I know normally you'd expect a big long rant about how stupid jQuery is, but in this case it's not -- well, not entirely -- their fault. Simple fact is that querySelectorAll didn't exist in JavaScript when jQuery was originally created. In terms of browser support it does not exist in IE 7 or earlier, and when jQ was new, support back to at least IE6 was still considered "essential".

Sadly their use of it for EVERYTHING is part of what makes jQ such an inefficient and outdated mess. Even when new it was pretty pointless, but like a lot of things it has aged like milk. See all the things that 15 years ago REQUIRED JavaScript to be done that as of about ten years ago we could use CSS for.

Also can you explain this:
do/while is a less used but important construct to know. Well, it's less used in C syntax languages because C programmers think about almost every problem backwards.

In many languages starting the loop and then testing the condition is the norm. This is even true in assembler where it's more natural to put the test at the end of the loop, instead of pointlessly looping back to the test at the start that then on failure has to jump-out. In Wirth family languages -- Pascal, Modula, Ada -- they have the "repeat until" construct which is identical in functionality to do/while. In point of fact in older versions of said languages they had no equivalent of while {}.

Hence something like:

Code: [Select]
program testInput;
uses
  crt;

var
  ch : char;

begin
  writeln('Press <ESC> to Exit');
  repeat
    ch := readkey();
  until ch = #27;
end.

Being the norm for loop logic in such languages.

It can be extremely useful in cases like this where our operation to get the first element -- parent.firstElementChild -- does not match our loop to get the next element. You could write the same section as:

Code: [Select]
while (li) {
li.firstElementChild.addEventListener('click', lightBoxClickEvent, false);
li = li.nextElementSibling;
}

But it's not necessarily clearer and it can execute slower since it forces an extra return to the start of the while at the end. Whether or not it's actually slower would hinge more on how the JavaScript engine is implemented. I know some people prefer this approach, more power to them. Both are valid ways of coding it, use whichever you're more comfortable with.

Why do I see so much code where people do all of them off document and then loop through them looking for classes, data or checking the parent?
Ignorance.

As I often say, I don't meant that as an insult. Ignorant just means you don't know any better. You can fix ignorance.

In this case as JavaScript just has a LOT of functions, objects, and methods and it's hard to be sure you've learned all of them, or that you've learned to use any of them to their full potential. I still go to MDN regularly to look something up that I've forgotten the nitty gritty details of, and ended up going "huh, how about that!". This is more the case now that the ECMA is adding new stuff with such frequency, and browser makers -- or at least Quantum and Blink -- are keeping up with implementation.

This is often worse in languages that have truly massive function/object libraries like PHP. So often you'll see people brute force code things that PHP already has functions/methods to handle. It's not because these programmers are stupid, it's because they don't know everything PHP basically hands you on a silver plate.

A situation only exacerbated by the fact that so many developers learn by blind copypasta without comprehension. This is because so many people will hand you a snippet, then NOT explain it.

Part of why I put so much effort into my code breakdowns and explanations. Might make a few half-tweet TLDR mouth-breathers scream "AAAH WALL OF TEXT", but in my view you get no points for half-answers.
Sorrow hides well in your shell. A fellow man with hurt to spare.
Dear one, here I am to share the fear. An act of kindness, without an amen.
Come in, the fire's warm. Burn the rope and dance some more.

John_Betong

  • Jr. Member
  • **
  • Posts: 61
  • Karma: +3/-1
    • The Fastest Joke Site On The Web
« Last Edit: 22 Aug 2020, 11:43:12 pm by John_Betong »
Retired in the City of Angels where the weather suits my clothes

Jason Knight

  • Administrator
  • Sr. Member
  • *****
  • Posts: 405
  • Karma: +62/-1
    • CutCodeDown -- Minimalist Semantic Markup
Re: Making a gallery what is wrong?
« Reply #19 on: 22 Aug 2020, 12:35:24 pm »
https://images.app.goo.gl/RsBSmK1KE4MhQLpF8
Which is actually a really good point! It's about knowing when it's the right tool for the job and when it's not.

If the condition could be fatal, it's the wrong tool... If you KNOW the first case is always true (because you just set it up) do/while is the correct one to use, or if the first condition differs from later ones. But if an initial test is the same as the loop test, and it's possible the loop will not -- or more importantly should not -- be run, then hell yes, use conventional while () {}.

For example:

Code: [Select]
var
anchors = document.getElementsByTagName('a'),
i = 0;
while (a = anchors[i++]) {
a.addEventListener('click', clickOverride, false);
}

Would be a good approach if "for" didn't exist. (again, this is just an example, not something you'd do real world".

But let's say you have a database result in PHP where if there are results you want to loop them out into a table. A lot of people would write that as:

Code: [Select]
$stmt = $db->query('
SELECT *
FROM users
');

if ($stmt->rowCount()) {
echo '
<tr>';
while ($row = $stmt->fetch() {
foreach ($row as $data) echo '
<td>', $data, '</td>';
}
echo '
</tr>';
}

But what if you could eliminate the rowcount function? Well, you can!

Code: [Select]
$stmt = $db->query('
SELECT *
FROM users
');

if ($row = $stmt->fetch()) {
echo '
<tr>';
do {
foreach ($row as $data) echo '
<td>', $data, '</td>';
} while ($row = $stmt->fetch());
echo '
</tr>';
}

Which is how a "Wirth" programmer used to "repeat/until" would think of solving that problem. It's often handy in cases where things like rowcount doesn't even work -- Oracle for example -- to be able to sample if there are results or not. One of the easiest of which being to simply pull the first result to see if it fails.

It's also handy if the first row is in the type of data where you know the first one needs to be output differently.  Sometimes you need that first row before what's done inside the loop.

The key in all such cases being that you still have a safety "if' at the start, neatly avoiding "Coyote Logic".

But another example, take working with CSV where the first row is the column names.

Code: [Select]
if (($handle = fopen('test.csv', 'r')) !== FALSE) {

$dataRowCount = 0;

if ($row = fgetcsv($handle)) {

$columns = count($row);

echo '
<table id="test">
<caption>Test Data</caption>
<thead>
<tr>';

foreach ($row as $data) echo '
<th scope="col">', $data, '</th>';

echo '
</tr>
</thead><tbody>'

while ($row = fgetcsv($handle)) {


echo '
<tr>';

$i = 0;
$count = count($row);
if ($count > 0) {
echo '
<th scope="row"', (
$count == 1 ? ' colspan="' . $count . '"'
), '>', $row[$i++], '</th>';
while ($i < $count) echo '
<td>', $row[$i++], '</td>'
$dataRowCount++;
} else echo '
<td colspan="', $columns, '" class="error">No Data</td>';

echo '
<tr>';

} // while fgetcsv

echo '
</tbody><tfoot>
<tr>
<td colspan="', $columns, '">', $dataRowCount, '</td>
</tr>
</tfoot>
</table>';

} else echo '
<p class="error">No Records Found in test.csv</p>';

} else echo '
<p class="error">Unable to open test.csv</p>';

Whilst it doesn't use do/while, it does do the "fetch to test THEN loop" approach.

Not that in production I'd mix template with logic like that. Also warning, drive-by, may have typos

The big advantage of "test by fetch" being that you don't have to incorporate extra crap INSIDE the loop. A lot of people would use the row count and test for zero to determine if a TH or TD should be used. That makes your loops slower.


Sorrow hides well in your shell. A fellow man with hurt to spare.
Dear one, here I am to share the fear. An act of kindness, without an amen.
Come in, the fire's warm. Burn the rope and dance some more.

 

Advertisement