1

I have created a _layout.twig file which acts as my base to hold content on the page -> _layout.twig:

<!DOCTYPE html>
<html lang="{{ craft.app.language }}">
  <head>
    <meta content="IE=edge" http-equiv="X-UA-Compatible" />
    <meta charset="utf-8" />
    <title>
      {{ siteName }}
    </title>
    <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
      name="viewport" />
    <link rel="stylesheet"
      href="https://unpkg.com/leaflet@1.4.0/dist/leaflet.css"
      integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA=="
      crossorigin="" />
    {% includeCssFile siteUrl ~ 'assets/css/style.css' %}
  </head>
  <body>
    {% include '_includes/nav' %}
    <div>
      {% block content %}

      {% endblock %}
    </div>
    <footer class="main-footer">
      <div class="footer-wrapper">
        {{ exampleInformation.exampleDescription|markdown }}
        <p>
          &copy; {{ now|date('Y') }}, <a href="https://craftcms.com">Lorem Ipsum</a>
        </p>
      </div>
    </footer>
    <script src="https://unpkg.com/leaflet@1.4.0/dist/leaflet.js"   integrity="sha512QVftwZFqvtRNi0ZyCtsznlKSWOStnDORoefr1enyq5mVL4tmKB3S/EnC3rRJcxCPavG10IcrVGSmPh6Qw5lwrg==" crossorigin=""></script>
    {% includeJsFile siteUrl ~ 'assets/js/scripts.js' %}
  </body>
</html>

Through the control panel in craft CMS I created an entry that contains a table that has a series of coordinates (longitude and latitude values) and a lightswitch to toggle it on or off, along with some other general information for each entry that is created e.g. title, date, image, etc. on a separate tab.

The _entry.twig page extends _layout.twig -> _entry.twig:

{% extends '_layout' %}

{% set featureImage = {
  mode: 'crop',
  width: 600,
  height: 600,
  quality: 90
} %}

{% block content %}
  <div class="entry__container">
    <div class="entry__wrapper">
      <div class="entry__title">
        <h1>
          {{ entry.title }}
        </h1>
      </div>

      <div class="entry__image">
        {% if entry.featureImage|length %}
          {% for image in entry.featureImage.all() %}
            <img src="{{ image.getUrl(featureImage) }}"
              alt="{{ image.title }}" />
          {% endfor %}
        {% endif %}
      </div>

      <div>
        {% for block in entry.exampleContent.all() %}
          <div class="entry__description">
            {% if block.type == 'text' %}
              {{ block.text }}
            {% elseif block.type == 'image' %}
              {% for image in block.image.all() %}
                <img src="{{ image.url }}" alt="{{ image.title }}" />
              {% endfor %}
            {% endif %}
          </div>
        {% endfor %}
      </div>

      {# display post categories #}
      {% if entry.exampleCategories|length %}
        <div class="entry__category">
          <p>
            Categories
          </p>
          {% for category in entry.exampleCategories.all() %}
            <a href="{{ category.url }}">{{- category.title -}}</a>
          {% endfor %}
        </div>
      {% endif %}

      {# display table info #}
      {% if entry.lotInfo|length %}
        {# Create a Twig array to store locations #}
        {% set locations = [] %}
        {% for row in entry.lotInfo %}
          {% if row.createNewEntry == '1' %}
            {# Add an entry in the locations Twig array #}
            {% set locations = locations|merge([{ lat: row.latitude, lng: row.longitude }]) %}
          {% endif %}
        {% endfor %}

        {% if locations is not empty %}
          {# Create a JS block at the end of <body> #}
          {% js %}
            {# call the JS function addToMap, passing it a json_encoded version of the locations Twig array #}
            addToMap({{ locations|json_encode|raw }})
          {% endjs %}
        {% endif %}
      {% endif %}
      {# end table info #}
      {% js %}
      <script type="text/javascript">
        var coordinates = {{ locations | json_encode | raw }};
        console.log(coordinates);
      </script>
      {% endjs %}
    </div>
  </div>
{% endblock %}

I was able to put together this small section in _entry.twig which looks at the table and if the lightswitch is set to 1, it outputs the corresponding latitude and longitude values in the row:

{# display table info #}
      {% if entry.lotInfo|length %}
        <div class="entry__coordinate">
          <ul>
            {% for row in entry.lotInfo %}
              {% if row.createNewEntry == '1' %}
                <li>
                  <div data-latCoordinate="{{ row.latitude }}"
                    id="latCoordinate">
                    {{ row.latitude }}
                  </div>,<div data-lngCoordinate="{{ row.longitude }}"
                    id="lngCoordinate">
                    {{ row.longitude }}
                  </div>
                </li>
              {% endif %}
            {% endfor %}
          </ul>
        </div>
      {% endif %}
      {# end table info #}

These values are currently displaying on the front end entry page which will show the coordinates depending on which lightswitch toggle is active- which has allowed me to ensure that it is pulling the correct coordinates corresponding to the correct information.

Now, I have an external js file linked which lives in local/craft/assets/js/*.js and contains this script -> scripts.js:

//Set initial map view

var map = L.map('map', { scrollWheelZoom: false }).setView(
  [50.4205, -104.52],
  15,
)

//Initialize the tilemap
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  maxZoom: 19,
  minZoom: 14.5,
  attribution:
    '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
}).addTo(map)

// Set location array
var locations = [{ lat: 'SOME LATITUDE COORDINATE', lng: 'SOME LONGITUDE COORDINATE' }]

function addToMap(locationArray) {
  //Iterate through array object
  ;[].forEach.call(locationArray, function (location) {
    var marker = L.marker([location.lat, location.lng]).addTo(map)
  })
}
//Show markers
addToMap(locations)

Currently, this script will create a leaflet/osm map and then based on:

// Set location array
var locations = [{ lat: '(SOME LATITUDE VALUE)', lng: '-(SOME LONGITUDE VALUE') }];

will output a marker to the map (currently only outputs a marker if I manually insert lat and long coordinates) which lives in my index.twig template file -> index.twig:

{% extends '_layout' %}
{% set posts = craft.entries.section('example').all() %}
{% block content %}
  <div class="background-test">
    <div id="map"></div>
  </div>
  <div class="main-container">
    <div class="main-wrapper">
      <h1 class="example-title">
        Some Title
      </h1>
      <div class="category-list">
        {% set entries = craft.entries.limit(null) %}
        {% for category in craft.categories.relatedTo(entries).order(
          'title asc'
        ) %}
          {% set entryCount = entries.relatedTo(category).total() %}
          <a href="{{ category.url }}">
            {{- category.title -}}<span class="count-number">({{ entryCount }})</span>
          </a>
        {% endfor %}
      </div>
      {% include '_includes/listing' with {
        posts: posts
      } only %}
    </div>
  </div>
{% endblock %}

What would be the best way to somehow use the

{{ row.latitude }}, {{ row.longitude }}

variables from my _entry.twig file in my existing scripts.js file to place a marker(s) on the map which lives on the index.twig page? I am still new to Craft and more so with Twig so I am still in the process of learning these things.

My folder structure is:

/assets
   /css
   /js
      scripts.js
/templates
   /includes
   /blog
      _category.twig
      _entry.twig
       index.twig
   _layout.twig
   index.html

Any help would be greatly appreciated!

Thank you
2

You can't and it's a good thing. Your external JS file is meant to be static so it can be cached by the visitors' browser.

One way to achieve what you want is to only define the addToMap() function in your external JS file and call this function from your template, passing it the locations to display.

Here's how you can do this from your template:

{% if entry.lotInfo|length %}
  {# Create a Twig array to store locations #}
  {% set locations = [] %}
  {% for row in entry.lotInfo %}
    {% if row.createNewEntry == '1' %}
      {# Add an entry in the locations Twig array #}
      {% set locations = locations|merge([{ lat: row.latitude, lng: row.latitude }]) %}
    {% endif %}
  {% endfor %}

  {% if locations is not empty %}
    {# Create a JS block at the end of <body> #}
    {% js %}
      {# call the JS function addToMap, passing it a json_encoded version of the locations Twig array #}
      addToMap({{ locations|json_encode|raw }})
    {% endjs %}
  {% endif %}
{% endif %}

Reference:

6
  • Thank you for the in-depth response- I am now getting a "Variable "location" does not exist." pointing to this line " {% set locations = location|merge([{ lat: row.latitude, lng: row.latitude }]) %" I will review the references you provided but if you have any other ideas it would be greatly appreciated, I am having some difficulty wrapping my head around Twig. – Gideon B Oct 5 '20 at 15:34
  • This is a typo, sorry about that. It should be locations|merge. I just edited my answer to correct the code. – nstCactus Oct 5 '20 at 15:59
  • Thank you, I made the change and although the _entry.twig page loaded this time, the markers were still not output to the map on the _layout.twig, I read through your references above and I think I am having difficulty with how Twig and Javascript work together. I have an external script (./web/scripts.js) which contains the addToMap function linked in the _layout.twig file and _entry.twig is an extension of _layout.twig. So although the page has loaded, I can't help but feel there is something I am not grasping that puts it all together. I appreciate your help with this. – Gideon B Oct 5 '20 at 17:54
  • I guess the part I am most confused on is this part "define the addToMap() function in your external JS file and call this function from your template, passing it the locations to display." I am no longer getting any errors but the function in my external script is not outputting anything to the map on the _layout.twig page? Any clarification on this part wouild be greatly appreciated. – Gideon B Oct 5 '20 at 19:42
  • I cannot help you much more without seeing the content of your layout.twig and entry.twig, or even the rendered page source. You can start by having a look in your JS console to see if there are any errors there. Also make sure that, by the time the addToMap() function is called, the JS file in which its defined has already been loaded. – nstCactus Oct 5 '20 at 23:31

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.