Force Google InfoWindow To Redraw Itself or Refres

2019-04-17 11:20发布

问题:

How can I force google to redraw its infoWindow or atleast refresh its contents? I noticed that I must click twice on a marker before the correct data appears inside the infoWindow -maybe my closure here is the culprit.

    var markers = new Array();
    var allMarkers = new Array();
    var infoWindow = new google.maps.InfoWindow();
    var infoWindows = new Array();

    // IE caches ajax request - need a way to clear cache with each fetch of data
    randomize = function () {
        var randomnumber = Math.floor(Math.random() * 100000);
        return randomnumber;
    }

    function getBeachLocations() {
        // construct query
        var queryURL = "https://www.googleapis.com/fusiontables/v1/query?sql=";
        var queryTail = "&key=apiKey&callback=?";
        var query = "SELECT * FROM BeachTable"; // beach locations tbl
        var queryText = encodeURI(query);

        $.ajax({
            type: "GET",
            url: queryURL + queryText + queryTail,
            cache: false,
            dataType: 'jsonp',
            success: createMarkers,
            error: function () {
                alert("Sorry, no spatial data is available at this time, please check back on a later date.");
            }

        });
    } //end getBeachLocations


    function createMarkers(data) { // =====================create markers

        url = "http://swim.jpg";
        var rows = data['rows'];
        var ecoli_rows;
        var algae_rows;



        for (var m in rows) {

            var ecoli_array = new Array();
            var marker = new google.maps.Marker({
                map: map,
                icon: new google.maps.MarkerImage(url),
                beach_id: rows[m][0],
                beach_name: rows[m][1],
                beach_region: rows[m][2],
                position: new google.maps.LatLng(rows[m][4], rows[m][5]),
                idx: m,
                getHeader: function () {
                    var str = [
                        '<div style="width:650px;">',
                            '<div class="tabs">',
                                '<ul>',
                                    '<li><a href="#tab-1" class="ecoli_tab"><span>E. Coli Data</span></a></li>',
                                    '<li><a href="#tab-2" class="algae_data"><span>Algae Data</span></a></li>',
                                '</ul>',
                                '<div id="tab-1">',
                                '<h1>' + this.beach_name + '</h1>',
                                '<h3>' + this.beach_region + '</h3>'

                    ].join('');
                    return str;
                }, // end getHeader method

                getEcoliData: function () { // begin getEcoliData
                    var obj;
                    obj = getEcoliData(this.beach_id);
                    return obj;
                }, // end getEcoliData method

                afterGetEcoliData: function (data) {

                    var ecoli_rows;
                    var ecoli_rows_str;

                    ecoli_rows = data['rows'];

                    var ecoli_rows_str = [
                        '<table id="ecoli_table " class="data" style="width:500px;">',
                        '<tr>',
                            '<th>Sample Date</th>',
                            '<th>Average E. coli Density <br/> (200 cfu/100 ml)</th>',
                            '<th>Recreational Water Quality Guideline</th>',
                        '</tr>'
                    ].join('');

                    if (typeof ecoli_rows == 'undefined') {
                        ecoli_rows_str = '<p>Sorry no ecoli data currently exists for this beach.</p></div>'
                    } else {

                        for (var i = 0; i < ecoli_rows.length; i++) {
                            //console.log(rows[i]);
                            ecoli_rows_str += '<tr><td>' + formatDate(ecoli_rows[i][2]) + '</td><td>' + checkEcoliCount(ecoli_rows[i][3]) + '</td><td>' + ecoli_rows[i][4] + '</td></tr>';
                        }
                        ecoli_rows_str += '</table>'
                        ecoli_rows_str += '</div>';

                        // remove after test
                        ecoli_rows_str += '<div id="tab-2"><h1>nothing loaded</h1></div></div></div>';
                    } //end if
                    return ecoli_rows_str;
                }, // end outPutEcoliData method

                getAlgaeData: function () { // begin getAlgaeData
                    var obj;

                    var algae_rows_str = [
                          '<div id="tab-2">',
                         '<h1>' + this.beach_name + '</h1>',
                         '<h3>' + this.beach_region + '</h3>',
                         '<table id="algae_table " class="data" style="width:500px;">',
                        '<tr>',
                            '<th>Sample Date</th>',
                            '<th>Algal Toxin Microcystin <br/> (20 ug/L)</th>',
                            '<th>Recreational Water Quality Guideline</th>',
                             '<th>Blue Green Algae Cells <br/>(100,000 cells/ml)</th>',
                            '<th>Recreational Water Quality Guideline</th>',
                        '</tr>'
                    ].join('');

                    obj = getAlgaeData(this.beach_id);
                    return obj;


                }, // end getAlgaeData method

                outPutAlgaeData: function (data) {
                    obj.done(function (data) {
                        algae_rows = data['rows'];
                    }); // end success


                    //console.log(algae_rows);

                    if (typeof algae_rows === 'undefined') {
                        algae_rows_str = [
                             '<div id="tab-2">',
                                 '<h1>' + this.beach_name + '</h1>',
                                 '<h3>' + this.beach_region + '</h3>',
                                '<p>Sorry no algae data exists for this beach.</p>',
                            '</div>',
                            '</div>',
                            '</div>',
                            '</div>'
                        ].join('');
                    } else {

                        for (var i = 0; i < algae_rows.length; i++) {
                            //console.log(rows[i]);
                            algae_rows_str += '<tr><td>' + formatDate(algae_rows[i][2]) + '</td><td>' + checkAlgaeToxinCount(algae_rows[i][3]) + '</td><td>' + algae_rows[i][4] + '</td><td>' + checkAlgaeCount(algae_rows[i][5]) + '</td><td>' + algae_rows[i][6] + '</td></tr>';
                        }
                        algae_rows_str += '</table>'
                        algae_rows_str += '</div></div></div>';
                        //return algae_rows_str;

                    } //end if
                    return algae_rows_str;
                } // end outPutAlgaeData

            });       // ====================end marker

            allMarkers.push(marker); //required for drop down menu

            console.log(marker.beach_id + " "  + marker.beach_name);



             // click event handler
            google.maps.event.addListener(marker, 'click', function () {
                var ajaxObj = this.getEcoliData();
                var marker = this;
                var str;

                // add loading gif
                //infoWindow.setContent('<img src="../img/loading.gif" alt="loading data"/>');

                ajaxObj.done(function (data) {

                    /*
                    str = marker.getHeader() + marker.afterGetEcoliData(data);
                    console.log(str);
                    */

                    infoWindow.setContent(marker.getHeader() + '' + marker.afterGetEcoliData(data));
                    infoWindow.open(map, this);

                    $(".tabs").tabs({ selected: 0 });
                }); // End done
            }); // End click event handler



        } // end for loop foreach marker

        checkAdvisory(); // determine where this needs to be called from.
    } //end function createMarkers

    // format date as January 1, 2013
    function formatDate(num) {
        var d = Date.parse(num).toString('MMMM d, yyyy');
        return d;

    }

    // check ecoli count - anything greater than or equal to 200 cfu/100ml is flagged
    function checkEcoliCount(num) {
        var str;
        num = parseFloat(num);
        if (num >= 200) {
            str = '<span class="ecoliCount_on" style="color:orange"><b>' + num + '</b></span>';
        } else {
            return num;
        }
        return str;
    }

    // check blue green algae count - anything greater than or equal to 100,000 cells/ml is flagged 
    function checkAlgaeCount(num) {
        var str;
        num = parseFloat(num);

        if (num >= 100000) {
            str = '<span class="algaeCount_on" style="color:orange"><b>' + num + '</b></span>';
        } else {
            return num;
        }
        return str;
    }

    // check algae toxin microcystin - anything greater than or equal to 20 ug/L is flagged
    function checkAlgaeToxinCount(num) {
        // why include < ? - ask Cassie
        var str;
        var idx;

        idx = num.indexOf("<");

        num = num.substring(idx + 1);

        num = parseFloat(num);

        if (num >= 20) {
            str = '<span class="algaeToxinCountOn" style="color:orange"><br>' + num + '</b></span>';
        } else {
            return num;
        }
        return str;
    }

    function checkAdvisory() {
        /* add advisory images
        ecoliCount_on
        algaeCount_on
        algaeToxinCountOn
        */
        $(".ecoliCount_on").each(function (i, v) {
            console.log(i, v);
            $(this).css("color", "green");
        });
        $(".algaeCount_on").each(function (i, v) {
            console.log(i, v);
            $(this).css("color", "green");
        });
        $(".algaeToxinCountOn").each(function (i, v) {
            console.log(i, v);
            $(this).css("color", "green");
        });
    }

    function getEcoliData(beach_id) {
        //console.log(beach_id);
        var rows;

        var queryURL = "https://www.googleapis.com/fusiontables/v1/query?sql=";
        var queryTail = '&key=apiKey&callback=?';
        var whereClause = "WHERE 'Beach_ID' = " + beach_id;
        var query = "SELECT * FROM EcoliTable "
        + whereClause + " ORDER BY 'Sample_Date' DESC";


        var queryText = encodeURI(query);

        var ecoli_array = new Array();

        return $.ajax({
            type: "GET",
            url: queryURL + queryText + queryTail,
            cache: false,
            dataType: 'jsonp'
        });
    }

    function getAlgaeData(beach_id) {

        var queryURL = "https://www.googleapis.com/fusiontables/v1/query?sql=";
        var queryTail = '&key=apiKey&callback=?';
        var whereClause = " WHERE 'Beach_ID' = " + beach_id;
        var query = "SELECT * FROM algaeTable "
        + whereClause + " ORDER BY 'Sample_Date' DESC";

        var queryText = encodeURI(query);

        // ecoli request
        return $.ajax({
            type: "GET",
            url: queryURL + queryText + queryTail,
            cache: false,
            dataType: 'jsonp'     
        });
    }


    // create beach locations dropdown
    function createDropDownMenu() {

        var query = 'SELECT Beach_Location, Beach_ID  FROM      beachTable ORDER BY Beach_Location ASC';

        var queryText = encodeURIComponent(query);
        var gvizQuery = new google.visualization.Query(
                                        'http://www.google.com/fusiontables/gvizdata?tq=' + queryText);

        //Send query and draw table with data in response
        gvizQuery.send(function (response) {
            var numRows = response.getDataTable().getNumberOfRows();
            var numCols = response.getDataTable().getNumberOfColumns();

            var name = ['<label style="font-weight:bolder;font-size:16px"> Select a Beach:</label><select id="beach_menu"  style="font-size:16px;" onchange="select_beach(this.options[this.selectedIndex].value);"><option class="defaultopt" value="">--All--</option>'];

            for (var i = 0; i < numRows; i++) {

                var nameValue = response.getDataTable().getValue(i, 0);
                var idValue = response.getDataTable().getValue(i, 1);




                name.push("<option value=" + "'" + idValue + "'" + ">" + nameValue + "</option>");

            }
            name.push('</select>');

            document.getElementById('beach_location_dropdown').innerHTML = name.join('');
        });

    } // end createDropDownMenu Function

    function select_beach(val) {
        $("#beach_menu option[value='" + val + "']").attr('selected', 'selected');
        if (val === "") {
            resetMapExtent();
            displayAllBeaches();
        }
        else {
            update_layer(val)
        }
    } // end select_beach function 

    function resetMapExtent() {
        google.maps.event.trigger(map, "resize");
        map.setCenter(new google.maps.LatLng(53.760861, -98.813876));
        map.setZoom(5);
    } // end resetMapExtent function

    // implement update_layer function
    function update_layer(beach) {
        infoWindow.close();
        for (var z = 0; z < allMarkers.length; z++) {
            if (beach === allMarkers[z].beach_id) {
                allMarkers[z].setVisible(true);
            } else {
                // hide all other markers
                allMarkers[z].setVisible(false);
            }
        }
    } // end update_layer function 

    function displayAllBeaches() {
        infoWindow.close();
        // show all markers
        for (var z = 0; z < allMarkers.length; z++) {
            // hide all markers
            allMarkers[z].setVisible(true);
        }
    } // end displayAllBeaches


    /* start map initialization  */
    function initialize() {


        // map
        latlng = new google.maps.LatLng(49.894634, -97.119141);
        var myOptions = {
            center: latlng,
            zoom: 7,
            mapTypeId: google.maps.MapTypeId.ROADMAP,
            zoomControlOptions: {
                style: google.maps.ZoomControlStyle.SMALL
            },
            mapTypeControl: true,
            mapTypeControlOptions: {
                mapTypeIds: [
                                                google.maps.MapTypeId.ROADMAP,
                                                google.maps.MapTypeId.SATELLITE,
                                                google.maps.MapTypeId.HYBRID,
                                                google.maps.MapTypeId.TERRAIN
                                            ],

                style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
            },
            overviewMapControl: true,
            overviewMapControlOptions: {
                opened: true
            }
        };

        map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);


        // invocation begins here
        createDropDownMenu(); // not working now.
        getBeachLocations();




        // legend
        map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].push(
            document.getElementById('legend'));

        var legend = document.getElementById('legend');
        var swim_icon = "swim.jpg";


        var div = document.createElement('div');
        div.innerHTML = '<h4>Features</h4>' +
                                        '<br/><img src="' + swim_icon + '"> ' + "Beaches";
        legend.appendChild(div);

    } // end initialization function

    $(function () {
        $('.view_normal').live('click', function () {
            $(".container").css("width", "930px").css("margin", "auto");
            $(".onewidecenter").css("width", "930px").css("margin", "auto");
            $("#map_canvas").css("width", "930px").css("margin", "auto");
            google.maps.event.trigger(map, "resize");
            map.setCenter(new google.maps.LatLng(53.760861, -98.813876));
            map.setZoom(5);

        });
        $('.view_full_screen').live('click', function () {
            $(".container").css("width", "100%").css("margin", "auto");
            $(".onewidecenter").css("width", "100%").css("margin", "auto");
            $("#map_canvas").css("width", "100%").css("margin", "auto");
            $(" #dropdown_container").css("width", "100%").css("margin", "auto");
            google.maps.event.trigger(map, "resize");
            map.setCenter(new google.maps.LatLng(53.760861, -98.813876));
            map.setZoom(5);
        });
    }); // end page load

I have included the sample code above. Please pay special attention to my click event handler. As always, as suggestions on how best to remedy this would be greatly appreciated.

Thanks in advance, Michael

回答1:

jQuery AJAX methods are asynchronous. That means:

obj.success(function (data) {
  ecoli_rows = data['rows'];
}); // end sucess

Returns immediately but the callback function doesn't run until the ajax request completes.

This means that:

infoWindow.setContent(this.getHeader() + '' +
    this.getEcoliData() + '' + this.getAlgaeData());
infoWindow.open(map, this); //ajax callback hasn't fired here

opens the info window with the content BEFORE the ajax request completes.

To correct, you might do something like this:

In marker.getEcoliData:

obj = getEcoliData(this.beach_id);
return obj;
// move processing below this point to new method

And in the click event handler:

google.maps.event.addListener(marker, 'click', function () {
  var ajaxObj = this.getEcoliData();
  var marker = this;
  ajaxObj.done(function() {
    infoWindow.setContent(marker.getHeader() + '' +
        marker.afterGetEcoliData() + '' +
        this.getAlgaeData());
    infoWindow.open(map, this);
    $(".tabs").tabs({ selected: 0 });
  });

This is not a complete solution since you have two asynchronous calls happening. You could either chain them, or set some kind of counter to make sure that the callback only executes when both have completed.

An even better approach would be to immediately open the infowindow with some kind of information to tell the user that data is being loaded. Then after the requests complete, you simply update the infowindow content again (with a handle to the content element) to show the returned data.



回答2:

Thanks for the help with this. I managed to get this to work as expected. As it turned out I had to restructure the marker class so that two ajax requests weren't be returned an additional time.