Help me organize my stipid javascript



  • I'm working on a webapp that uses Knockout (which I really really like!), but I'm having some trouble with my "working knowledge" of JavaScript.

    I built my ViewModel following the Knockout tutorials, and it works the way I expect. But I ended up writing a bunch of methods like loadClientByDay, loadClientByName, etc. Also, because it's Knockout, I have a bunch of observables, like currentClient, etc.

    I'd like to change the method names to be more like app.load.client.day, app.load.client.name, etc. That should be straight-forward enough. But how do I actually do it? As much as possible, I'd like to keep using the notation:

    function ViewModel() {
      var self = this;
      self.app.state.client = ko.observable(); 
      self.app.load.client =  function () { loadStuff };
    }
    

    The naive thing, to just initialize the fields I will use, didn't work. It keeps complaining that, for example, app.state isn't defined. So I tried using empty objects and I got kind of stuck. I could keep plugging along with initializing a ton of empty objects, but is there a better way?


  • đźš˝ Regular

    You can use nested object literals:

    self.app = {
        load: {
            client:  {
                day: function (day) { /**/ },
                name: function(name) { /**/ }
            } 
        }
    };
    

    Notice the similarity to JSON (or the other way around, really).

    Also, starting with ES2015 (I think) there's an alternate, shorter way of writing methods:

    self.app = {
        load: {
            client:  {
                day(day) { /**/ },
                name(name) { /**/ }
            } 
        }
    };
    


  • @zecc Yeah, I've beed doing the first style a bit:

    self.app = { state: {}
               , load: {}
               , resource: {}
               }
    

    And then filling in the components with

    self.app.state.client = ko.observable()
    

    and so on.

    I guess, thinking about it, what I REALLY want is more like modules or namespaces than objects. One of the things that has me stuck is where a method like loadSheetsForClient should if into the scheme. Should it be app.load.sheets.client or app.load.client.sheets. And, if it's the latter, how do I make it play nice with the fact that I already have an app.load.client method? (I'm leaning toward the app.load.sheets.* style)



  • @zecc There's also the arrow notation:

    day: (foo) => { /**/ }
    

    Though that one is best used if you don't want to change this to the context of the function thus created. No more that = this



  • @rhywden Only works in later versions of JS and if you aren't using a transpiler like babel ... it won't work on anything except for Chrome.



  • @captain said in Help me organize my stipid javascript:

    app.load.client.sheets. And, if it's the latter, how do I make it play nice with the fact that I already have an app.load.client method? (I'm leaning toward the app.load.sheets.* style)

    Since JavaScript is magical and full of wonder, it is perfectly acceptable* to add members to functions. E.g. (from console):

    > var helloFn = () => console.log('hello world');
    undefined
    > helloFn.houseOnFire = () => console.log('this is fine')
    () => console.log('this is fine')
    > helloFn()
    VM30513:1 hello world
    undefined
    > helloFn.houseOnFire()
    VM30527:1 this is fine
    undefined
    

    * :doing_it_wrong:



  • @rhywden

    And a better explanation (Mozilla's explanations suffer from some of the MSDN docs of the past, a very vague and unrealistic example).

    Here is a better example of how to use the bind().

    You can rebind "this" since IE9 I believe (I am not sure tbh). There is also a polyfill for older browsers.


  • :belt_onion:

    @captain you can do this using something like this:

    function namespace(object, path) {
      if (typeof path === 'string') path = path.split('.');
      return path.reduce((obj, element) => element in obj ? obj[element] : (obj[element] = {}), object);
    }
    
    function ViewModel() {
      var self = this;
      namespace(self, 'app.state').client = ko.observable(); 
      namespace(self, 'app.load').client =  function () { loadStuff };
    }
    

  • đźš˝ Regular

    @captain said in Help me organize my stipid javascript:

    One of the things that has me stuck is where a method like loadSheetsForClient should if into the scheme. Should it be app.load.sheets.client or app.load.client.sheets. And, if it's the latter, how do I make it play nice with the fact that I already have an app.load.client method? (I'm leaning toward the app.load.sheets.* style)

    You could assign the object to them all, but there lies madness.

    @lucas1 said in Help me organize my stipid javascript:

    @rhywden Only works in later versions of JS and if you aren't using a transpiler like babel ... it won't work on anything except for Chrome.

    Lies!

    Oh, FFS, it doesn't embed. Here:

    0_1522219671930_22475a56-d87d-4d41-9dc8-93863bc8f2b1-image.png


  • đźš˝ Regular

    @zecc said in Help me organize my stipid javascript:

    Lies!

    Well, TBF you're only half wrong, if we consider relative browser usage.

    0_1522219942084_6f9f6c37-e49c-45da-b34b-152c173d8a79-image.png



  • @zecc IE 11 isn't an unusual platform, especially if you have corp clients.

    I am a mobile js dev mostly these days, but at least I bother to check on older desktop browsers.

    If I want to make sure my arrow syntax works, I make sure I put it through the compiler.


Log in to reply