3
votes

I'm trying to use RequireJS to add the references to my jQuery validation script files. I have 3 script files instead of the usual 1:

  1. jquery.validate - The jquery validation library
  2. jquery.validate.unobtrusive - This adds unobtrusive validation to the jquery validation library (so you can use data attributes and it automatic wires them up). This depends on jquery.validate
  3. jquery.validate.custom - This add my own custom unobtrusive validation methods and depends on jquery.validate.unobtrusive

I have setup the following configuration:

require.config({
    paths: {
        'jquery': 'Scripts/jquery-1.8.3.min',
        'jquery.validate': 'Scripts/jquery.validate.custom'
    },
    shim: {
        'Scripts/jquery.validate': ['jquery'],
        'Scripts/jquery.validate.unobtrusive': ['jquery', 'Scripts/jquery.validate'],
        'Scripts/jquery.validate.custom': ['jquery', 'Scripts/jquery.validate.unobtrusive']
    }
});

Now I have the following module:

define(['jquery', 'jquery.validate'], function($) {
    alert('Yey!');
});

However an error is thrown in the jquery.validate.custom file telling me the unobtrusive dependency has not been injected. After some debugging with the browser tools and looking at the network tab I can see it successfully downloads the jquery.validate.custom.js and jquery.validate.js files but it doesn't even try to download the jquery.validate.unobtrusive.js file.

I'd appreciate it if someone could show me what I am doing wrong. Thanks

Edit:

I have now tried:

require.config({
    paths: {
        'jquery': 'Scripts/jquery-1.8.3.min',
        'jquery.validate': 'Scripts/jquery.validate.custom'
    },
    shim: {
        'Scripts/jquery.validate': ['jquery'],
        'Scripts/jquery.validate.unobtrusive': ['jquery', 'Scripts/jquery.validate'],
        'jquery.validate': ['jquery', 'Scripts/jquery.validate.unobtrusive']
    }
});

And it works correctly. I also tried the following as I think it looks better:

require.config({
    paths: {
        'jquery': 'Scripts/jquery-1.8.3.min',
        'jquery.validate': 'Scripts/jquery.validate.custom',
        'jquery.validate.core': 'Scripts/jquery.validate',
        'jquery.validate.unobtrusive': 'Scripts/jquery.validate.unobtrusive'
    },
    shim: {
        'jquery.validate.core': ['jquery'],
        'jquery.validate.unobtrusive': ['jquery', 'jquery.validate.core'],
        'jquery.validate': ['jquery', 'jquery.validate.unobtrusive']
    }
});

But this gives a timeout error.

If anyone could explain why the second solution doesn't work that would be great. Thanks

2

2 Answers

1
votes

You'll need to fix only one key in your config. Change this line:

'Scripts/jquery.validate.custom': ['jquery', 'Scripts/jquery.validate.unobtrusive']

With following:

'jquery.validate': ['jquery', 'Scripts/jquery.validate.unobtrusive']

And everything will work. This is because if you're using jquery.validate as a path you'll need to use same name in shim config to make all dependencies work correctly.

2
votes

I believe the keys in the shim should match the names that you are require'ing in your module. Also I think it confuses the issue to use the name jquery.validate but then map it to custom.

To me the following structure would be more intuitive:

require.config({
    paths: {
        jquery: 'Scripts/jquery-1.8.3.min',
        jquery_validate: 'Scripts/jquery.validate'
        jquery_validate_unobtrusive: 'Scripts/jquery.validate.unobtrusive'
        jquery_validate_custom: 'Scripts/jquery.validate.custom'
    },
    shim: {
        jquery: {
           exports: ['jQuery', '$']
        },
        jquery_validate: ['jquery'],
        jquery_validate_unobtrusive: ['jquery_validate'],
        jquery_validate_custom: ['jquery_validate_unobtrusive']
    }
});

And then in your module, request the custom file:

define(['jquery', 'jquery_validate_custom'], function($) {
    alert('Yey!');
});

EDIT: thinking more about your original config and why it doesn't work: the issue you have is that you are trying to intersperse the use of full paths with module aliases in the shim section. RequireJS does not appear to work this way. It seems to be a one way resolution process:

Module names requested --> expand to any additional modules from shim config --> load the actual files based on path mapping

Whereas what you are trying to do is:

Module names requested (jquery.validate) --> resolve to actual files based on path mapping (jquery.validate.custom) --> expand to any additional modules from shim config --> resolve paths again

So for example, this works fine:

require.config({
  paths: {
    module1: 'module1file',
    module2: 'module2file',
    module3: 'module3file'
  },
  shim: {
    module3: ['module2'],
    module2: ['module1']
  }
});

require(['module3'], function( ) {
});

But this does not:

require.config({
  paths: {
    module1: 'module1file',
    module2: 'module2file',
    module3: 'module3file'
  },
  shim: {
    module3: ['module2'],
    module2file: ['module1']
  }
});

require(['module3'], function( ) {
});