Ad

'TypeError: JQuery Is Undefined' After Partial Update - OctoberCMS

- 1 answer

I have an OctoberCMS component that has an AJAX Handler for onSelectTag, but when the #posts HTML element is updated (rendered) with the blogPosts/postList partial, the following error is thrown:

TypeError: jQuery is undefined

tagList.htm:

{% for tag in tags %}
<button type="button" class="list-group-item" data-request="onSelectTag" data-request-data="tagId: {{ tag.id }}">{{ tag.name }}</button>
{% endfor %}

onSelectTag() AJAX Handler:

public function onSelectTag()
{
    $this->page['posts'] = Post::all();

    // below is where the partial updates / renders
    return [
        '#posts' => $this->renderPartial('blogPosts/postList.htm')
    ];
}

blogPosts/postList.htm:

[viewBag]
==
{% if posts is empty %}
{% set posts = __SELF__.posts %}
{% endif %}
{% if not hideFeatured is defined %}
  {% set hideFeatured = __SELF__.property('hideFeatured') %}
{% endif %}
{% set pageSlug = post.slug %}
{% if not hideFeatured %}
<div class="row" id="highlight">
  <div class="col-lg-8">
    <div class="card" id="featured">
      <a target="_blank" rel="nofollow noreferrer" href="{{ posts.first.url }}">
        {% if posts.first.featured_images.count %}
          <img src="{{ posts.first.featured_images[0].path }}" alt="{{ posts.first.title }}" class="card-img-top">
        {% endif %}
        {% if posts.first.categories.count %}
            <p class="card-header">
            {% for category in posts.first.categories %}
                <a target="_blank" rel="nofollow noreferrer" href="{{ category.url }}" class="badge badge-secondary">{{ category.name }}</a>
            {% endfor %}
            </p>
        {% endif %}
        <div class="card-body bg-success text-white">
            <h5 class="card-title"><a target="_blank" rel="nofollow noreferrer" href="{{ posts.first.url }}" class="text-white">{{ posts.first.title | upper }}</a> <small class="float-right">{{ posts.first.published_at|date('F d, Y') }}</small></h5>
            <hr class="tagline"/>
            <p class="card-text">{{ posts.first.summary|striptags|length > 150 ? posts.first.summary|striptags|slice(0, 150) ~ '...' : posts.first.summary|striptags}}</p>
        </div>
        <div class="card-footer text-muted">
          <span><i class="fas fa-tags" aria-hidden="true"></i> Tags: </span>
          {% if posts.first.tags.count %}
              {% for tag in posts.first.tags %}
                  <span class="badge badge-primary">{{ tag.name }}</span>
              {% endfor %}
          {% else %}
              <span class="badge badge-danger">No Tags</span>
          {% endif %}
        </div>
      </a>
    </div>
  </div>
    <div class="col-lg-4">
        <div class="embed-responsive embed-responsive-16by9">
            {% partial 'youtube' %}
        </div>
        <br />
        <div class="card">
            <h4 class="card-header">SUBSCRIBE TO OUR NEWSLETTER</h4>
            <div class="card-body">
                {% partial 'mail-chimp' %}
            </div>
        </div>
    </div>
</div>
{% endif %}
<br />
<div class="card-columns">
{% for post in posts %}
    {% if loop.first and not hideFeatured %}
    <!-- First Post is Featured -->
    {% elseif post.slug != pageSlug %}
    <a target="_blank" rel="nofollow noreferrer" href="{{ url('/blog/post/' ~ post.slug) }}">
        <div class="card">
            {% if post.featured_images.count %}
            <img src="{{ post.featured_images[0].path }}" class="card-img-top" alt="{{ post.title }}">
            {% endif %}
            <div class="card-body">
                <h4 class="card-title text-center"><a target="_blank" rel="nofollow noreferrer" href="{{ post.url }}">{{ post.title | upper }}</a></h4>
                <p class="card-subtitle text-muted text-center">{{ post.published_at|date('F d, Y') }}</p>
                {% if post.categories.count %}
                    {% for category in post.categories %}
                    <a target="_blank" rel="nofollow noreferrer" href="{{ url('/blog/category/' ~ category.slug) }}" class="badge badge-success">{{ category.name }}</a>
                    {% endfor %}
                {% endif %}
                <hr class="tagline" />
                <div class="card-text">{{ post.summary|striptags|length > 50 ? post.summary|striptags|slice(0, 50) ~ '...' : post.summary|striptags}}</div>
            </div>
            <div class="card-footer text-muted">
                <span><i class="fas fa-tags" aria-hidden="true"></i> Tags: </span>
                {% if post.tags.count %}
                    {% for tag in post.tags %}
                    <span class="badge badge-primary">{{ tag.name }}</span>
                    {% endfor %}
                {% else %}
                <span class="badge badge-danger">No Tags</span>
                {% endif %}
            </div>
        </div>
    </a>
    {% endif %}
{% else %}
<h3 class="no-data">{{ noPostsMessage }}</h3>
{% endfor %}
</div>

<div class="row">
{% if posts.lastPage > 1 %}
    <ul class="pagination">
        {% if posts.currentPage > 1 %}
            <li><a target="_blank" rel="nofollow noreferrer" href="{{ this.page.baseFileName|page({ (pageParam): (posts.currentPage-1) }) }}">&larr; Prev</a></li>
        {% endif %}

        {% for page in 1..posts.lastPage %}
            <li class="{{ posts.currentPage == page ? 'active' : null }}">
                <a target="_blank" rel="nofollow noreferrer" href="{{ this.page.baseFileName|page({ (pageParam): page }) }}">{{ page }}</a>
            </li>
        {% endfor %}

        {% if posts.lastPage > posts.currentPage %}
            <li><a target="_blank" rel="nofollow noreferrer" href="{{ this.page.baseFileName|page({ (pageParam): (posts.currentPage+1) }) }}">Next &rarr;</a></li>
        {% endif %}
    </ul>
{% endif %}
</div>

<!-- Modal -->
<div class="modal fade" id="subscribeModal" tabindex="-1" role="dialog" aria-labelledby="subscribeModalTitle" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered modal-md-sm" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="subscribeModalTitle">SUBSCRIBE TO OUR NEWSLETTER</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        {% partial 'mail-chimp' %}
      </div>
    </div>
  </div>
</div>

<div class="accordion subscribe-footer" id="accordionExample">
    <div class="card">
        <div class="card-header text-center" id="headingOne">
            <h5 class="mb-0">
                <button class="btn btn-link" type="button" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
                    SUBSCRIBE TO OUR NEWSLETTER <i class="fas fa-chevron-up subscribe-chevron" aria-hidden="true"></i>
                </button>
            </h5>
        </div>

        <div id="collapseOne" class="collapse hide" aria-labelledby="headingOne" data-parent="#accordionExample">
          <div class="card-body">
            {% partial 'mail-chimp' %}
          </div>
        </div>
    </div>
</div>
<div class="accordion subscribe-footer-mobile" id="accordionExample">
    <div class="card">
        <div class="card-header text-center" id="headingOne">
            <h5 class="mb-0">
                <button class="btn btn-link" type="button" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
                    SUBSCRIBE <i class="fas fa-chevron-up subscribe-chevron" aria-hidden="true"></i>
                </button>
            </h5>
        </div>

        <div id="collapseOne" class="collapse hide" aria-labelledby="headingOne" data-parent="#accordionExample">
          <div class="card-body">
            {% partial 'mail-chimp' %}
          </div>
        </div>
    </div>
</div>

I don't think the reference or load order is the issue because I've tried moving the jQuery reference and the {% framework extras %} reference and the {% scripts %} reference to many different parts of the page, and nothing changed either way.

My theory:

I think that when the partial updates, it's messing up the jQuery Framework call or something. It's odd because jQuery functions still work like:

$('#tagFilter').on('input', function() {
    console.log("TEST");
});

That still works, but functions defined by the OctoberCMS AJAX framework like $.request(...) do not work. I'm not sure why this is happening though.

Ad

Answer

I read your question again and noticed that you seem to be including the jquery library but don't show the layout code.

I have also ran into this problem. Multi-depth ajax doesn't work and breaks the content from using the whole dom. It might have something to do with the life cycles of partials.


Leaving this for anyone who was a fool like me in the beginning.

{{ framework extras }} doesn't actually load the jquery library. Here is the default template code for Octobercms. Referenced here in the docs.

        <!-- Scripts -->
        <script src="{{ 'assets/vendor/jquery.js'|theme }}"></script>
        <script src="{{ 'assets/vendor/bootstrap.js'|theme }}"></script>
        <script src="{{ 'assets/javascript/app.js'|theme }}"></script>
        {% framework extras %}
        {% scripts %}

I am calling <script src="{{ 'assets/vendor/jquery.js'|theme }}"></script> in the head of my layout which connects to a minimized and compressed version of some jquery.

Also the {% scripts %} is how you want to handle inserted scripts. Referenced here in the docs.

Ad
source: stackoverflow.com
Ad