3

I'm wondering if there's another way of using templates in knockout.js without having to use require.js to load them dynamically.

It adds around 20Kb after minification more to the site and it seems we are loading quite a big library to do something that probably wouldn't need as much code behind it.

This is what I'm doing now:

ko.components.register('menu', {
    viewModel: { instance: mm.viewModel },
    template: { require: 'text!views/menu.html' },
});

To do so I had to include require.js in my project and requrie text`:

<script type="text/javascript">
    requirejs.config({
        paths: {
            text: 'bower_components/text/text'
        },

        urlArgs: "v=" + new Date().valueOf()

    });
</script>
Alvaro
  • 40,778
  • 30
  • 164
  • 336
  • Did you check out this documentation page? http://knockoutjs.com/documentation/component-loaders.html#custom-component-loader Seems to me that you'll have to implement the `loadTemplate` method to fetch the html from the server... – user3297291 Jun 28 '16 at 16:07
  • 1
    Here is an article that I wrote a while back with some options: https://www.safaribooksonline.com/blog/2014/01/31/using-external-templates-knockout-js/. Using a string-based template engine with a build step to bundle your templates is a possible option that I have used in the past. – RP Niemeyer Jun 28 '16 at 16:17

2 Answers2

1

I ended up getting the file from the server side with my own call.

In node (but this can be done in PHP or any other language as well), I added a route to retrieve the requested file:

router.get('/loadFile/', function(req, res, next){
    var params = req.query;
    var demo = express.static(path.join(res.locals.virtualDirPath, 'public'));

    fs.readFile( __dirname + '/../public/elements/' + params.filename, "utf-8", function read(err, data) {
        if (err) {
            throw err;
        }

        // Invoke the next step here however you like
        return res.send(data);

        processFile(); 
    });
});

Then I created my own custom component loader in the Javascript side as detailed in the docs.

var templateFromUrlLoader = {
    loadTemplate: function(name, templateConfig, callback) {
        var newUrl = url + 'others/loadFile/';
        var params = { 'filename' : templateConfig.filename };

        if (templateConfig.filename) {
            // Uses jQuery's ajax facility to load the markup from a file
            $.get(newUrl, params, function(markupString) {
                // We need an array of DOM nodes, not a string.
                // We can use the default loader to convert to the
                // required format.
                ko.components.defaultLoader.loadTemplate(name, markupString, callback);
            });
        } else {
            // Unrecognized config format. Let another loader handle it.
            callback(null);
        }
    }
};

// Registering it
ko.components.loaders.unshift(templateFromUrlLoader);

This way I saved myself from having to load 84Kb of require.js for this simple task. Plus I'm not limited this way to the use of require.js and I can use a single combined and minified file for production environments.

Also, I'm in total control over the caching of the returned templates, which used to cause me problems when using require.js.

Community
  • 1
  • 1
Alvaro
  • 40,778
  • 30
  • 164
  • 336
-1

We used to use require.js with knockout, but we have started to use browserify instead. Since then the code base is much nicer and we build the whole project into one file except the basic libraries we use. (Eg.: knockout.js - because we load them separately from cdn, which makes the app in production much, much faster)

Here is a component library what we are developing: https://github.com/EDMdesigner/knobjs

We use gulp to build the project. Check the build:dev task in the gulpfile. Basically, the templates will be included in the built js file.

gyula.nemeth
  • 847
  • 10
  • 9