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.