2

Lines 12-22

Function openManu currently displays a block on load and makes a for loop for my array. What this does is then creates an obj variable based on the array and takes Manufacturer from the array that's defined by the links that calls the function. So a link in my HTML for instance will have an onMouseOver event tied to openManu('manufacturer') and manu will be defined as manufacturer, only the "Description" in the array corresponding to this manufacturer will be inserted into the HTML.

My problem is I'm trying to create another function that runs before this that goes through my array and creates the links depending on what's in the array. Then since this gets called once the body loads the links should be present and the links will also have the onMouseOver event where the second function from lines 12-22 can be called.

Currently only openManu() works onMouseOver and will insert the Description based on the specified manufacturer into an object in my HTML called content. The createLinks() function I have opens the array and defines URL as a variable and inserts it into a link tag that gets created.

Is this possible to do? And is the order messing it up?

javascript:

var arr =   
[
  {
    "Manufacturer": "Any manufacturer",
    "Description": "Traditional values",
    "URL": "http://www.website.com"
  },
  {
    "Manufacturer": "Different Manufacturer",
    "Description": "Short description of said manufacturer",
    "URL": "http://www.website2.com"
  },
  {
    "Manufacturer": "A Similar Manufacturer",
    "Description": "Not quite the same as the previous manufacturer",
    "URL": "http://www.website3.com"
  },
  {
    "Manufacturer": "Manufacturer",
    "Description": "Essentially a ripoff of the first manufacturer",
    "URL": "http://www.website4.com"
  }
]

function createLinks() {
    for (var i=0; i<arr.length; i++){
      var obj = arr[i];
      var m = obj["Manufacturer"];
      if (manu == m) {
        URL = obj["URL"];
      }
    }
    document.getElementById('col').innerHTML = "<a onmouseover=\"openManu(\'" ++ m ++ "\')\" onmouseout=\"mouseOut()\" onClick=\"openWeb(\'" ++ URL ++ "\')\">" ++ m ++ "</a>");
}

function openManu(manu) {
  document.getElementById('content').style.display = 'block';
    for (var i=0; i<arr.length; i++){
      var obj = arr[i];
      var m = obj["Manufacturer"];
      if (manu == m) {
        desc = obj["Description"];  
      }
    }
    document.getElementById('content').innerHTML = desc;
}

window.onmousemove = function (e) {
    var tooltipSpan = document.getElementById('content');
    var x = e.clientX,
        y = e.clientY;
    tooltipSpan.style.top = (y - 20) + 'px';
    tooltipSpan.style.left = x + 'px';
}

var mouseOut = function(){
    document.getElementById('content').style.display = 'none'
}

function openWeb(URL) {
    window.open(URL);
}
#container{
width:870px;
margin-top:2em;
font-size:1.1em;
position:relative;
padding-left:20px;
display:inline-block;
background-color:#3C3C4E;}

#content{
z-index:1;
display:none;
width:300px;
font-size:16px;
font-family: 'Raleway', sans-serif;
position:absolute;
padding:10px;
background-color:white;}

a {
cursor:pointer;
padding:0;
display:inline-block;
margin:0;
color: white;
font-family: 'Raleway', sans-serif;
position:inherit;
}

h4 {
padding:0;
z-index:0;
display:inline-block;
margin:0;
color: white;
font-family: 'Raleway', sans-serif;
font-weight:normal;
font-size:15px;
background-color:#3C3C4E;
position:absolute;
left:8px;
padding:24px;
top:400px;
width:842px;
}

pre {
display:block;
float:left;
line-height:21px;
}
<!DOCTYPE html>
<html onload="createLinks()">

<div id="content"></div>

<pre id="col"></pre>

</html>

The old HTML included links that looked like this.

<a onmouseover="openManu('Any manufacturer')" onmouseout="mouseOut()" onClick="openWeb('http://www.website.com/')">Any manufacturer</a>

@Zer00ne in response to your answer, I changed createLinks() to this. I can't get it to work I might not fully understand your solution.

function createLinks() {
  arr[i]["Manufacturer"]
  var obj = arr[i];
  var m = obj["Manufacturer"];
  document.getElementById('col').innerHTML = "<a onmouseover=\"openManu(\'" ++ m ++ "\')\" onmouseout=\"mouseOut()\" onClick=\"openWeb(\'" ++ URL ++ "\')\">" ++ m ++ "</a>");
}

JSFiddle

4
  • 1
    Wouldn't be easier to do this: arr[i]["Manufacturer"] than var obj = arr[i]; var m = obj["Manufacturer"];? Commented Aug 8, 2016 at 16:37
  • 1
    Adding HTML events inside an innerHTML makes kitten cry. Why not createElement('a') and attach the event directly in the JavaScript. Using in code function references is far more performant and easier to reason then having the browser parse HTML and eval() strings which will introduce XSS (cross site scripting) problems. Commented Aug 8, 2016 at 17:04
  • I see, well I got as far as correcting createLinks() but now there another series of erreors... Commented Aug 8, 2016 at 17:08
  • >>Zer00ne in response to your answer, I changed createLinks() to this. I can't get it to work I might not fully understand your solution.<< See answer, Ben. Btw, Sukima is correct events generated by innerHTML do in fact make kittens cry. I would've went the way of createElement('a'), but I'm running out of time. Commented Aug 8, 2016 at 19:15

2 Answers 2

2

At first glance the string variable concatenation in the createLinks function is not formatted correctly.

function createLinks() {
    for (var i=0; i<arr.length; i++){
      var obj = arr[i];
      var m = obj["Manufacturer"];
      if (manu == m) {
        URL = obj["URL"];
      }
    }
    //document.getElementById('col').innerHTML = "<a onmouseover=\"openManu(\'" ++ m ++ "\')\" onmouseout=\"mouseOut()\" onClick=\"openWeb(\'" ++ URL ++ "\')\">" ++ m ++ "</a>");

// should be.
document.getElementById('col').innerHTML = "<a onmouseover=\"openManu(" + m + ") onmouseout=\"mouseOut()\" onClick=\"openWeb(" + URL + ") >" + m + "</a>";
}

// Although m and URL are never defined.

I also am not sure if you are trying to pass a variable or a string to the openMenu function, but i see that you are checking for the argument in your if statement.

    function openManu(manu) {
      document.getElementById('content').style.display = 'block';
        for (var i=0; i<arr.length; i++){
          var obj = arr[i];
          var m = obj["Manufacturer"];
          if (manu == m) { 
            /* 
This will never be true because your argument (manu) comes from whatever you are passing into your function which appears to be a string based on your code. The m that is being assigned from the obj will never be 'm' based on the code. It will be the value that is assigned to the "Manufacturer" key of the object."
*/
            desc = obj["Description"];  
          }
        }
        document.getElementById('content').innerHTML = desc;
    }

I hope this is a good start as to what is happening.

UPDATE -- THIS WORKS

This cod eis based off your JSFiddle code.

HTML

<body onload="createLinks()">

<div id="container">
<pre id="col"></pre>
</div>
<div id="content2"></div>
</body>

CSS

#container{
width:300px;
margin-top:2em;
font-size:1.1em;
position:relative;
display:inline-block;
background-color:#3C3C4E;}


#content{
display:none;
width:300px;
height: 45px;
font-size:16px;
font-family: 'Raleway', sans-serif;
padding:10px;
background-color:white;
}

#col a{
  display:block;
  padding-left:20px;
}
a {
cursor:pointer;
padding:0;
display:inline-block;
margin:0;
color: white;
font-family: 'Raleway', sans-serif;
position:inherit;
}

h4 {
padding:0;
z-index:0;
display:inline-block;
margin:0;
color: white;
font-family: 'Raleway', sans-serif;
font-weight:normal;
font-size:15px;
background-color:#3C3C4E;
position:absolute;
left:8px;
padding:24px;
top:400px;
width:842px;
}

pre {
display:block;
float:left;
line-height:21px;
}

JavaScript

var arr =   
[
  {
    "Manufacturer": "Any manufacturer",
    "Description": "Traditional values",
    "URL": "http://www.website.com"
  },
  {
    "Manufacturer": "Different Manufacturer",
    "Description": "Short description of said manufacturer",
    "URL": "http://www.website2.com"
  },
  {
    "Manufacturer": "A Similar Manufacturer",
    "Description": "Not quite the same as the previous manufacturer",
    "URL": "http://www.website3.com"
  },
  {
    "Manufacturer": "Manufacturer",
    "Description": "Essentially a ripoff of the first manufacturer",
    "URL": "http://www.website4.com"
  }
];

// cache the col element
var col = document.getElementById("col")
// The forEach loop goes through the array 
arr.forEach( function(key, idx){ // grab the key an dthe index
    var newAchr = document.createElement("a"); // create an anchor DOM element
    newAchr.href = key.URL; // assign the href for the element
    newAchr.text = key.Manufacturer; // assign the text
    newAchr.setAttribute("class", idx); // assign a class that will store the index. This will be used to get the description on mouseover.

    document.getElementById('col').appendChild(newAchr); // apend the element to the DOM
});

col.addEventListener("mouseover", function(e){
    var target = e.target, //get the currently targeted anchor tag
        idx = target.classList[0], // get the index that wsa stored inthe elements class
        desc = arr[idx].Description, // get the description from the array usinf the index from the class
        contentElem = document.getElementById('content2'); // get a reference to the content element

    contentElem.style.display = "block"; // display the content area
    contentElem.innerHTML = desc; // add the discription text to the content area
});

col.addEventListener("mouseout", function(e){
    var contentElem = document.getElementById('content2'); // get a reference to the content area

    contentElem.style.display = "none"; // hide the content area on mouseout
});
Sign up to request clarification or add additional context in comments.

7 Comments

So this is set up so that the key "Manufacturer" is supposed to be returned depending on which link is being hovered over and then the key's corresponding object "Description" is placed inside of the content block. I changed my original post to include the old HTML link tag which passes the manu argument into the function. The argument it passes is supposed to correlate to the "Manufacturer" and return it's "Description" with the onMouseOver event. I am trying to eliminate the need for these hard-coded link tags so that all that needs to be modified is the array.
You cannot use the onmouseover function unless you only want the "Manufacturer" that you place in the function. It never loops through the array. most of these action should be placed in their own function or at least inside the click function.
It also look like you are trying to match the array index to a menu item in you HTML. You can do that by matching the menus index with the array index.
Sorry I'm just confused. openManu works flawlessly, just the way I need it to. It finds the corresponding description and inserts it into the div. The only thing I am having trouble with is changing it up so that the links are generated from the createLinks() function. I am very new to JS so my terminology is very weak and I'm having a hard time understanding. The array gets matched to the link in HTML and displays a description. Should I open a JSFiddle?
The JSFiddle will make it easier to walk through.
|
1

UPDATE

Added the tooltips back, I realized what your intention was and #content following the cursor now. That would explain the wacky styles I was having trouble with.

I fixed it, the concept was sound the code needed a ton of work. I removed the mousemove event handler because having a tooltip made no sense when you already have a description displayed in #content. The following Snippet has descriptions in the /* comments */ // comments.

SNIPPET

/* Wrapped in an anonymous function to avoid globals */
(function() {
  var mfc = [{
    "Manufacturer": "Any manufacturer",
    "Description": "Traditional values",
    "URL": "http://www.website.com"
  }, {
    "Manufacturer": "Different Manufacturer",
    "Description": "Short description of said manufacturer",
    "URL": "http://www.website2.com"
  }, {
    "Manufacturer": "A Similar Manufacturer",
    "Description": "Not quite the same as the previous manufacturer",
    "URL": "http://www.website3.com"
  }, {
    "Manufacturer": "Manufacturer",
    "Description": "Essentially a ripoff of the first manufacturer",
    "URL": "http://www.website4.com"
  }];

  /* It's better to declare variable of 'for' loop outside of loop */
  var i, len = mfc.length;


  for (i = 0; i < len; i++) {
    // Use of bracket notation requires quotes 
    var m = mfc[i]["Manufacturer"];
    var URL = mfc[i]["URL"];
    var desc = mfc[i]["Description"];
    var col = document.getElementById('col');
    /*
    /| When concatenating strings, alternate between single and double
    /| quotes and don't double up on '+'
    */
    // title attribute will be "Description"
    // Just use href attribute instead of a function that does the same thing (i.e. openWeb(URL)
    // The text of an anchor is m
    /* 
    /| Notice the '+=' operand, this allows us to accumulate strings 
    /| instead of overwriting them on every loop. 
    */
    col.innerHTML += '<a title="' + desc + '" href="' + URL + '">' + m + '</a>';
  }
  var content = document.getElementById('content');


  /*
  /| Instead of attribute events, use addEventListener() on the 
  /| parent of the links (i.e. #col). In order to determine which anchor
  /| was clicked, you assign a var to event.target.
  */

  col.addEventListener("mouseover", function(e) {
    // Find the e.target (i.e. element that was hovered over), and get it's title
    // display content with desc as it's content.
    var desc = e.target.getAttribute('title');
    content.style.display = "block";
    content.innerHTML = desc;
  }, false);

  col.addEventListener("mouseleave", function(e) {
    content.style.display = "none";
  }, false);


  col.addEventListener("mousemove", function(e) {
    var x = e.clientX,
      y = e.clientY;
    content.style.top = (y - 20) + 'px';
    content.style.left = x + 'px';
  }, false);

})();
#container {
  width: 870px;
  line-height: 1.2;
  margin-top: 2em;
  font-size: 1.1em;
  position: relative;
  padding-left: 20px;
  display: inline-block;
  background-color: #3C3C4E;
}
#content {
  z-index: 0;
  display: none;
  width: 400px;
  font-size: 16px;
  font-family: 'Raleway', sans-serif;
  position: absolute;
  padding: 10px;
  color: white;
  background-color: black;
  top: 0;
}
col {
  position: absolute;
  top: 70px;
}
a {
  cursor: pointer;
  padding: 0;
  display: inine-block;
  margin: 0 5px;
  color: white;
  font-family: 'Raleway', sans-serif;
}
h4 {
  padding: 0;
  z-index: 0;
  display: inline-block;
  margin: 0;
  color: white;
  font-family: 'Raleway', sans-serif;
  font-weight: normal;
  font-size: 15px;
  background-color: #3C3C4E;
  position: absolute;
  left: 8px;
  padding: 24px;
  top: 400px;
  width: 842px;
}
pre {
  display: block;
  float: left;
  line-height: 21px;
}
<!doctype html>
<html>

<head>
  <meta charset="utf-8">
  <title></title>
</head>

<body>

  <div id="container">
    <div id="content"></div>
    <div id="col">
    </div>
  </div>
</body>

</html>

2 Comments

Your solution works the best for me, I was able to make it work the best with 3 columns and the ability to add links so that's exactly what I needed. I know that using the title tag on some browsers will bring up a tool tip alongside the custom tool tip, so instead of using title I changed it to alt and it works while only showing the desired tool tip. Is this an OK solution? It seems to work just fine, just wondering if you used title for a specific reason.
That's great, I'm glad I could help. I picked title because that's a default tooltip, so if for some reason your code broke because of a browser update or plugin incompatibility, etc. you'd still have some sort of tooltip as backup. alt is for img descriptions and are mainly for the purpose for screen readers, but if accessibility isn't a concern then it's just as valid choice as most other attributes. data-* should work as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.