1

I have encountered a problem numerous times where I cannot get an onclick function in an external js file to work in my Laravel projects. Here is an example from my page source:

<button onclick="testMe()">test</button>
<script type="text/javascript" src="http://[myurl]/js/jobs.js"></script>

Inside jobs.js:

function testMe() {
    console.log('i have appeared');
}

This example is from having my script tag be called AFTER I call on click. I have also tried adding the script BEFORE I call on click. I have also tried adding it to my <head>, but the following error still persists:

Uncaught ReferenceError: testMe is not defined at HTMLButtonElement.onclick

I understand that it cannot find the function, but what else can I try to problem solve this? Is it possible to call onclick to an external JS file?

Edit:

Here is the relevant line of my webpack file:

.js('resources/js/jobs/jobs.js', 'public/js/jobs.js')

How I actually call it (opposed to how it looks viewing the page src):

<script type="text/javascript" src="{{ asset('js/jobs.js') }}"></script>

This is also definitely being brought in because I have a console log above the function, which is being logged to the console.

gbalduzzi
  • 9,356
  • 28
  • 58
party-ring
  • 1,761
  • 1
  • 16
  • 38
  • 2
    Do you use laravel mix or some processor do produce the final `jobs.js` or you simply include the `jobs.js` you wrote? – gbalduzzi Aug 24 '20 at 14:13
  • I use webpack to compile it all, so it actually looks like this: `` in my text editor - the file gets compiled though as I can navigate to "http://[myurl]/js/jobs.js" to see the js file there – party-ring Aug 24 '20 at 14:15
  • try adding `console.log('jobs are working')` in your javascript file outside of every function and check that when you load the page the text `jobs are working` appears on console – gbalduzzi Aug 24 '20 at 14:15
  • Your given code working here too – STA Aug 24 '20 at 14:15
  • I've got that already, the console is logging out my text outside of the function, so I know the file is being read – party-ring Aug 24 '20 at 14:16
  • 1
    Just want to add that you should use `mix('js(jobs.js')` to load your file instead of `asset` to avoid problems in case you want to version your files in production – gbalduzzi Aug 24 '20 at 14:30

2 Answers2

9

When you use laravel mix or webpack, those pre-processor create a new 'scope' for every file to avoid naming conflict between different files.

So, the function testMe() is declared inside the jobs.js file, but it is not accessible from the outer scope.

You have 2 options:

  1. Attach the function testMe to the outer scope.

In a browser, the 'root' scope is the window object. So you can attach your function to the window object, and it will be accessible from your HTML elements:

function testMe() {
    console.log('i have appeared');
}
window.testMe = testMe

This is probably the easiest way to get it working, but if you have a lot of functions it would pollute the whole scope

  1. Attach the handler from javascript instead of using onClick html attribute.

Instead of using the onClick HTML attribute, you can set testMe as the click handler from the javscript file itself:

<button id="test-button">test</button>
function testMe() {
    console.log('i have appeared');
}

document.getElementById('test-button').addEventListener('click', testMe)
gbalduzzi
  • 9,356
  • 28
  • 58
  • Okay, thank you - that explains a lot. Would an event listener be practical in a case where there is a button that is repeated x times (every row of table) which has data to pass in? Or would an onclick make more sense seeing as I need to pass in arguments? – party-ring Aug 24 '20 at 14:26
  • it is generally better to use an event listener in order to don't mix javascript logic between your blade files and the javascript file itself – gbalduzzi Aug 24 '20 at 14:29
  • i am facing same problem with laravel8 and mix. first method window.testMe = testMe is working fine, but second method of eventhander is not working after compiling. any guide – user198926 Oct 12 '22 at 04:55
1

The external JS file needs to be loaded before you call the method. There is no guarantee that the external JS file will be loaded at the time of clicking the button, so creating a local wrapper may be a better idea. The local wrapper should check if the remote script has loaded (see this link to see how to do it.