0

I have a basic U.S. map. It needs to be fixed position. The state abbreviations are also in fixed positions. A database is queried according to user input. When the results of that query have information relevant to a particular state, I change the class of that state abbreviation that formats a button. My goal is to produce a div holding the information related to that state below the button. My problem is that, rather than appearing after the state abbreviation button, the div appears after the container holding the map. CSS

<style>
    #MapContainer {position:absolute; width:1760px; height:1099px; top:0; left:0; padding:0; z-index:1;}
    .Abr {position:absolute; font-size:18px; font-weight:bold; color:#006393; z-index:100}
    .Active {background:red; padding:6px; color:white; border:1px solid black; border-radius:50%;}
</style>

HTML with PHP (I'll show one state)

<div id="MapContainer">
    <img src="maps/TransUSA-All50-1760x1099.png" style="width:100%" />
    <div class="Abr" id="WA" style="top:100px; left:238px;">WA</div>
    // Database queries follow here after all state names have been defined
    while($Info = i5_fetch_array($Result))
   {
     switch($Info[STATE])
     {
     case "WA":
        echo('<script>$("#WA").addClass("Active"); var Rates = "'.$Info[Rates].'"; var Charges = "'.$Info[Charges].'";</script>');
        break;
     //etc.
    }
</div>

Obviously, I will need to send the variables (Rates, Charges) to the function that creates the display. But that is not my concern at the moment. The purpose of this question is, first of all, getting the div that will hold the data to appear below the state abbreviation button.

jQuery

<script type="text/JavaScript">
    $(".Active").on("click", function()
    {
       this.insertAdjacentHTML("afterend","<div>This is a data Div</div>");
    });
</script>

The result of a click is that the appended div appears at the end of the map container instead of directly after the "WA" abbreviation button.

Example:

<div id="MapContainer">
    <div id="WA">WA</div>
    // Data div should appear here
</div>
// Data div appears here



  ___________________________________________________
    |                                                 |
    |  <div>WA</div>                                  |
    |   <div>Data div should appear here</div>        |
    |                                                 |
    |_________________________________________________|
    <div>Data div appears here instead</div> 
 

I created a fiddle Here But here, rather than appearing below the map block, it appears inside it. Still, of course, not the desired outcome.

Final Outcome For those interested, this was the final outcome, but still with a caveat - Used in this way with fixed positioning, I have failed to find a remedy to the stacking structure, so the info box is overridden by adjoinig state abbreviations.

enter image description here

https://jsfiddle.net/RationalRabbit/rj8g2bqm/87/

My eventual solution to that was to simply take a screenshot of the map with abbreviations in place and use that for the background, removing the abbreviations from the span sections, and adding them in when a state is active. Still, some active buttons overrode the info boxes, which I solved by changing the order they are rendered. I realized then this may have been the solution in the first place, although I haven't tested it. For example, if the abbreviation "ID" had been placed before "OR" in the abbreviation definitions, this may have solved the problem.

RationalRabbit
  • 1,037
  • 13
  • 20
  • Hi, can you show html generated of your code ? – Swati Apr 09 '21 at 04:23
  • @Swali I'm sorry, I don't know if I understand the question. It's a map. Basically, there are two blocks - the div container that holds the map, with a number of smaller divs, each holding a state name abbreviation, placed throughout the map. Those divs have a z-index of 100, while the z-index of the map is 1. When active, the smaller divs are clickable. The data div should appear below the "Active" div when clicked. Instead, it appears below the map container div. All divs are predefined. They become dymanic when the "Active" class is added, but the click works. – RationalRabbit Apr 09 '21 at 04:40
  • so are you seeing that behaviour [here](https://jsfiddle.net/jwh7opgk/) ? – Swati Apr 09 '21 at 04:46
  • Try `.insertAdjacentHTML('beforeend', ...)` – Wazeed Apr 09 '21 at 04:50
  • @Swali Thank you. No. I put a border around the main div to assure it was inside that div. Going to play around with this fiddle a little more ... – RationalRabbit Apr 09 '21 at 04:58
  • @Wazeed It expands inside the state div, rather than above it. – RationalRabbit Apr 09 '21 at 05:03
  • Also , check [this](https://stackoverflow.com/questions/14846506/append-prepend-after-and-before) will help you to understand more or try `$(this).after('
    This is a data Div
    ');`.
    – Swati Apr 09 '21 at 05:08
  • @RationalRabbit where is the class `Active` is added in html? – Wazeed Apr 09 '21 at 05:10
  • @Wazeed Notice the script in the HTML PHP code – RationalRabbit Apr 09 '21 at 05:20
  • @RationalRabbit, then provided code would add html just after `#WA` div. – Wazeed Apr 09 '21 at 05:34
  • @Wazeed Take a look at the fiddle https://jsfiddle.net/RationalRabbit/rj8g2bqm/20/ – RationalRabbit Apr 09 '21 at 06:03

2 Answers2

1

Check this below code, added the same in codepen Positioned DIVs for MAP

$(document).ready(function () {
    $("#WA").addClass("Active");
    $(".Active").on("click", function (e) {
        var $this = $(this), $data = $this.next('.AbrData');
        var ST = "AK"; // You can pull this from the state div along with the data
        if ($data.length == 0) {
            $data = $("<div class='AbrData'></div>").insertAfter($this);
            $data.append('<div id="' + ST + 'Data">This is a data Div</div>');
        }
        else {
            $data.toggle();
        }
    });
});
#MapContainer {
    position: absolute;
    width: 700px;
    height: 400px;
    top: 10px left 10px;
    padding: 0;
    z-index: 1;
    border: 2px solid black;
}

.Abr {
    position: absolute;
    font-size: 18px;
    font-weight: bold;
    color: #006393;
    z-index: 100;
}

.AbrData {
    position: relative;
    top: 10px;
    font-size: 12px;
    color: blue;
    z-index: 101;
    max-height: 100px;
    overflow: auto;
    border: 1px solid grey;
}

.Active {
    background: red;
    padding: 6px;
    color: white;
    border: 1px solid black;
    border-radius: 50%;
    cursor: pointer;
}
<div id="MapContainer">
    <div class="Abr" style="top:100px; left:238px;">
        <span id="WA">WA</span>
    </div>
    <div class="Abr" style="top:213px; left:207px;">
        <span id="OR">OR</span>
    </div>
    <div class="Abr" style="top:315px; left:550px;">
        <span id="WY">WY</span>
    </div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

I have merged suggested changes, and the appearing line after toggling data is the border of div.AbrData. I have changed toggle line from so the it toggles div.AbrData instead of it's inside content.

// Changed this toggle
$("#"+ST+"Data").toggle();

// To this
$data.toggle();
Wazeed
  • 1,230
  • 1
  • 8
  • 9
0

Actually insertAdjacentHTML is not part of jQuery. It's DOM element's method. See the example below, how it works:

var div = document.querySelector('#idDiv');
div.insertAdjacentHTML('beforebegin', '<p>beforebegin</p>');
div.insertAdjacentHTML('afterbegin', '<p>afterbegin</p>');
div.insertAdjacentHTML('beforeend', '<p>beforeend</p>');
div.insertAdjacentHTML('afterend', '<p>afterend</p>');

console.log(document.querySelector('#container').outerHTML);
div {
  color: blue;
  border: 1px solid blue;
  padding: 5px;
}
p {
  color: red;
  border: 1px solid red;
  padding: 5px;
}
<div id="container">
<div id="idDiv">ORIGINAL HTML DIV CONTENT</div>
</div>
Wazeed
  • 1,230
  • 1
  • 8
  • 9
  • 1
    Yes, I've read quite a bit for several hours as to how it SHOULD behave, and tried several different methods. Problem is, that is not what's happening. I'll try to put a fiddle together that will more represent the situation. I edited Swali's, but it didn't save. – RationalRabbit Apr 09 '21 at 05:30
  • I added a fiddle at the bottom of my question. – RationalRabbit Apr 09 '21 at 05:43
  • I see, this UI behavior is due to added CSS `position: absolute;`. You can see in generated HTML, the elements are getting added just after `#WA` div. – Wazeed Apr 09 '21 at 06:01
  • Yes, if you remove the positioning, the added div will fall in where you would expect it to. Certainly, though there is a way to achieve this functioning. (Normally, they are actually "fixed" rather than "absolute"). Yes, the elements (if you mean the script that changes the class) are added afterwards. Certainly a better idea than adding then before the div exists, no? Or are you saying the JavaScript is getting ahead of the HTML? The JavaScript certainly has no problem changing the class and formatting appropriately. – RationalRabbit Apr 09 '21 at 06:15
  • Yes, I have made some changes in CSS and HTML as well to achieve proper positioning of added data div. Please refer this codepen [Positioned DIVs](https://codepen.io/Wazeed/pen/LYxOJKy) – Wazeed Apr 09 '21 at 06:18
  • That's fine if you have straight little blocks. But I don't have straight little blocks. I have a map of the United States. – RationalRabbit Apr 09 '21 at 06:26
  • Yes, the issue is actually is not with `.insertAdjacentHTML("afterend", ...)`. Need to look into the CSS in positioning. I will try to prepare another codepen. – Wazeed Apr 09 '21 at 06:30
  • I guess you could send coordinates for the new div to the function. That should work, but seems a little messy. Seems like there should be a better way. – RationalRabbit Apr 09 '21 at 06:39
  • @RationalRabbit, I have added another answer to this. Check the same, hope that helps – Wazeed Apr 09 '21 at 07:26
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/230926/discussion-between-wazeed-and-rationalrabbit). – Wazeed Apr 09 '21 at 07:39