Calling methods in RequireJs modules from HTML elements such as onclick handlers

34,399

Solution 1

One benefit from using AMD is to drop the need for namespaces. Trying to create them again with RequireJS will go against the patterns AMD promotes.

With regard to using main.js, this is only really appropriate when you have a single page app and all your code be reference from one place. You're free to make additional calls to require and load other modules as you need them.

Using your example from above, you could approach it this way:

foo.js

define(['jquery'], function($) {

    // Some set up 
    // code here

    // Return module with methods
    return {
        bar: function() {

        }
    }


});

page.js

require(['foo'], function(foo) {

    // jQuery loaded by foo module so free to use it
    $('.button').on('click', function(e) {
        foo.bar();
        e.preventDefault();
    });

});

Then in your page request the page.js file with require.

Using your example above:

require({
    // config stuff here
}, [ 'page' ]);

Or loading it in the page further down:

<script>
    require(['page']);
</script>

Some additional points

  • Using the pattern above, page.js could easily require many other modules to load other page related functionality.

  • Where before you would attach members to your global namespace, you now split that code into separate modules that can be re-used on any page. All without reliance on a global object.

  • Using require this way to attach events to your DOM elements will most likely rely on the DOM Ready module provided by RequireJS

Solution 2

You can also set the reference on javascript's window class.

At the bottom of the application module window.MyApi = MyApi;

<a class="button" href="#" onclick="MyApi.foo();"></a>

Solution 3

putting onclick="" inside your markup feels dirty -- mixing presentation with content. I'd recommend you add a <script> block and put the require in it, and once inside the callback, and inside another inner $(document).ready() if necessary then wire up your event handlers in the normal way: $('#node').click(...). If you can do this generically enough that it's applicable to multiple pages, then put it inside an external file that is minified, combined, and cached. But typically these things end up being page-specific, so a <script> tag at the bottom of the page is a good solution to avoid yet another external resource request.

Solution 4

Another solution is just use code like that (of course requirejs must be added to the page):

<input type="button" onclick="(function() { require('mymodule').do_work() })()"/>
Share:
34,399
HostileFork says dont trust SE
Author by

HostileFork says dont trust SE

(I say "do not trust SE" because it seems to me like the institutional knowledge that volunteers contribute to is incredibly fragile. I feel a strong sense of fragility every time I break out the credit card and buy a domain name. And watching elected moderators fall by the wayside over arguments over put-your-pronouns-in-your-profile makes me wonder if it's an accident that stackoverflow overtook expertsexchange.com (ha ha, expert sex change, wait, was that a joke in the first place?). How can these petty human issues destroy our collective knowledge about programming? What's with the status war over gender pronouns? Not like I knew who Monica was before, but how the hell did Shog9 get fired? How did this happen? And it's kind of like seeing how weak the entirety of the world is by virtue of electing Trump, we are all way...way...too...hackable.) Eh. Or, as I used to say: "Not actually "hostile", just a bit irate. :)" (A "hostile fork"--as many developers know--refers to when open source efforts diverge due to different ideas about where the code should be taken. I started my site intending to get to the bottom of "why we all can't just get along" as a bit of an SEO/keyword hack. It worked...try googling "hostile fork".) Until I figure out how to make everyone bring the best ideas to the table, I'm just blogging about software development. Long term I hope that people searching for "hostile fork x" will find my site and consider engagement instead of forking. Yet somehow it's easier to answer StackOverflow questions than make people get along. Who knew? And yes I drew the fork. I'm an artiste as well as a programmer. :P

Updated on March 02, 2020

Comments

  • HostileFork says dont trust SE
    HostileFork says dont trust SE about 4 years

    I'm changing a project from an "old" browser-style module structure to a "new" browser-or-server-side-javascript module structure with require.js.

    On the client I'm using an offsite hosted jQuery, so I started from the example they give in the "use priority config" technique of the README:

    <title>My Page</title>
    <script src="scripts/require.js"></script>
    <script>
    require({
        baseUrl: 'scripts',
        paths: {
            jquery: 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min',
            jqueryui: ...,
            ...
            ... // bunch more paths here
        },
        priority: ['jquery']
    }, [ 'main' ]);
    </script>
    

    This is actually working all right. But I'd like to export functionality from main to the HTML webpage itself. For instance:

    <a class="button" href="#" onclick="MyApi.foo();">
        <img src="foo.png" alt="foo" />Click for: <b>Foo!</b>
    </a>
    

    Before fitting into the AMD module pattern, I'd exposed functionality from my various files by creating a dictionary object in the global space:

    // main.js
    
    var MyApi = {};
    
    jQuery(document).ready(function($) {
        // ...unexported code goes here...
    
        // export function via MyApi
        MyApi.foo = function() {
            alert("Foo!");
        };
    });
    

    But I don't know what the right approach in require.js is. Is it okay to put in the HTML more require statements inside of <script> tags, and then name modules so that it can be used from within the webpage? Or should this always be done dynamically inside of main.js, like $('#foobutton').click(...)?