Stefan
Stefan

Reputation: 858

Javascript function (type) to store & use data

I really never used a javascript function type or class before, I understand Java and Python, but not javascript. So, I build a class like this:

function FormStore (type) {

    this.setup = () =>{
        this.store = {};
        this.ERR_LINE_PREFIX = '#err_';
        this.NO_DISPLAY_CLASS = 'no-display';
        this.settings = {
            'myID':{'hide':false},
        }
    }

    this.checkVal= () => {
        var geoArr = ['id_xx','myID', (...)];
        var id;
        $.each( geoArr, function(val) {
            id = geoArr[val];
            console.log(this.store) //-> returns undefined, below line is error
            if (!(this.store[id])) { 
                return false;
            }

        });
};

var FS = new FormStore();
FS.setup();

The store is filled by components on document.ready. There is a function that looks up if the aligned components (glyph, label, input) have some classes or values and for the specific component fills a dict: {label:false,glyph:false, input:false}. However, for some reason it doesn't matter. Even if I enter some values in to the store right away (in setup) or create them on the fly, in checkVal the store doesn't exist, it's undefined.

Please, anybody, what am I not understanding about javascript type and classes here? I am googling this a lot and trying to find good resources but, "javascipt variable class" (or type) just yields a lot of DOM manipulation.

Upvotes: 0

Views: 129

Answers (3)

Rob M.
Rob M.

Reputation: 36511

edit

There is a context problem in checkVal, you are using a non-arrow (and not explicitly bound) callback function and trying to access this inside of it. Change that to an arrow function as well, and the parent context (this) will be preserved:

$.each( geoArr, (val) => {
    id = geoArr[val];
    console.log(this.store)
    if (!(this.store[id])) { 
        return false;
    }
});

And while you are at changing that section, it's not going to work. You will not get access to $.each's return value. You should rely on native array APIs for this task and use Array.every to determine if all geoArr items are in the store (assuming that's your goal):

// returns false if not all geoArr items are in the store
geoArr.every(id => this.store[id])

original

I don't see you calling checkVal() anywhere, but based on the error you are getting it is called prior to setup() (since setup initializes the store). You could solve that problem straight away by moving this.store = {} out of setup (right at the top), e.g.:

function FormStore(type) {
   this.store = {};
   ...

Having said that, I would suggest either defining your methods on the prototype, or utilizing ES6 classes. Here is a simplified version of both:

ES5 class

function FormStore(type) {
   // make sure user didn't forget new keyword
   if (this === window) { 
      throw new Error('FormStore must be called with "new" keyword')
   }
   // initialize state, this is the constructor
   this.type = type;
   this.store = {};
   // any other state the class manages
}

FormStore.prototype = {
   setup: function() {
      // do setup stuff
      // "this" points to instance
      console.log('setup', this.type)
   },
   checkVal: function() {

   }
}

var formStore = new FormStore('foo')
console.log(formStore.store) // <-- not undefined
formStore.setup()

ES6 Class

class FormStore {
   constructor(type) {
      this.type = type;
      this.store = {};
   }
   setup() {
      console.log('setup', this.type)
   }
   checkVal() {

   }
}

const formStore = new FormStore('bar')
console.log(formStore.store) // <-- not undefined
formStore.setup()

Upvotes: 1

Shardj
Shardj

Reputation: 1969

function FormStore () {

    this.setup = function(){
        this.store = {};
        this.ERR_LINE_PREFIX = '#err_';
        this.NO_DISPLAY_CLASS = 'no-display';
        this.settings = {
            'myID':{'hide':false},
        }
    }

    this.checkVal= function(){
        var geoArr = ['id_xx','myID'];
        var id;
        $.each( geoArr, function(val) {
            id = geoArr[val];
            console.log(this.store) //-> returns undefined, below line is error
            if (!(this.store[id])) { 
                return false;
            }

        });
    }
};
var FS = new FormStore();
FS.setup();

Works absolutely fine, the code you provided had a missing bracket and you were using some broken es6 syntax

Upvotes: 0

Thijs
Thijs

Reputation: 2351

It has to do with scoping. Your $.each in checkVal has a normal function. Inside the function the scope if this is different. If you want to keep the original scope you could use a fat arrow function like you do when defining the methods.

this.checkVal= () => {
    var geoArr = ['id_xx','myID', (...)];
    var id;
    $.each( geoArr, val => {
        id = geoArr[val];
        console.log(this.store) //-> returns undefined, below line is error
        if (!(this.store[id])) { 
            return false;
        }
    });
}

When you run your original code and place a breakpoint on the line with console.log you can see in the inspector that this is set to the Window object and no longer points to your FormStore.

Upvotes: 1

Related Questions