3

Google Maps for Craft outputs data into script tags to add markers to map with Javascript. Everything works great until a user goes to cache the output of an entries loop. It works upon first page load, but all subsequent page loads do not contain any of the JS at the bottom of the page as it should.

Here is a simple example to duplicate this issue. I am not sure what to do about it. In my mind, there should be a way to output JS that can be cached and output to the page without the query running.

{% set options = {
    id: 'map', 
    width: '400px', 
    height: '300px',
    clustering: true
} %}

{{ craft.googleMaps.map(options) }}

{% cache %}

    {% for entry in craft.entries.section('news') %}

        {{ craft.googleMaps.data('map', entry.map) }}

        test<br>

    {% endfor %}

{% endcache %}

Within my add-on all the methods that use includeJs behave the same way. But this is just a simple example of what I am doing. I just instantiate an object with some data and include it in the JS.

 craft()->templates->includeJs('new GoogleMaps.MapData('.$id.','.$data->toJson().','.$this->jsonEncode($options).');');

For additional information you can see it here in this support thread on the Github repo.

https://github.com/objectivehtml/Google-Maps-for-Craft/issues/12

3

That’s a tricky one, because right now the {% cache %} tag is only focussed on the actual HTML that gets output between its tags, but when you include Javascript using TemplatesService::includeJs, etc., that’s actually queuing up the Javascript to be output later on.

So, the trick here will be to make sure any JS that is included within the {% cache %} tag is also output within the {% cache %} tag:

{% cache %}
    {% for entry in craft.entries.section('news') %}

        {{ craft.googleMaps.data('map', entry.map) }}

        {# Output any queued-up JS #}
        {{ getFootHtml() }}

    {% endfor %}
{% endcache %}

This isn’t a perfect solution because that tag will also output any Javascript that was already queued up before the {% cache %} tag. If there is any, then it will end up getting output twice on requests where the {% cache %} tag already has cached HTML to return. Might be something we can address in a future update though.

| improve this answer | |
  • Thanks for the reply. I would definitely be interested in a little cleaner solution if it's possible. Let me know if I can be any help with testing or anything. This is definitely a unique use case in that most plugins won't use scripts in this manner, but given the nature of Google Maps, this is really the best way to handle it. – Justin Kimbrell Oct 1 '14 at 16:46
2

I am posting this answer in addition to Brandon's. His answer is "correct", but this answer shows the correct code to get the caching using the method Brandon mentioned. Like he said, all the JS that is cached must be included inside the cache tags. So if one wants to cache the output of a map, you must use code similar to the following:

Note, the entire map and loop are included in the cache, not just the loop. If you the map isn't included in the cache, you will get a JS error saying the Google Maps API has been instantiated twice (which breaks the whole thing).

{% cache %}

    {% set options = {
        id: 'map', 
        width: '400px', 
        height: '300px',
        clustering: true
    } %}

    {{ craft.googleMaps.map(options) }}

    {% for entry in craft.entries.section('news') %}

        {{ craft.googleMaps.data('map', entry.map) }}

        {{ getFootHtml() }}

    {% endfor %}

{% endcache %}
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.