2

I've iterated over a table with javascript so I can use the data as a variable for creating markers on a Google Map. My map and the code that iterates over the table both work, but I cannot figure out how to make the gridmap value available inside my marker variable. I assume I need to do a for loop around my marker variable, which I can probably figure out, I am simple stuck on taking my element variables, and making them available as variables for my markers. Below is my code, if this makes any sense. I've been at this for hours and it is 3:30am; I will refractor the question in the morning if needed. Thank you.

This is the updated and working code:

I iterated over the DOM to grab the <tr> elements from tbody only. Note the tr:gt(0) part - this skips the first header row. Then I create a new array by filtering out the markers against the gdata array. I still need to clean this up a bit add more functionality like clustering, but I am very happy at this point and hopefully this will help someone else.

<script>
    function initMap() {
        var map;

        var table = $("table");
        var labels = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        var labelIndex = 0;
        var htmlLabel = labels.split(""); // Add Labels to Html Columns for Matching

        var gdata = new Array();

        $("table tbody tr:gt(0)").each(function (i) {
            gdata[i] = new Array();
            $(this).children('td').each(function (ii) {
                gdata[i][ii] = $(this).text();
            });
        });

        var bounds = new google.maps.LatLngBounds();
        var mapOptions = {
            mapTypeId: 'satellite',
            disableDefaultUI: true,
            scrollwheel: false,
            draggable: true
        };

        // Display a map on the page
        map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
        map.setTilt(45);

        // Multiple Markers
        var markers = [
            ['a0', 32.840801, -117.244842],
            ['a10', 32.840801, -117.244842],
            ['a20', 32.840777, -117.244864],
            ['a30', 32.840758, -117.244881],
            ['a40', 32.840732, -117.244899],
            ['aa0', 32.840828, -117.244794],
            ['aa10', 32.840828, -117.244794],
            ['b0', 32.840624, -117.24493],
            ['b10', 32.840624, -117.24493],
            ['b20', 32.840594, -117.244928],
            ['b30', 32.840567, -117.244924],
            ['b40', 32.840544, -117.244918],
            ['b60', 32.840544, -117.244918],
            ['bb0', 32.840495, -117.244897],
            ['bb10', 32.840495, -117.244897],
            ['bb20', 32.840468, -117.244885],
            ['c0', 32.84082, -117.244712],
            ['c10', 32.84082, -117.244712],
            ['c20', 32.840815, -117.244729],
            ['c30', 32.840806, -117.244749],
            ['c40', 32.840793, -117.244767],
            ['c50', 32.840779, -117.244789],
            ['c70', 32.840755, -117.244816],
            ['cc0', 32.840828, -117.244661],
            ['cc10', 32.840828, -117.244661],
            ['d0', 32.840607, -117.244867],
            ['d10', 32.840607, -117.244867],
            ['d20', 32.840586, -117.24486],
            ['d30', 32.840567, -117.244856],
            ['d40', 32.840543, -117.244841],
            ['d50', 32.840514, -117.244824],
            ['dd0', 32.84046, -117.244774],
            ['dd10', 32.84046, -117.244774],
            ['e0', 32.840788, -117.244598],
            ['e10', 32.840788, -117.244598],
            ['e20', 32.840791, -117.24462],
            ['e30', 32.840788, -117.244644],
            ['e40', 32.840787, -117.244665],
            ['e50', 32.840783, -117.244687],
            ['e60', 32.84078, -117.244707],
            ['e70', 32.840769, -117.244729],
            ['ee0', 32.84078, -117.244539],
            ['ee10', 32.84078, -117.244539],
            ['f10', 32.840607, -117.244809],
            ['f20', 32.840586, -117.244802],
            ['f30', 32.840564, -117.244785],
            ['f40', 32.840543, -117.244765],
            ['f50', 32.840532, -117.244749],
            ['f60', 32.840519, -117.244731],
            ['f70', 32.840508, -117.244714],
            ['ff0', 32.840473, -117.244632],
            ['ff10', 32.840473, -117.244632],
            ['g0', 32.840709, -117.244468],
            ['g10', 32.840709, -117.244468],
            ['g20', 32.840718, -117.244484],
            ['g30', 32.840737, -117.244499],
            ['g40', 32.840739, -117.244515],
            ['g50', 32.840747, -117.244531],
            ['h0', 32.840681, -117.244569],
            ['h10', 32.840681, -117.244569],
            ['h20', 32.840707, -117.244574],
            ['i0', 32.840611, -117.24458],
            ['i10', 32.840611, -117.24458],
            ['i20', 32.840576, -117.24461]
        ];


        var filteredMarkers = []; // the results array

        for (var iii = 0; iii < gdata.length; iii++) // iterate for every marker key
        {
            filteredMarkers = filteredMarkers.concat(markers.filter(function (item) {
                return item[0] == gdata[iii][0];
            }));
        }
        console.log(filteredMarkers);
        console.log(gdata);
        console.log(markers);


        // Info Window Content
        var infoWindowContent = [
            ['<div class="">' +
            '<h3>Add Code Here</h3>' +
            '<p>Add Code Here</p>' + '</div>']
        ];

        // Display multiple markers on a map
        var infoWindow = new google.maps.InfoWindow(), marker, i;

        for (i = 0; i < filteredMarkers.length; i++) {
            var position = new google.maps.LatLng(filteredMarkers[i][1], filteredMarkers[i][2]);
            bounds.extend(position);
            marker = new google.maps.Marker({
                position: position,
                map: map,
                title: filteredMarkers[i][0],
                label: labels[labelIndex++ % labels.length]
            });

            // Allow each marker to have an info window
            google.maps.event.addListener(marker, 'click', (function (marker, i) {
                return function () {
                    infoWindow.setContent(infoWindowContent[i][0]);
                    infoWindow.open(map, marker);
                }
            })(marker, i));

            // Automatically center the map fitting all markers on the screen
            map.fitBounds(bounds);
        }

        // Override our map zoom level once our fitBounds function runs (Make sure it only runs once)
        var boundsListener = google.maps.event.addListener((map), 'bounds_changed', function (event) {
            this.setZoom(24);
            google.maps.event.removeListener(boundsListener);
        });
    }
</script>
Charles Smith
  • 3,201
  • 4
  • 36
  • 80
  • What is `a10` ? – Thomas Jan 22 '17 at 11:44
  • Which `maker`? There are two `maker` variable in your code. And I don't get where you want to access `gridmap` value. – fumihwh Jan 22 '17 at 11:57
  • you don't need the instances of `marker` inside your `each` loop as you can just use `alphabet[i]` in your console.log. `gridmap` is defined as a private variable, so it is also inaccessible from outside of your `each` loop. would suggest defining `gridmap` as one of your initial `var`s instead. From here I would also ask the same question as @fumi_hwh – Sam0 Jan 22 '17 at 12:05
  • The `a10` refers to an external file with a list of lat/lng variables that look like `var a0 = {lat: 32.840801, lng: -117.244842};` - it was temporary; I updated my question with `gridmap`. This is a Django app, and one of the model objects is a `gridmap`, but using a Django tag in my script is tough, so I used `.each` to grab the values while in the DOM, which is fine because the only markers I need are what are in the DOM at the time. See my dev site at http://www.new.soledadmemorial.com/plaques/ – Charles Smith Jan 22 '17 at 17:34
  • Oh and The alphabet[i] is for the label I need to add to my html table to match the `LABEL` that Google Maps will add to the marker - I've updated alphabet[i] to label[i] in my question. – Charles Smith Jan 22 '17 at 17:37
  • my bet: sleep over it, refactoring the question will clear the issues :) – philipp Jan 22 '17 at 18:00
  • I updated my code and made it a little cleaner, plus added the marker variable inside the .each loop. For better explanation, I added a screenshot with annotations. I think the only thing I am trying to figure out is how to get my gridmap text from the .each loop into the marker `position: gridmap`. It prints to console just fine, but when added to the marker position, I get a `InvalidValueError: setPosition: not a LatLng or LatLngLiteral: not an Object` error in console. If I add a variable such as `a20` to the position, it works with no error - obviously I need to run through the loop. – Charles Smith Jan 22 '17 at 23:26
  • looks like you just need to convert the text string gained from `gridmap = $tds.eq(8).text();` into an object literal, should be solvable if you can show us a sample `gridmap` string? I imagine using something like `gridmap = $.parseJSON( $tds.eq(8).text());` from http://api.jquery.com/jquery.parsejson/ ? The gridmap object numbers will probably be in string format so might further have to be converted again. Will add an answer suggestion, please comment if it doesn't work – Sam0 Jan 23 '17 at 01:18
  • That gives me a `Uncaught SyntaxError: Unexpected token e in JSON at position 0` - I imagine because one of my gridmap variables begins with a single `e`. – Charles Smith Jan 23 '17 at 01:28
  • I understand now, was halfway through an answer but realised `gridmap` is returning the variable name as a string, but you need the variable content as it would be called in the script. If there's a way for you to push the series of variables into an array it would be easier, but will have a look at a different path in the meantime – Sam0 Jan 23 '17 at 01:31
  • you might find this helps: http://stackoverflow.com/questions/1920867/get-global-variable-dynamically-by-name-string-in-javascript which if this is right means this script needs to be able to access the variables in your plaque-vars.js file, something like `scope[gridmap]` with scope being the window or other as described in the SO answer. – Sam0 Jan 23 '17 at 01:37
  • @sam0 No sure if this is what you meant, but I added ` var obj = []; obj.push(gridmap); console.log(obj[0]);` and all it does is print the gridmap var to the console again but still not allowing usage as a `position` – Charles Smith Jan 23 '17 at 02:25
  • essentially the content of the cell data that you're reading into gridmap needs to look like `"{lat:34.544,lng:46.554}"` (object literal) in the table before it is read into gridmap, but currently it looks like `"e40"` which is in principle the name of a variable, but as a string (hence not the actual variable). these are two very different kinds of data, hence the problem. so first question is are you able to introduce the object literal data into the same arena, if it's currently in a different file and all defined as discrete private variables then it'll be tricky – Sam0 Jan 23 '17 at 07:32

1 Answers1

0

It appears you're also using Angular and that the id='gridmap' div is returning the object name and not the content. The nature of the div content looks like the crux of problem and so would suggest looking at this SO question: How to show object property with Angularjs

From here if you can generate HTML that looks something like this below after Angular has done its thing, keeping the property out of view by inserting its elements into data tags:

<tr>
   <td> ..... </td>
   <td> ..... </td>
   <td> ..... </td>
   <td class='gridmap' data-lat='23.424' data-lng='-117.233'>a0</td>
</tr>

If you insert the whole object including curly brackets you may have to do additional JSON stringification and parsing which at this point are better avoided.

Note that HTML id labels should only used for unique DOM elements, so if you have more than one table row it should be a class (which also means adjusting your css accordingly)

Now we can use jquery data to interrogate the same HTML cell tag and pass to grLat and grLng variables :

    $('tr').each(function (i) {
        var $tds = $(this).find('td').eq(8), // moved the eq(8) here
            gLabel = htmlLabel[i],
            gridmap = $tds.text(),
            grLat = Number($tds.data('lat')), // get the lat data
            grLng = Number($tds.data('lng')); // get the lng data

        console.log(
            'Marker:' + gLabel
            + '\nRow:' + (i + 1)
            + '\nGrid Map: ' + gridmap
            + '\nGrid lat: ' + grLat
            + '\nGrid lng: ' + grLng   // check components
        );

        var marker = new google.maps.Marker({
            position: {lat: grLat, lng:grLng}, // recomposed object
            map: map,
            label: labels[labelIndex++ % labels.length],
            animation: google.maps.Animation.DROP

        });
    })

This should put you in a better position to debug

Community
  • 1
  • 1
Sam0
  • 1,459
  • 1
  • 11
  • 13
  • There will no doubt be many people outraged at my combining Angular with jQuery. I'm no good at angular but have had similar situations using Wordpress php with jquery to pass json data and have had to perform various acrobatics to parse the data, hence better to interrogate the elements of your database and insert those directly. – Sam0 Jan 23 '17 at 11:02
  • I wasn't using Angular. But I did figure it out...only tool 3 days :) Thank you for everyones input. – Charles Smith Jan 23 '17 at 19:51