ELI5: What are states initialization and circular dependencies?

I’ve been having a problem with a plug-in I’m trying to build and I’m rereading the manual, rewatching @eli ’s tutorial, and generally so deep in StackOverflow I’m earning badges.

But I don’t grasp this thing. The description text makes me question my questionable intellect because I don’t get it.

Could some explain this to me like I’m 5? When do I have to use it? How do I use it?

It’s probably easier to explain how to generate a circular dependency error:

  • create a plugin element with a filed of type text, let’s call it “textinput”
  • add a state of type text, let’s call it “textoutput”
  • let’s initialize “textoutput”
    image
  • now in the app editor let’s assign a value to “textinput” that reference the element state
    image
  • go to preview and watch your error :slight_smile:

It looks complicated but it’s the equivalent of this javascript code
image
it’s just made in 2 steps between the plugin code and the editor

You are literally telling bubble to inizialite the state “textoutput” with the value of the state “textoutput”.

A solution is to initialize the state in the initialize function where you don’t have the properties and you can only initialize the state to a static value. Then publish the state value in the update function.
image
image

I hope it’s more clear now

Cheers

Mariano

3 Likes

Duuude!!! :bowing_man:
Consider myself educated! Wow, thanks! I get it now.

1 Like

Should I always initialize any value that I plan on using with publishState?

Hey @rico.trevisan, are you actually running into the issue of the issue checker throwing the circular dependency error for your plugin?

If not, don’t worry about this somewhat confusing note. (Though @dorilama provides an example of how you might cause a circular dependency error.)

But, what this note is referring to is the two different ways to initialize the value of an exposed state (we’ll get to those in a second).

An exposed state is how the plugin communicates values back to Bubble. For example, in List Shifter, I expose a ton of different states like “List Shifter’s Original List”, “List Shifter’s Shifted List”, “Initialized”, etc. Those are “exposed states”. (In my videos and documentation, I more often refer to those as the plugins “outputs” – because that’s essentially what they are and feel “exposed states” is overly verbose.)

In the plugin editor, they are defined here:

One does not have to provide an initial value for an exposed state. In some cases, we may be fine with having them be empty/null and there’s no point in initializing them further.

But in some cases, we might want to populate them at initilization time. And there are two ways to do this. The “default” way (but I would say this is not the preferred way) is that every exposed state that you define has its own “Code state initialization” block in the editor. Those appear here:

And so, as you can see in the example, we can define a function whose return value becomes the initial value for the state, as in this simple example from a test plugin.

But this way of initializing your states is pretty much madness, as why separate your code all over the place in those dumb little boxes?

ALSO, Bubble did at one time actually break the processing of the “code state initialization” functions and I presume that could occur again. This method of initialization seems to have been provided to make very simple plugins even simpler to create. An example would be the early versions of Browser Timezone & Locale, which just exposes things like the user’s timezone. And in that first version it just looks like this:

But we can instead initialize those outputs using instance.publishState() like so (this is the current version of Browser Timezone & Locale):

This, to my mind is a much better way to do things. Most of my code for a plugin will be in the initialize function which defines everything we need to do and executes itself. Then, in sections like Code Actions, I just reference the already defined action code. And we don’t need to fuss with the Code state initialization sections at all.

For an example of this, look at my Fielder plugin. This is generally how more sophisticated plugin devs do their code.

4 Likes

I usually publish all the states in the update function just because I have everything in one place and that works better for the way I reason about it.

1 Like

Thanks, Keith!

No, I’m not getting circular reference warnings. I was facing a couple of problems and my troubleshooting <airquotes> technique </airquotes> I was to ogre around the plugin builder trying all the buttons.


Wow, so you build your entire plugin in the initialize and then just pass the properties to that function afterwards. Noice.

Also, I appreciate how you write your code with the native Bubble objects: instance.data.whatever. Is it a style choice or are there some performance gains?


Let me blabber on about my problems, maybe you guys can spot improvements. Context: it is a text editor plugin. The text editor works when it’s alone on the page and has only 1 source of content. It fails when it is in a popup and the source changes often. It will load with the content from the previous popup or it won’t load any content or it will let me type, but then erase everything I just typed.

Any ideas?

1 Like

So presumably your editor uses some library and you’ve defined that script in the Headers section? If you’ve done this correctly your script will be loaded in the page and available even if your element is in a popup.

If not, that’s what’s causing your element not to work in a popup.

I’m not sure what you mean by this, though?:

In answer to your question:

Well, Bubble passes the instance object to our functions everywhere. And it provides the data object property on instance as a place to store values we need to access and pass between in our various functions. So that’s where I put them.

We could also make some other object on instance (e.g., instance.d = {})as a place to pass such values, but data is already there.

I’m almost there. Thanks for rubber ducking with me. I was not loading the content into a variable on the update function.


@keith, what I meant with my question if it was a style choice, is that I see a lot of plugins where people will create a bunch of variables like:

let thing = properties.thing;
const objectA = instance.data.objectA;

I thought it was a way to make your code more readable and save on keystrokes, but I just learned my lesson: this is how Bubble loads your data.

It happened!

But now I know how to fix it Danke!

way to go! :slight_smile:

1 Like

Is there a way to add conditions in the styles tab?

do you mean adding a condition in the style tab from the plugin? Or maybe adding oprions in the dropdown of the style tab?

My written messages quality is super low, sorry for not being clear. I mean the first: adding conditions in the style tab from the plugin.

I just went back and realized that I could change the type of element (I had completely forgot that option).

Just went back through the editor and re-read all the options and realized that there was a “in style” checkbox. Note to self: that only shows if it’s NOT set as a dynamic value.

It shows the option (2), but not in the “when…” (1). Pity.


What do you experienced Bubblers think about boolean fields:

  1. better as checkboxes
  2. better as dynamic yes/no

Looking at Keith’s Fielder and ListShifter it’s the latter all the way.

It depends on how you want to update thes as user:

  • checkbox : you need a condition to update it
  • dynamic value: set up an expression and the value updates automatically because is reactive
1 Like

I typically make all of my properties dynamic, @rico.trevisan.

1 Like

I’d like to add something, as I encountered this problem as well, and it wasn’t easy for me to understand the issue even after reading the detailed information here.

Indeed, I understand the concept of a recursive error of type let x = x, but in my case, this didn’t seem to be the issue.

When creating an empty plugin (with no code), with just an exposed state and a custom field, an error, Recursion when evaluating property XXX on element, appears when adding a condition that changes the custom field based on the state, even if they aren’t directly related, because not code so no attribution depending on properties.customField.

It seems necessary to initialize the state, but nothing I tried in the initializeState function worked—even a simple return true; didn’t resolve it.

What did work was initializing the state at the beginning of the plugin’s initialize function (the plugin one, not the initializeState one). A simple instance.publishState('my_state', null); solved the issue.
My initializeState function stays empty.

After that, the state value can then be modified without any recursion error from within the update function. Since the update function runs at least once after initialize, the initial value has little importance, as the correct value will be set right after.

Be careful to not setup a real recursion, as described in the previous answers.

I hope this will be helpful!


Also, @rico.trevisan, I would also like exposed states to be accessible in style conditionals. A few months ago, I created a card on the ideaboard for this.

If you’re interested, give it a thumbs up!

Plugin element states accessible on Styles page | Bubble Ideaboard

1 Like

if you publishState in the global initialize function it will trigger an update in any element of the page that references the state. Only after that your update function runs, so the initial value can have importance, depending on how you use that state in the page.

3 Likes