Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I have multiple instances of a RequireJS Module?

I am obviously missing some concept/understanding and most definitely javascript OO basics!

I am loving using RequireJS, and my web app now looks more like a structured app now rather than a whole heap of crazy code.

I am just struggling to understand how/if the following is possible.

I have a module which acts as a base dataservice module called dataservice_base as follows:

define(['dataservices/dataservice'], function (dataservice) {

    // Private:     Route URL
    this.route = '/api/route-not-set/';
    var setRoute = function (setRoute) {
        this.route = setRoute;
        return;
    }

    //  Private:    Return route with/without id 
    var routeUrl = function (route, id) {
        console.log('** Setting route to: ' + route);
        return route + (id || "")
    }

    //  Private:    Returns all entities for given route
    getAllEntities = function (callbacks) {
        return dataservice.ajaxRequest('get', routeUrl())
        .done(callbacks.success)
        .fail(callbacks.error)
    };

    getEntitiesById = function (id, callbacks) {
        return dataservice.ajaxRequest('get', routeUrl(this.route, id))
        .done(callbacks.success)
        .fail(callbacks.error)
    };

    putEntity = function (id, data, callbacks) {
        return dataservice.ajaxRequest('put', routeUrl(this.route, id), data)
        .done(callbacks.success)
        .fail(callbacks.error)
    };

    postEntity = function (data, callbacks) {
        return dataservice.ajaxRequest('post', routeUrl(this.route), data)
        .done(callbacks.success)
        .fail(callbacks.error)
    };

    deleteEntity = function (id, data, callbacks) {
        return dataservice.ajaxRequest('delete', routeUrl(this.route, id), data)
        .done(callbacks.success)
        .fail(callbacks.error)
    };

    //  Public:     Return public interface
    return {
        setRoute: setRoute,
        getAllEntities: getAllEntities,
        getEntitiesById: getEntitiesById,
        putEntity: putEntity,
        postEntity: postEntity,
        deleteEntity: deleteEntity
    };

});

As you can see, I am referencing dataservices/dataservice, which is actually the core AJAX call mechanism (not shown, but really just basic jQuery ajax call in a wrapper).

What I am trying to do is allow this base dataservice module to be "instanced" as follows (within another module - snippet code only):

define(['dataservices/dataservice_base', 'dataservices/dataservice_base', 'dataservices/dataservice_base'], function (dataservice_profile, dataservice_qualifications, dataservice_subjects) {

    //  Set the service route(s)
    dataservice_profile.setRoute('/api/profile/');
    dataservice_qualifications.setRoute('/api/qualification/');
    dataservice_subjects.setRoute('/api/subject/');

As you can see, I am trying to include the same dataservice_base(defined above) 3 times, but in the function references, I am trying to refer to each instance by named vars i.e:

dataservice_profile, dataservice_qualifications, dataservice_subjects

.. and of course I am trying be able to set a unique setRoute value for each of those instances to use further on in the module.. whilst leveraging the common calls (get,puts,posts etc).

Obviously I am missing a few things here.. but any help to point me back on the road would be very gratefully received!!

Kind Regards, David.

like image 866
Dav.id Avatar asked Jan 08 '13 14:01

Dav.id


People also ask

Is RequireJS synchronous?

So, RequireJS doesn't support it. From your use case it seems that you don't need synchronous RequireJS, you need to return result asynchronously. AMD pattern allows to define dependencies and load them asynchronously, but module's factory function must return result synchronously.

Why do we need RequireJS?

Managing the Order of Dependent Files Even though the file order is considered, we cannot guarantee that the first file is loaded before the second file due to the asynchronous nature. So, RequireJS allows us to use the shim config to define the sequence of files which need to be loaded in correct order.

What is Shim RequireJS?

shim: Configure the dependencies, exports, and custom initialization for older, traditional "browser globals" scripts that do not use define() to declare the dependencies and set a module value. Here is an example. It requires RequireJS 2.1. 0+, and assumes backbone. js, underscore.

What is RequireJS config JS?

RequireJS is a JavaScript file and module loader. It improves perceived page load times because it allows JavaScript to load in the background. In particular, it enables asynchronous JavaScript loading.


3 Answers

I think you need to include your dependency only once and use the new keyword. Possibly you will need to refactor so that the common functions are in a depending module:

define(['dataservices/dataservice'], function (dataservice) {
    var dataservice_profile = new dataservice();
    var dataservice_qualifications = new dataservice();
    var dataservice_subjects = new dataservice();

    //  Set the service route(s)
    dataservice_profile.setRoute('/api/profile/');
    dataservice_qualifications.setRoute('/api/qualification/');
    dataservice_subjects.setRoute('/api/subject/');

    // define needs to return something
    return {
       profile: dataservice_profile,
       qualifications: dataservice_qualifications,
       subjects: dataservice_subjects
    };
});
like image 71
asgoth Avatar answered Oct 30 '22 13:10

asgoth


Yes, brain-freeze or whatever.. problems of working alone sometimes!

So, as @asgoth mentioned, quite rightly had to clear my mind and think things through a bit!

I ended up with a re-factored dataservice_base module as follows:

define(['dataservices/dataservice'], function (dataservice) {

    //  Set any class/static vars

    //  Set the instance function
    function dataservice_base(setRoute) {

        var self = this;

        self.route = setRoute;
        console.log('setting route: ' + self.route);

        function routeUrl(route, id) {
            console.log('** Setting route to: ' + route);
            return route + (id || "")
        }

        self.getAllEntities = function (callbacks) {
            return dataservice.ajaxRequest('get', routeUrl())
            .done(callbacks.success)
            .fail(callbacks.error)
        }

        self.getEntitiesById = function (id, callbacks) {
            return dataservice.ajaxRequest('get', routeUrl(self.route, id))
            .done(callbacks.success)
            .fail(callbacks.error)
        }

        self.putEntity = function (id, data, callbacks) {
            return dataservice.ajaxRequest('put', routeUrl(self.route, id), data)
            .done(callbacks.success)
            .fail(callbacks.error)
        }

        self.postEntity = function (data, callbacks) {
            return dataservice.ajaxRequest('post', routeUrl(self.route), data)
            .done(callbacks.success)
            .fail(callbacks.error)
        }

        self.deleteEntity = function (id, data, callbacks) {
            return dataservice.ajaxRequest('delete', routeUrl(self.route, id), data)
            .done(callbacks.success)
            .fail(callbacks.error)
        }

    } // eof instance

    return dataservice_base;
}

and of course again as @asgoth mentioned, I only need to of course include one reference to the dataservice_base module, and instance it for my needs as follows:

define(['dataservices/dataservice_base','viewmodels/viewmodel_profile', 'viewmodels/viewmodel_qualifications', 'viewmodels/viewmodel_subjects', 'app/common'], function (dataservice_base, viewmodel_profile, viewmodel_qualifications, viewmodel_subjects, common) {

    var dataservice_profile = new dataservice_base('/api/profile/');
    var dataservice_qualifications = new dataservice_base('/api/qualification/');
    var dataservice_subjects = new dataservice_base('/api/subject/');

    // do whatever now with those instance objects...
}

SO.. now all working!

I guess the only other thing I need to do is looking up about cleaning up process to ensure these objects are released.. however there will only ever be a few.. but still..

thanks again @asgoth

like image 21
Dav.id Avatar answered Oct 30 '22 14:10

Dav.id


Just return a function instead of a object like this

return function(){
    return {
        // your public interface goes here
    };
}

Now you can create new instances of your plugin with new componentName().

like image 27
dude Avatar answered Oct 30 '22 14:10

dude