1

The set accessor does not take place whenever one does mutate the Crumbs class property value by e.g pushing into it.

I'm trying to create a class property via set syntax which I expect to handle an additional sessionStorage task. But every time, I'm going to push an item into the array, the set accessor does not take place.

The code I came up with so far is as follows ...

class Environment {
  constructor() {
    this.Crumbs = [];
  }
  set Crumbs(value) {
    // debugger;
    sessionStorage.setItem('_crumbs', JSON.stringify(value));
  }
  get Crumbs() {
    // debugger;
    let result = [];

    if (sessionStorage.getItem('_crumbs') !== null) {

      result = JSON.parse(sessionStorage.getItem('_crumbs'));
    } else {
      sessionStorage.setItem('_crumbs', JSON.stringify([]));
    }
    return result;
  }           
}
let env = new Environment();

let _metricId = 6;
let _concept = 'Back orders';

let _crumb = {
  MetricId: _metricId,
  Concept: _concept,
};
env.Crumbs.push(_crumb);
3
  • 2
    push won't activate the setter. You have to actually set it like env.Crumbs = ... Commented May 29, 2023 at 20:28
  • @PeterSeliger Sincerely I use the first response from the comments, I appreciate your response and your time. Commented May 31, 2023 at 20:00
  • @JosueBarrios ... How do you handle or even prevent a user (from) operating the Crumbs array via mutating array methods like e.g. push, pop, unshift, shift and splice? Commented May 31, 2023 at 20:03

1 Answer 1

1

None of the mutating array methods will ever activate the OP's setter. This only happens for direct assignments to Crumbs.

But since the OP wants to go with the least effort of handling array changes by any array operation, the OP needs to expose a proxyfied array as an Environment instance's crumbs property. The proxy's handler configuration has to implement just the set trap, and moreover needs to specifically handle just the change to the proxy's length property, where one would keep the stored crumbs value up to date by storing the local/internal crumbList mirror.

class Environment {
  constructor() {
    // - always "up to date" mirror of the `this.crumbs` proxy object.
    // - initialized either from `sessionStorage` or as empty array.
    const crumbList =
      JSON.parse(sessionStorage.getItem('crumbs') ?? null) ?? [];

    this.crumbs = new Proxy(crumbList, {
      set(obj, prop, value) {
        // debugger;
        // console.log({ obj, prop, value });

        // proceed with `set`.
        const result = Reflect.set(...arguments);

        if (prop === 'length') {
          // - immediately put most recent `crumbList`
          //   mirror into `sessionStorage`.
          sessionStorage.setItem('crumbs', JSON.stringify(crumbList));
        }
        return result;
      }
    });
    // - since one does access the `this.crumbs` proxy for any
    //   (mutating) array operation, one might think about a
    //   custom `valueOf` implementation which returns a shallow
    //   copy of the proxy object's up to date mirror state.
    Object.defineProperty(this.crumbs, 'valueOf', {
      value: function valueOf () {
        return [...crumbList];
      },
    });
  }
}
const env = new Environment;

const metricId = 6;
const concept = 'Back orders';

const crumb = { metricId, concept };

env.crumbs.push(crumb);

env.crumbs.push('foo');
env.crumbs.push('bar');

env.crumbs.length = 5;

env.crumbs.push('baz');
env.crumbs.push('biz');

env.crumbs.length = 9;

console.log('... after initial `push` operations and `crumbs.length` changes ...');
console.log({ "current value": env.crumbs });

env.crumbs.shift();
env.crumbs.pop();
env.crumbs.pop();

console.log('... after `shift` and `pop` operations ...');
console.log({ "current value": env.crumbs });

env.crumbs.splice(1, 3);

console.log('... after a final `splice` operation ...');
console.log({ "current valueOf()": env.crumbs.valueOf() });

console.log({ "currently stored JSON": sessionStorage.getItem('crumbs') });
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
  // mock for the SO specific stack snippet
  // due to the policies and environment are
  // not allowing an original storage access.
  const sessionStorage = (function () {

    // https://developer.mozilla.org/en-US/docs/Web/API/Storage
    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
    const storage = new Map;

    function key(int) {
      return [
        ...storage.keys()
      ][parseInt(int, 10)];
    }

    function setItem(key, value) {
      return storage.set(String(key), String(value));
    }
    function getItem(key) {
      return storage.get(String(key));
    }

    function removeItem(key) {
      return storage.delete(String(key));
    }

    function clear() {
      return storage.clear();
    }

    return {
      get length() {
        return storage.size;
      },
      key,
      getItem,
      setItem,
      removeItem,
      clear,      
    };

  }());
</script>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.