Jan Raak
Jan Raak

Reputation: 31

Different in google chrome and internet explorer

My application uses knockout.js custom elements. The load sequence of the viewmodel and template are different in google chrome and internet explorer.

In my web application I have defined a number of custom elements like:


   ko.components.register('account-management-me', {
        viewModel: {  require: 'Scripts/app/components/accountManagementMe/ViewModel' },
        template: { require: 'text!Scripts/app/components/accountManagementMe/' + language + 'View.html' }
    });

With Internet Explorer I observed the following load sequence:

  1. ViewModel.js
  2. enView.html

With Chrome I observed the following load sequence:

  1. enView.html
  2. ViewModel.js

Hence fields bound in the view from the ViewModel.js are undefined and an exception is thrown by knockout.

Is there a way to influence the load order?

Upvotes: 3

Views: 984

Answers (1)

Louis
Louis

Reputation: 151491

Is there a way to influence the load order?

Yes, if you register your component as a single module, as shown in the documentation, then you can make it so that your view model is dependent on your template and so your template will always be loaded before your view model.

Knockout is using RequireJS to load the view model and the template. As explained in the documentation, it issues a plain require call with the module names you to ko.components.register. For your code, the equivalent require calls would be:

require(['Scripts/app/components/accountManagementMe/ViewModel'], callback);
require(['text!Scripts/app/components/accountManagementMe/enView.html', callback);

These two calls cannot constrain the load order. It does not matter that .../ViewModel is first. (Actually, it could be second.) Both calls are asynchronous and can resolve in any order unless the modules use define to establish a dependency of one on the other. This is just how RequireJS works. Without an explicit dependency, the order is indeterminate and can vary due to browser internals, network conditions, etc.

To register your component as a single module, you'd do:

ko.components.register('account-management-me', 
  { require: 'Scripts/app/components/accountManagementMe/ViewModel' });

And the module referred above would contain something like:

define(['knockout', 'text!Scripts/app/components/accountManagementMe/enView.html'], function(ko, template) {
    function ViewModel() {
    }

    ViewModel.prototype.foo = function() { ... };

    return { viewModel: ViewModel, template: template };
});

In this example, I've made the template module name static string. You want to load different templates depending on the configured language but putting strings computed at run time in the dependencies of a define is not supported. You can make it work for some trivial cases but if you want to optimize your modules with r.js, it will choke on computed strings. To get support for languages, you should use the i18n plugin. Or something that provides similar functionality. There are a lot of questions on SO on how to use it which you can look at if you run into trouble setting up i18n.

Upvotes: 2

Related Questions