2

I'm working on a Durandal SPA, and I've setup some views and viewmodels. I'm unclear how I should be creating "model" objects on the client side. For instance, let's say that I want to define and create "Person" model object.

Everything else in my app is defined AMD style. This allows Durandal/RequireJS to automatically load up the files it needs.

So, my first thought was that I might define my "Person" model type in a models/person.js file, like this:

define(function () {
    var id = ko.observable(0);
    var firstname = ko.observable('');
    var lastname = ko.observable('');

    return = {
        id: id,
        firstname: firstname,
        lastname: lastname,
    };
});

However, I don't think this is right, because from here I don't think there's a way to actually create individual "Person" objects. For instance, let's say I wanted to create two "Person" objects. Durandal/RequireJS will happily load in my "Person" module, but it's just one object--and I may want to create another instance of the "Person" type, or five more instances, etc.

What's the appropriate way to do this? Thanks for helping clear up my confusion!

UPDATE: I've gotten some responses that explain some ways to do this. I think my confusion stemmed from the fact that a "module" is not a "type", or a "class". It's more like a singleton object. So if you want to define a type, and put it inside a module, you need to create module that is, essentially, a factory.

Is that right?

A factory makes sense in this case. But, I have a clarifying question: is this a factory the accepted method for defining model types in a Durandal/RequireJS/AMD style JavaScript app? I'm sure I'm not the first person to run into this issue. I'm wondering how it has been solved before, and (especially) if there is an accepted convention in the AMD world on how to define reusable types.

Josh
  • 7,232
  • 8
  • 48
  • 75

2 Answers2

3
define(function () {

    return function(){
       var self = this;
       self.id = ko.observable(0);
       self.firstname = ko.observable('');
       self.lastname = ko.observable('');
    };
});

define(['models/person'], function(person){
    var myPerson = new person();
});
Sujesh Arukil
  • 2,469
  • 16
  • 37
  • So your "module" becomes the constructor function for your type. Clever. Is this an accepted practice for defining types in the AMD world? – Josh May 14 '13 at 18:59
  • absolutely yes. The one that you have been using is more like a Static class. Predefined. I usually have my models separated out like this and instantiate it when I get my data. – Sujesh Arukil May 14 '13 at 19:26
  • you can even pass data in to the constructor of the function. One good practice would be to set the first character to upper case, just to let others know that you are going to instantiate it.. define(['models/person'], function(Person){} – Sujesh Arukil May 14 '13 at 19:28
  • Thanks, that makes sense. Also, for reference, here is a related question I found that discusses this as well: http://stackoverflow.com/questions/4869530/requirejs-how-to-define-modules-that-contain-a-single-class – Josh May 14 '13 at 20:07
1

A "person" doesn't really sound like a concept that can be turned into a module, but how about a "PersonFactory"?

person-factory.js

define(['knockout'], function (ko) {
    return {
        spawnPerson: function () {
            var id = ko.observable(0);
            var firstname = ko.observable('');
            var lastname = ko.observable('');

            return {
                id: id,
                firstname: firstname,
                lastname: lastname,
            }
        }
    }
});

It could be used in another module in the following manner:

do-something-with-person.js

define(['person-factory'], function (PersonFactory) {
    var newPerson = PersonFactory.spawnPerson();

    return {
        // do something with newPerson
    }
});
kryger
  • 12,906
  • 8
  • 44
  • 65
  • Makes sense. Is this the way types are defined in a RequireJS/AMD JavaScript app? – Josh May 14 '13 at 19:06
  • 1
    AMD is about defining modules themselves, it doesn't touch the problem of creating new objects. Use whichever solution feels better/looks more readable/is more expressive/etc. – kryger May 14 '13 at 22:08