MozillaZine

JavaScript question

Discuss how to use and promote Web standards with the Mozilla Gecko engine.
Bethrezen
 
Posts: 390
Joined: September 13th, 2003, 11:56 am

Post Posted May 8th, 2018, 7:56 pm

I'd argue that I gave you the tools to figure it out by putting a description of what you could do in a comment. What I didn't do is spell it out. ;)


Perhaps the issue with that though is that you are assuming a grater level of knowledge than I actually possess currently, unfortunately JavaScript isn’t something I covered extensively in college so I have only the most basic of knowledge / understanding of the language, so much so it's probably better to just assume that I have no idea what you are talking about because the chances are I probably don't.

You could do that, but personally I'd be more inclined to turn it around for simplicity.

The easiest but not necessarily best way to get your example to work is this:

Code: Select all
var attribute = target.getAttribute('data-name') ? target.getAttribute('data-name') : target.parentNode.getAttribute('data-name');


[Edit: look up ternary operator if you don't know that notation yet. See here. It's just an alternative way of writing if/else.]

If you don't know the specific markup you'll encounter you could just keep on going up the tree, e.g. like this.

You could also do the reverse in the script init step (i.e. take the data-* attribute from the TR and stick it in child TDs), but in that case I'd say you should just do it while generating the markup.


Question since I'm already getting the event target and the data attribute of that target would a simple loop work for this purpose, something like this perhaps ?

Code: Select all
function hoveron(event)
{
  var target = event.target;
  var attribute = target.getAttribute('data-name');

  var cells = document.querySelector("td");
  for (i = 0; i < cells.length; i++)
  {
    cells[i].setAttribute(data-name, attribute)
  }

  var id = document.getElementById(attribute);
  id.style.cssText = "border:1px dashed red;";
}


i know its maybe not the best way but at least it is something that i sort of understand i can follow what its doing unlike that ternary operator stuff the logic of which isn't making a whole lot of sense to me.

I mean maybe this is simply another case of me missing something that is obvious to those that are more knowledgable about this stuff but I'm not really seeing how using that ternary operator stuff would actually accomplish what I'm trying to do since this isn't one of them times when i need to use an if() or a boolean (true or false)

I simply need to get the value from the parent row and then apply it to the children of that row so that i don't get the id is null error when i hover on the TDs.

Frenzie

User avatar
 
Posts: 2134
Joined: May 5th, 2004, 10:40 am
Location: Belgium

Post Posted May 9th, 2018, 7:20 am

Perhaps the issue with that though is that you are assuming a grater level of knowledge than I actually possess currently, unfortunately JavaScript isn’t something I covered extensively in college so I have only the most basic of knowledge / understanding of the language, so much so it's probably better to just assume that I have no idea what you are talking about because the chances are I probably don't.

Unless you don't know how to use a search engine and/or documentation resources like MDN and MSDN I don't think I am assuming much of anything in particular. That fact that you figured it out based on the information I provided doesn't really seem to question that assumption. :)

i know its maybe not the best way but at least it is something that i sort of understand i can follow what its doing unlike that ternary operator stuff the logic of which isn't making a whole lot of sense to me.

The ternary operator is just a different way of writing if/else.

Code: Select all
if condition == true then
  doSomething();
else
  doSomethingElse();
end

// or in ternary form
condition ? doSomething() : doSomethingElse()


It's a personal choice and value judgment about legibility.

I mean maybe this is simply another case of me missing something that is obvious to those that are more knowledgable about this stuff but I'm not really seeing how using that ternary operator stuff would actually accomplish what I'm trying to do since this isn't one of them times when i need to use an if() or a boolean (true or false)

I simply need to get the value from the parent row and then apply it to the children of that row so that i don't get the id is null error when i hover on the TDs.

You might want to actually try the working code I provided so that you can figure out why it works instead of assuming it doesn't because it doesn't fit your preconceived notions. That's on line #511.

I'll add this: https://stackoverflow.com/help/how-to-ask

In particular this: https://stackoverflow.com/help/mcve

Your last example was the first to include a not exactly minimal testcase, but a working testcase nonetheless. As far as the JS went it was close enough to minimal. Therefore I was able to post a working solution in seconds. That's the way to go. One thing I personally find is that trying to distill a problem to a minimal testcase will clarify it to yourself and often provide the solution in the process.

You'll note a common thread in the answers you received. I was talking in relative generalities because you posted disconnected code snippets. You can see the same in the first comment to this topic:

jscher2000 wrote:I can't test this without creating a document, but as a general idea:


Since you didn't pick up on my subtler hint when I said I would propose the exact opposite solution, to put it more bluntly your question as phrased is not a great question.

I simply need to get the value from the parent row and then apply it to the children of that row


This part is probably okay: "I simply need to get the value from the parent row"

But this part presupposes a solution: "then apply it to the children of that row"

When you lay out a problem you should indicate what the problem is, what you're trying to achieve and what you've already tried. Regarding your complaint, part of the reason you received answers in generalities is because you didn't provide a working testcase until the last reply. Ideally it would be a minimal testcase, but the JS was close enough in any case, which enabled me to provide a working solution in seconds. One that you then dismissed as not working because it didn't fit your preconceived notion of how the problem should be solved. Most people don't even bother responding to questions like that precisely for that reason, but I'm an optimist. :P

Question since I'm already getting the event target and the data attribute of that target would a simple loop work for this purpose, something like this perhaps ?

As for that code snippet, something along those lines would work but it doesn't make a whole lot of sense to do it on each and every hover event. You'd want to do it during setup, e.g., on DOMContentLoaded. That's an event, so document.addEventListener('DOMContentLoaded', SomeInitFunction).

Code: Select all
var trs = getElementsByTagName('tr') //or querySelectorAll())
// for loop over trs
  var tr = trs[i]
  var tds = tr.getElementsByTagName('td')
  // for loop over tds
    tds[j].setAttribute(whatever, tr.getAttribute(whatever))


That's the way to write it backward compatible to possibly IE5, but at least IE6. On modern browsers you could also use array.forEach() to write it more elegantly.

https://developer.mozilla.org/en-US/doc ... ay/forEach

PS Props for learning proper JS instead of doing jQuery and subsequently not having a notion of what JS actually entails! :D
Intelligent alien life does exist, otherwise they would have contacted us.

Bethrezen
 
Posts: 390
Joined: September 13th, 2003, 11:56 am

Post Posted May 10th, 2018, 10:20 am

When you lay out a problem you should indicate what the problem is, what you're trying to achieve and what you've already tried. Regarding your complaint, part of the reason you received answers in generalities is because you didn't provide a working testcase until the last reply. Ideally it would be a minimal testcase, but the JS was close enough in any case, which enabled me to provide a working solution in seconds. One that you then dismissed as not working because it didn't fit your preconceived notion of how the problem should be solved. Most people don't even bother responding to questions like that precisely for that reason, but I'm an optimist.


You make a fair point and perhaps I didn’t explain things as well as I could, but again this in part is down to the fact that my knowledge of JavaScript is so limited which can make it difficult to explain things in a clear concise way, more over what I'm attempting could be considered advanced for someone like me that has such limited knowledge of the subject matter, I mean ideally I'd much prefer not to use JavaScript at all because I'm of the opinion your pages should work correctly even if JavaScript is turn off, but in this instance I don’t seem to have a choice because despite looking I have been unable to find a way to do this that doesn't involve using JavaScript.

As for dismissing your answer it's less a case of dismissing it and more a case of not understanding it, I did have a read of the page you posted on ternary operators but that didn’t really make your code any clearer to me and I'm still none the wiser as to where you where going with it or what that’s supposed to do, I mean I could just copy and paste but in the long run that’s not really going to do my any good.

As for that code snippet, something along those lines would work but it doesn't make a whole lot of sense to do it on each and every hover event. You'd want to do it during setup, e.g., on DOMContentLoaded. That's an event, so document.addEventListener('DOMContentLoaded', SomeInitFunction).

Code: Select all
var trs = getElementsByTagName('tr') //or querySelectorAll())
// for loop over trs
  var tr = trs[i]
  var tds = tr.getElementsByTagName('td')
  // for loop over tds
    tds[j].setAttribute(whatever, tr.getAttribute(whatever))



Would that actually work though since each row has a different identifier? Again I'm having a tough time figuring out what that is supposed to do and how.

That's the way to write it backward compatible to possibly IE5, but at least IE6. On modern browsers you could also use array.forEach() to write it more elegantly.


To be honest I'm struggling with this enough as is without worrying about IE and M$ none standard way of doing things, I figure if Microsoft cant be bothered to make there browser follow web standards like everyone else then why should i waste my time trying to fix my code to make it work in IE I mean its not like they have like 75% of the browser market share any more, and as far as I'm concerned Microsoft should just give web developers a brake and

a.) stop making browsers because they suck at it
b.) immediately discontinue all versions of IE and edge
c.) Provide an uninstaller so that people can remove internet explorer and edge

PS Props for learning proper JS instead of doing jQuery and subsequently not having a notion of what JS actually entails! :D


Well trying any way and not doing so well apparently, frustrating as that is ](*,)

JavaScript designed to be easy for beginners, yeah right !! Unfortunately this is just so far beyond my level of knowledge at this point, that I'm completely out of my depth, and I'm beginning to wonder if I'm just going to have to pull the plug on this whole exercise since I simply lack the necessary know-how and understanding for this.

Frenzie

User avatar
 
Posts: 2134
Joined: May 5th, 2004, 10:40 am
Location: Belgium

Post Posted May 11th, 2018, 1:56 am

As for dismissing your answer it's less a case of dismissing it and more a case of not understanding it, I did have a read of the page you posted on ternary operators but that didn’t really make your code any clearer to me and I'm still none the wiser as to where you where going with it or what that’s supposed to do, I mean I could just copy and paste but in the long run that’s not really going to do my any good.


It's the equivalent of something like this:

Code: Select all
var attribute;
var data_name = target.getAttribute('data-name');
if (data_name) {
  attribute = data_name;
}
else {
  attribute = target.parentNode.getAttribute('data-name'); // Note the parentNode!
}


Sorry, I thought the parentNode would stick out like a sore thumb as something odd and different.

tl;dr What it's saying is: if this element doesn't have a data-name attribute, grab it from the parent.

To be honest I'm struggling with this enough as is without worrying about IE and M$ none standard way of doing things

This actually has nothing to do with IE breaking any standards. In IE4 you'd need to use a different, not standards-compliant method. ;) You could replace IE6 with something like Mozilla 1 or Opera 5 and the same would be true. I intended it as a temporal remark, because browsers from prior to ~2010 won't support some of this fancy new stuff like array.forEach() or document.querySelector(). IE8 is, however, the only older browser you might still consider worrying about in practice. (I wouldn't.)

Basically what I'm trying to say is that if all you're doing is, for instance, querySelectorAll('#some-id') then you might just as well use getElementById and be compatible with close to two decade old browsers. Depends on what you're going for.

JavaScript designed to be easy for beginners, yeah right !! Unfortunately this is just so far beyond my level of knowledge at this point, that I'm completely out of my depth, and I'm beginning to wonder if I'm just going to have to pull the plug on this whole exercise since I simply lack the necessary know-how and understanding for this.

Don't give up; you're doing fairly well so far. But are you saying this is your first attempt at scripting/programming?
Intelligent alien life does exist, otherwise they would have contacted us.

Bethrezen
 
Posts: 390
Joined: September 13th, 2003, 11:56 am

Post Posted May 11th, 2018, 6:01 pm

Don't give up; you're doing fairly well so far. But are you saying this is your first attempt at scripting/programming?


Pretty much.

I studied interactive media and web development at college up to HND level, and that did cover a bit of programming (national 5 computing science, although national 5 is probably only equivalent to what you would do in high school) a bit of JavaScript and a bit of php but most of what I covered was foundation level stuff, so things like basic functions, if statements, how to do simple loops, retrieving and working with data from web forms, a bit of data base stuff, so stuff like setting up a database and then linking it to the web page, doing simple searches, really basic stuff.

As far as programming goes I have only the most rudimentary knowledge, I know enough to be able to do some simple things like retrieving an element and then say changing its CSS, or retrieving a group of elements and then set up a simple loop to let me work with those elements, again really basic stuff but that’s about as far as my knowledge of JavaScript goes for the time being, it’s the one big criticism I have of the course that I did.

What I'm attempting now is simply me doing a bit of self learning, or at least trying to anyway, and what I'm working on right now is just one part of a project I've been working on in my spare time, mostly as a learning exercise but one with a useful end result when finished.

here is a little snap shot of what i have been working on

Image Image

have you ever heard of the X series of games ?
Last edited by Bethrezen on May 12th, 2018, 10:53 pm, edited 1 time in total.

Frenzie

User avatar
 
Posts: 2134
Joined: May 5th, 2004, 10:40 am
Location: Belgium

Post Posted May 12th, 2018, 10:09 am

Is that related to X-COM?
Intelligent alien life does exist, otherwise they would have contacted us.

Bethrezen
 
Posts: 390
Joined: September 13th, 2003, 11:56 am

Post Posted May 12th, 2018, 10:44 pm

No the X series of games X Beyond the Frontier, X Tension, X2 The Threat, X3 Reunion, X3 Terran Conflict, X3 Albion Prelude are space sims like wing commander / privateer / elite, and what I have been working on is my X Universe map simply check the radio button and the map will automatically morph to the one for that game so its basically 6 maps in 1, and when I'm done you'll be able to click on each sector and see a system map for that sector which will show a verity of information, or well it will if i can ever get this on hover highlighting working right that is, unfortunately that's proving to be more difficult that i anticipated given my limited knowledge of JavaScript.

Frenzie

User avatar
 
Posts: 2134
Joined: May 5th, 2004, 10:40 am
Location: Belgium

Post Posted May 13th, 2018, 12:32 am

https://developer.mozilla.org/en-US/doc ... parentNode

Would that actually work though since each row has a different identifier? Again I'm having a tough time figuring out what that is supposed to do and how.

I think doing it that way would be rather overcomplicated as I've said repeatedly, but of course. ;)

For debugging, use console.log.

Code: Select all
var trs = document.getElementsByTagName('tr')
for (var i=0; i<trs.length; i++){console.log(trs[i])}


Then in the console — that's in Tools → Web Developer → Web Console or Browser Console — you'll see all the elements nicely listed.

The reason I stored a reference to the trs[i] reference inside the scope of the for loop (var tr = trs[i]) is twofold:

1. It's simply easier to read and comprehend.
2. Otherwise you're potentially repeating the lookup over and over.

If any part of this is mysterious then the particular language isn't really relevant, but please don't hesitate to ask.

https://www.learn-js.org/en/Loops
Intelligent alien life does exist, otherwise they would have contacted us.

Bethrezen
 
Posts: 390
Joined: September 13th, 2003, 11:56 am

Post Posted May 13th, 2018, 10:11 am

ok so looks like changing

Code: Select all
var attribute = target.getAttribute('data-name');


to

Code: Select all
var attribute = target.parentNode.getAttribute('data-name');


did the trick, Why doing

Code: Select all
<script>
function hoveron(event)
{
  var target = event.target;
  var attribute = target.parentNode.getAttribute('data-name');

  var id = document.getElementById(attribute);
  id.style.cssText = "border:1px dashed red;";
}

function hoveroff(event)
{
  var target = event.target;
  var attribute = target.parentNode.getAttribute('data-name');

  var id = document.getElementById(attribute);
  id.style.cssText = "border:none;";
}

var cells = document.querySelectorAll("td");
for (i = 0; i < cells.length; i++)
{
  cells[i].addEventListener("mouseover", hoveron);
  cells[i].addEventListener("mouseout", hoveroff);
}
</script>


works where

Code: Select all
<script>
function hoveron(event)
{
  var target = event.target;
  var attribute = target.getAttribute('data-name');

  var id = document.getElementById(attribute);
  id.style.cssText = "border:1px dashed red;";
}

function hoveroff(event)
{
  var target = event.target;
  var attribute = target.getAttribute('data-name');

  var id = document.getElementById(attribute);
  id.style.cssText = "border:none;";
}

var cells = document.querySelectorAll("td");
for (i = 0; i < cells.length; i++)
{
  cells[i].addEventListener("mouseover", hoveron);
  cells[i].addEventListener("mouseout", hoveroff);
}
</script>


doesn't I don't really understand, but the upshot is i only need to add the data-name attribute on each row once instead of multiple times on every TD which would be extremely laborious, and ok it doesn't fire when you hover over the table row but that doesn't matter since table rows are inline elements that shrink-wrap there contents anyway.

god wish I'd known solving that little glitch was as simple as telling the script to look at the parent row for the data-name attribute instead of on the element on which I'm hovering in this case the child TDs, it would have saved me a lot time, frustration and confusion, well at least everything seems to be working now.

Bethrezen
 
Posts: 390
Joined: September 13th, 2003, 11:56 am

Post Posted May 13th, 2018, 11:36 am

Ok so now that I finally got this working correctly and I'm no longer getting errors in the console
for the benefit of everyone else out the that might be trying to do something similar in the future, here is how you can do.

Code: Select all
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>

div
{
display:inline-block;
vertical-align:top;
border:1px solid black;
height:100px;
width:100px;
}
</style>
</head>

<body>

  <div id="left">
    <img id="icon1" src="path to image" alt="Image 1">
    <br><img id="icon2" src="path to image" alt="Image 2">
    <br><img id="icon3" src="path to image" alt="Image 3">
    <br><img id="icon4" src="path to image" alt="Image 4">
  </div>

  <div id="right">
   
    <table>
      <tr>
        <td onmouseover="hoveron('icon1')" onmouseout="hoveroff('icon1')">Row</td>
        <td onmouseover="hoveron('icon1')" onmouseout="hoveroff('icon1')">1</td>
      </tr>

      <tr>
        <td onmouseover="hoveron('icon2')" onmouseout="hoveroff('icon2')">Row</td>
        <td onmouseover="hoveron('icon2')" onmouseout="hoveroff('icon2')">2</td>
      </tr>

      <tr>
        <td onmouseover="hoveron('icon3')" onmouseout="hoveroff('icon3')">Row</td>
        <td onmouseover="hoveron('icon3')" onmouseout="hoveroff('icon3')">3</td>
      </tr>

      <tr>
        <td onmouseover="hoveron('icon4')" onmouseout="hoveroff('icon4')">Row</td>
        <td onmouseover="hoveron('icon4')" onmouseout="hoveroff('icon4')">4</td>
      </tr>

    </table>

  </div>

<script>
function hoveron(id)
{
  var id = document.getElementById(id);
  id.style.cssText = "border:1px dashed red;";
}

function hoveroff(id)
{
  var id = document.getElementById(id);
  id.style.cssText = "border:none;";
}
</script>

</body>
</html>


without having to add onmouseover="hoveron('value')" onmouseout="hoveroff('value')" to your html, which is generally considered bad practice for the same reasons that inline css is generally considered bad practice because it makes editing and maintenance harder and more labour intensive, which completely defeats the whole point of separating structure, presentation and behaviour.

ok so first we have to modify the html from

Code: Select all
  <div id="left">
    <img id="icon1" src="path to image" alt="Image 1">
    <br><img id="icon2" src="path to image" alt="Image 2">
    <br><img id="icon3" src="path to image" alt="Image 3">
    <br><img id="icon4" src="path to image" alt="Image 4">
  </div>

  <div id="right">
   
    <table>
      <tr>
        <td onmouseover="hoveron('icon1')" onmouseout="hoveroff('icon1')">Row</td>
        <td onmouseover="hoveron('icon1')" onmouseout="hoveroff('icon1')">1</td>
      </tr>

      <tr>
        <td onmouseover="hoveron('icon2')" onmouseout="hoveroff('icon2')">Row</td>
        <td onmouseover="hoveron('icon2')" onmouseout="hoveroff('icon2')">2</td>
      </tr>

      <tr>
        <td onmouseover="hoveron('icon3')" onmouseout="hoveroff('icon3')">Row</td>
        <td onmouseover="hoveron('icon3')" onmouseout="hoveroff('icon3')">3</td>
      </tr>

      <tr>
        <td onmouseover="hoveron('icon4')" onmouseout="hoveroff('icon4')">Row</td>
        <td onmouseover="hoveron('icon4')" onmouseout="hoveroff('icon4')">4</td>
      </tr>

    </table>

  </div>


to

Code: Select all
  <div id="left">
    <img id="icon1" src="path to image" alt="Image 1">
    <br><img id="icon2" src="path to image" alt="Image 2">
    <br><img id="icon3" src="path to image" alt="Image 3">
    <br><img id="icon4" src="path to image" alt="Image 4">
  </div>

  <div id="right">
   
    <table>
      <tr data-name='icon1'>
        <td>Row</td>
        <td>1</td>
      </tr>

      <tr data-name='icon2'>
        <td>Row</td>
        <td>2</td>
      </tr>

      <tr data-name='icon3'>
        <td>Row</td>
        <td>3</td>
      </tr>

      <tr data-name='icon4'>
        <td>Row</td>
        <td>4</td>
      </tr>

    </table>

  </div>


next we have to modify the script from

Code: Select all
<script>
function hoveron(id)
{
  var id = document.getElementById(id);
  id.style.cssText = "border:1px dashed red;";
}

function hoveroff(id)
{
  var id = document.getElementById(id);
  id.style.cssText = "border:none;";
}
</script>


to

Code: Select all
<script>
function hoveron(event)
{
  var target = event.target;
  var attribute = target.parentNode.getAttribute('data-name');

  var id = document.getElementById(attribute);
  id.style.cssText = "border:1px dashed red;";
}

function hoveroff(event)
{
  var target = event.target;
  var attribute = target.parentNode.getAttribute('data-name');

  var id = document.getElementById(attribute);
  id.style.cssText = "border:none;";
}

var cells = document.querySelectorAll("td");
for (i = 0; i < cells.length; i++)
{
  cells[i].addEventListener("mouseover", hoveron);
  cells[i].addEventListener("mouseout", hoveroff);
}
</script>


finally here is the complete example

Code: Select all
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>

div
{
display:inline-block;
vertical-align:top;
border:1px solid black;
height:100px;
width:100px;
}

</style>
</head>

<body>

  <div id="left">
    <img id="icon1" src="path to image" alt="Image 1">
    <br><img id="icon2" src="path to image" alt="Image 2">
    <br><img id="icon3" src="path to image" alt="Image 3">
    <br><img id="icon4" src="path to image" alt="Image 4">
  </div>

  <div id="right">
   
    <table>
      <tr data-name='icon1'>
        <td>Row</td>
        <td>1</td>
      </tr>

      <tr data-name='icon2'>
        <td>Row</td>
        <td>2</td>
      </tr>

      <tr data-name='icon3'>
        <td>Row</td>
        <td>3</td>
      </tr>

      <tr data-name='icon4'>
        <td>Row</td>
        <td>4</td>
      </tr>

    </table>

  </div>

<script>
function hoveron(event)
{
  // Get the target of the event, e.g. the TD.
  var target = event.target;

  //Get the value of the data-name attribute from the targets parent.
  var attribute = target.parentNode.getAttribute('data-name');

  // set the value of getElementById() to the value of the targets parent.
  // e.g. getElementById('icon1') or getElementById('icon2') ect.
  var id = document.getElementById(attribute);

  // do something to the specified target.
  // e.g. place a border on the target on hover.
  id.style.cssText = "border:1px dashed red;";
}

function hoveroff(event)
{
  // Get the target of the event, e.g. the TD.
  var target = event.target;

  //Get the value of the data-name attribute from the targets parent.
  var attribute = target.parentNode.getAttribute('data-name');

  // set the value of getElementById() to the value of the targets parent.
  // e.g. getElementById('icon1') or getElementById('icon2') etc.
  var id = document.getElementById(attribute);

  // Do something to the specified target.
  // e.g. place a border on the target on hover.
  id.style.cssText = "border:none;";
}

// Get all table cells.
//You can also use document.getElementsByTagName("td").
var cells = document.querySelectorAll("td");

// iterate through the node list and add event listeners.
// (i = 0;) start the loop at the first value in the node list.
// (i < cells.length;) while the index is less than the number of items in the node list keep iterating through the node list.
// (i++) with each iteration add one to the index.
for (i = 0; i < cells.length; i++)
{
  //to each table cell add a mouseover event listener.
  //When the mouse over event is detected run the hoveron function
  cells[i].addEventListener("mouseover", hoveron);

  //to each table cell add a mouseout event listener.
  //When the mouseout event is detected run the hoveroff function
  cells[i].addEventListener("mouseout", hoveroff);
}
</script>

</body>
</html>

Return to Web Development / Standards Evangelism


Who is online

Users browsing this forum: No registered users and 1 guest