Categories


Archives


Recent Posts


Categories


Magento 2: The uiElement “Statefull” Default

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

The next uiElement default we’re going to talk about is the statefull default. Before we begin, let us bask is the programmer’s glory of the misspelling of “stateful” making it into a production release.

The statefull default allows you to create a uiElement object with properties that will be automatically persisted into the localStorage, via the localStorage abstraction we discussed in our previous post.

Let’s start with the code – run this from your javascript console on a Magento bootstrapped page.

UiElement = requirejs('uiElement');

OurConstructorFunction = UiElement.extend({
    'defaults':{
          'name':'aUniqueNameForTheUiElement',
          'tracks':{
              foo:true
          },              
          'statefull':{
              foo:true
          }
     }
}); 

object = new OurConstructorFunction;

object.foo = "Some Value for the foo property";

Now, refresh the page, and run the following program

UiElement = requirejs('uiElement');

OurConstructorFunction = UiElement.extend({
    'defaults':{
          'name':'aUniqueNameForTheUiElement',
          'tracks':{
              foo:true
          },              
          'statefull':{
              foo:true
          }
     }
}); 

object = new OurConstructorFunction;

console.log( object.foo );

You should see that the .foo property has persisted across page loads!

The statefull defaults has two important prerequisites. If we look at the creation of our constructor function

OurConstructorFunction = UiElement.extend({
    'defaults':{
          'name':'aUniqueNameForTheUiElement',
          'tracks':{
              foo:true
          },              
          'statefull':{
              foo:true
          }
     }
}); 

First, in order to use a statefull property, our uiElement class and object will need a name. That’s because the local storage abstraction uses the name attribute to create a namespaced space in the browser’s localStorage data store. (viewable in Google Chrome’s debugger at Application -> Local Storage). Also, remember that the local storage abstraction (and therefore this feature) assume your uiElement based object will only ever be instantiated/registered once. If you instantiate other objects with the same constructor function they’ll load the same values from local storage, because they have the same name.

Second, the property you want to be stateful must be tracked. Here we’ve tracked it via the tracks default. You should be aware that you can also setup this tracking manually, as seen in this core code

#File: vendor/magento/module-ui/view/base/web/js/grid/columns/column.js
this._super()
    .track([
        'visible',
        'sorting',
        'disableAction'
    ])

It’s not 100% clear to me why the stateful setting code doesn’t handle this itself, which usually means either an oversight on the part of Magento’s core team, or an oversight on my understanding of the feature. Tread carefully.

Those two prerequisites down, we have the statefull configuration itself

'defaults':{
      /*...*/         
      'statefull':{
          foo:true
      }
 }

The statefull default is an object of key/value pairs. The key is the property we want to automatically store in local storage, and the value should be a “truthy” javascript value. If we look at the code that sets up the stateful properties

#File: vendor/magento/module-ui/view/base/web/js/lib/core/element/element.js
initStatefull: function () {
    _.each(this.statefull, function (path, key) {
        if (path) {
            this.setStatefull(key, path);
        }
    }, this);

    return this;
},  

setStatefull: function (key, path) {
    var link = {};

    path        = !_.isString(path) || !path ? key : path;
    link[key]   = this.storageConfig.path + '.' + path;

    this.setLinks(link, 'imports')
        .setLinks(link, 'exports');

    return this;
},     

We can see if this “truthy” value is a string,

path        = !_.isString(path) || !path ? key : path;
link[key]   = this.storageConfig.path + '.' + path;

it will impact the registry URN Magento passes to the imports/exports link feature.

I’m not 100% clear on the implications of this, but it seems to be a way to tell Magento to store and fetch the value from a different place in local storage.

'statefull':{
  foo:'someOtherValueForLocalStorage'
}

This is another area where I would tread lightly, and just stick to the simple true configuration unless you’re up for some local storage debugging.

Also, one last parting caveat. Remember that localStorage is a per browser thing. It won’t vary between frontend and adminhtml, and it won’t vary between logged in users. It also won’t be picked up if a user logs into a different browser. It’s the same, big, bucket for everyone using this particular browser profile.

Be careful what you store, and think through the implications of using the uiElement’s local storage feature.

Copyright © Alan Storm 1975 – 2017 All Rights Reserved

Originally Posted: 28th November 2016