ndabas / toc

Table of Contents jQuery Plugin - A minimal, tiny jQuery plugin that will generate a table of contents, drawing from headings on the page.
https://ndabas.github.io/toc/
Apache License 2.0
84 stars 24 forks source link

Uncaught TypeError: $(...).toc is not a function #16

Closed HowcanoeWang closed 4 years ago

HowcanoeWang commented 4 years ago

Hello, when I use

<script src="https://cdn.bootcss.com/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/ndabas/toc/jquery.toc.js"></script>

in the head part to import this package, and using the following to dynamically generate TOC

function generateTOC() {
    //get the <p>[toc]</p>
    var ptoc = $("p").filter(function(index){
        return $(this).text() == '[toc]';
    })
    // if [toc] exist
    if (ptoc.length == 1) {
        // replace <p>[toc]</p> to the following part
        ptoc.replaceWith($('<div class="toc"><ul id="tocjs"></ul></div>'));
        $("#tocjs").toc({content: "article", headings: "h1,h2,h3"});
    };
};

it sometimes works in a local testing environment, however, when pushed to github pages, it always raises this error.

It may due to my poor javascript skills rather than your package problem, and I am not quite sure if it is correct to use it in such a function.

HowcanoeWang commented 4 years ago

The full error is

page.html?id=19:147 Uncaught TypeError: $(...).toc is not a function
    at generateTOC (page.html?id=19:147)
    at Object.success (page.html?id=19:233)
    at c (jquery.min.js:2)
    at Object.fireWith [as resolveWith] (jquery.min.js:2)
    at l (jquery.min.js:2)
    at XMLHttpRequest.<anonymous> (jquery.min.js:2)
ndabas commented 4 years ago

This is likely caused by your code executing before the jquery.toc.js file has loaded. You can try using the jQuery load event to execute your code.

If that doesn't help, please provide a link to the page in question, and I can take a look.

HowcanoeWang commented 4 years ago

PS: I previously use file/// to do the local test which is not a correct way. Then I use python to run a localhost and now the local environment performs the same as the online environment (raise .toc() is not a function error).

I tried it again, it may not the jquery.toc.js not loaded error because if I use that function directly:

<div id="page-placeholder">
    <p>[toc]</p>
    <h1>esdgsefd</h1>
    <script type="text/javascript">
        updateTOC();
    </script>
<div>

it functioned all well.

However, the problem may be, my page contents were dynamically generated via markdown file:

var converter = new showdown.Converter();
$.get("md/000.md", function( md ) {
    html = converter.makeHtml(md);
    $('#page-placeholder').html(html);

    // use TOC function inside jQuery raise this error
    generateTOC();
},'text');

// use TOC function outside jQuery don't raise this error but make no sense.
//generateTOC();

It seems $.get() is the last step to run in javascript, if I move generateTOC() outside $.get() block, it isn't meaningful because the article hasn't been loaded yet and nothing will be generated.

I think the problem may be something like, how to use $().toc() as a global function inside a JQuery function?

I understand it now changed to another jQuery problem and not related to this package issue. I am very appreciated for your patience if you could help me solve this!

ndabas commented 4 years ago

I was able to find the page in question from your GitHub profile (https://www.sigmameow.com/blog/page.html?id=19), and took a look at the source.

The problem is that you have added jQuery twice on the page: once in the HEAD, and then again near the bottom of the page: <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.slim.min.js"></script>.

What's happening is that:

  1. jQuery loads the first time.
  2. jquery.toc.js loads and adds itself to the loaded jQuery instance.
  3. jQuery.slim.min,js loads, and clobbers the loaded jQuery instance.
  4. Your code runs, and this time, the jQuery plugins that were loaded earlier are no longer available.

The simple fix is to remove the SCRIPT tag at the bottom which is referencing jquery.slim.min.js.

Let me know if this works for you.

HowcanoeWang commented 4 years ago

Yes, you are correct, I simply copied the bootstrap template and haven't realized the jquery.slim.min.js has already existed at the end of that page!

Thank you a lot for your patience to go through these "trash" code of my website!

ndabas commented 4 years ago

No worries, always happy to help!