2

We have a page that appears to have been broken with the latest chrome update (to 84). There's a checkbox with an onclick event, that no longer fires. We're presented with an error: Uncaught TypeError: timeline.toggleWatcher is not a function

attached is the HTML calling this JavaScript function

<ul class="dropdown-menu dropdown-menu-right condensed-dropdown">
                    <li>
                        <a class="pos-rel" data-watcher-toggle-type="submitter" data-notify="submitter" data-selected="true" onclick="timeline.toggleWatcher('submitter')">
                        <span class="dropdown-toggle-icon">
                            <i class="fa fw fa-check-square"></i> 
                        </span>
                        <span class="history-filter-label">Submitter</span> </a>
                    </li>
                    <li>
                        <a class="pos-rel" data-watcher-toggle-type="analyst" data-notify="analyst" data-selected="false" onclick="timeline.toggleWatcher('analyst')">
                        <span class="dropdown-toggle-icon">
                            <i class="fa fw fa-square-o"></i> 
                        </span>
                        <span class="history-filter-label">Assigned Analyst</span></a>
                    </li>
                    <li>
                        <a class="pos-rel" data-watcher-toggle-type="watcher" data-notify="watcher" data-selected="true" onclick="timeline.toggleWatcher('watcher')">
                        <span class="dropdown-toggle-icon">
                            <i class="fa fw fa-check-square"></i> 
                        </span>
                        <span class="history-filter-label">Watchers</span></a>
                    </li>
                </ul>

Has timeline become a reserved word in JavaScript?

Jake
  • 21
  • 3

3 Answers3

2

It is not a reserved word. Also, it will work if you use window.timeline.dosomething.

The reason you are seeing this problem is because document now has a new property timeline.

Now you may wonder why this matters, you are not writing document.timeline but just timeline, right? Well, the reason is historical: To make writing inline event handlers simpler and shorter, some things are in their scope which are a bit unexpected today.

The details can be read in the HTML spec (check the instructions under "scope"). Also, this Stack Overflow answer explores this topic further.

You can imagine it as if your code is called within a number of nested with blocks:

  • with (document)
  • If the handler is on an element that is inside of a <form>: with (formElement)
  • with (element) (the element itself for which you write the handler)

This article illustrates it as follows:

Given the following markup:

<p onclick="self.alert(event);"></p>

The augmented scope chain, if written in ECMAScript, would look like:

function onclick(event) {
  with(document) {
    with(this.form) {
      with(this) {
        self.alert(event);
      }
    }
  }
}

As you can see, the issue is that in this context, document.timeline is accessible in your scope as just timeline, overriding the global variable with the same name.

The immediate solution is to use window.timeline as I wrote above, but going forward, it would be advisable to use addEventListener instead anyway, instead of writing inline handlers.

CherryDT
  • 25,571
  • 5
  • 49
  • 74
0

timeline is not a "reserved word", it's a property of Document:

https://developer.mozilla.org/en-US/docs/Web/API/Document/timeline

You should add event handlers programmatically rather than using inline attributes in your markup and relying on global variables, which will be shadowed by any new properties added to Document.

For example, this works fine:

<html>
    <head><title>Bug Test</title></head>
    <body>
        <button id="btn">Works</button>
        <script>
         
        var timeline = {
            dosomething: function(param){
                alert('doing something: '+param);
            }
        }
        
        document.querySelector('#btn').addEventListener('click', event => {
          timeline.dosomething("works");
        });
        </script>
    </body>

</html>
user229044
  • 232,980
  • 40
  • 330
  • 338
-1

After posting, did some more testing... It looks like timeline is in fact a reserved word now. See example HTML below:

<html>
    <head><title>Bug Test</title></head>
    <body>
        <button onclick="mgtest.dosomething('hello there')">Works</button>
        <button onclick="timeline.dosomething('hello there')">Does Not Work</button>
    </body>
    <script>
        var mgtest = {
            dosomething: function(param){
                alert('doing something: '+param);
            }
        }

        var timeline = {
            dosomething: function(param){
                alert('doing something: '+param);
            }
        }
    </script>
</html>
Jake
  • 21
  • 3