triggerEvent() not firing inside repeating groups?

Not sure if a feature or a bug, but I’ve noticed that I cannot get instance.triggerevent("something_has_happened") to fire when my plugin’s page element is placed inside a repeating group as well as when triggerEvent() is itself called from an event listener.

What I’m trying to do:
If the user clicks something inside the HTML of my plugin element, I want to trigger a bubble workflow to run.

run triggerEvent() from an event listener when plugin element is outside of repeating group = OK
run triggerEvent() without event listener inside repeating group using update() function = OK
run triggerEvent() with element inside a repeating group, triggered by event listener = BROKEN

I did verify that the event listener is indeed firing when my element is placed in a repeating group.
item.onclick = ( ) => { instance.triggerEvent('test') ;
alert();
};
In the above case, the alert() window did get triggered, however instance.triggerEvent('test') did not not fire.

When I place the element outside of the repeating group triggerEvent() and alert() both fired.

Taking it a step further

item.onclick = ( ) => {
instance.triggerEvent('test') ;
console.log(instance.triggerEvent())
};

does show instance.triggerEvent() is still defined with the exact same function code at the time of user interaction so it doesn’t seem to be any sort of esoteric platform-related behavior of the instance.triggerEvent() object/function

Weird, because calling instance.triggerEvent('revealed'); from the initialize function works, even inside a repeating group.

I called it from the update () function since my plugin’s UI is generated based on the update() function.

So I did a workaround…

I put a ‘message’ event listener inside theinitialize() function. That listener then ran triggerEvent() function when a message was received–all within the initialize function. I then sent the listener strings from my update() function using window.postMessage(myString) and then processed that string and targeted the my trigger function in bubble usingtriggerEvent()

Had to make sure to establish a global variable initComplete = true and load the listener conditionally insideinitialize() so it would only be loaded once and not fire off for each instance of the plugin in the repeating group.

update(instance,properties,context){
  appName = "mySpecialPlugin";'
  groupName = properties.user_supplied_plugin_group_name;'
  instance.data.groupName = groupName;'
 triggerEventName = "when_item_is_clicked";'
 window.postMessage(appName + "," + groupName + "," + triggerEventName) '
 // " mySpecialPlugin,group1,when_item_is_clicked "
'}'

    initialize(instance, context ){
     if (window.pluginIsLoaded == undefined){
      let msgArray = msg.data.split(',');
      window.addEventListener('message',(msg) => {
       if (msgArray[0] == 'rt_triggerEvent' && 
        msgArray[1] == instance.data.groupName]){
         instance.triggerEvent(msgArray[2]) 
       })
     window.pluginIsLoaded = true; //don't attach this event listener again
    }
    }
3 Likes

Great! Thanks for sharing what worked!

1 Like

At the time I first wrote about this behavior. This seemed like a great solution, however after considering it for a bit more, it was ultimately kludgy and limiting.

What I’ve come to understand is a better design layout for bubble is to continue with the web messaging, however to also create a separate plugin element that is be placed outside of the RG. This ‘outside’ element contains most/all of the ‘run once’ code for the group of spawned RG elements. It also has an event handler to listen for messages that are triggered from the individual element(s) within the RG.

Not only is this well-organized and easier to understand for the developer, but by placing a separate element outside the RG you gain the ability to trigger workflows and expose states to the entire page. Its an extra step for the user to configure, but is ultimately necessary if you want to do these things.

You can see this concept at work with the dragtable plugin. :slight_smile:

1 Like

Hey @jon2,

I was hoping you could elaborate a little more on your solution. I have a very simple plugin that triggers an event when the plugin is initialized on the page.

Every time I create a new thing and it is added to the repeating group, it should trigger an event. When the event is triggered, an alert should appear showing the unique ID of the parent.

This works most of the time, until I delete an item from the repeating group. However many items I delete from the repeating group, the event will not trigger for that number of times. So, if I delete one item, then the event won’t trigger the next time a thing is created. If I delete two items, then the event won’t trigger the next two times a thing is created.

Is your solution a potential workaround for this issue?

Video: https://www.loom.com/share/6241fc0bcbbb444e9133ab8f2c3df5ad
Editor: https://bubble.io/page?type=page&name=new-test&id=my-forum-examples&test_plugin=1662743012128x236951277671809020_current&tab=tabs-1
Run Mode: https://my-forum-examples.bubbleapps.io/version-test/new-test?debug_mode=true

As you’ve probably figured out, when a RG is downsized, those elements that were there, stay there. So the instances of your plugin never get deleted and initialize doesn’t run until a genuinely new row is added.

The way that I get around this is having a controlling state on the RG for each action you want to perform - e.g. index_to_add in your case - which is a number. When the add button in the cell is clicked then this state is changed to the current cell’s index / new cell’s index - whatever applies.

Meanwhile in your plugin you add two fields: current_index and index_added. Every time either one of these values changes your plugins update function is going to run - so all you need to do is a) check whether that plugin instance’s current_index === index_added:

function(instance, properties, context) {

if (!current_index || !index_added) return; //if either are empty then don't bother

if (current_index === index_added) {

instance.publishState('what_cell_is_added', `properties.current_index`);
instance.triggerEvent('revealed', function(err){});

}
}

Finally, in your Revealed event fired workflow you want to reset your index_added state back to null, as well as show your Alert etc.

2 Likes

Hey @exception-rambler,

Thanks for your help! That solution worked great for my example :smiley:

Building on that, however, I ran into another problem. I have a plugin where I am trying trigger an event when an enter key is pressed in a multiline input. I have written an event listener:

function(instance, properties, context) {
    
$(document.getElementById(properties.input_id)).keydown(function(e) {

    if (e.keyCode == 13) {
                         
            if (event.repeat == false) {
                e.preventDefault();
                instance.triggerEvent("enter_pressed");
            } 

            else {
                e.preventDefault();
                return;
            }                     
    }
    
})
    
}

Previously, I was triggering an event in the initialize function. In the workflow, I would run the event listener. Theoretically, any time a new row was added, it would trigger a workflow to run the event listener. This worked except when I deleted a row and experienced the problem I described previously.

In addition, I have a second event that is triggered whenever an enter key is pressed in the multiline input. When an enter key is pressed, I want to create a new thing in my database and add a row in the repeating group.

When I switched from the initialize function to the new code in the update function, it creates some weird behavior. Rather than creating a single thing in the database, it creates 5-10 things at a time (video below). I believe this is because the event is now triggered from the update function, so every plugin in the repeating group is updated, whereas previously it would only run once in the initialize function.

Would you have another recommendation / workaround?

Editor: https://bubble.io/page?type=page&name=trigger-event&id=my-forum-examples&tab=tabs-1
Plugin Editor: Bubble Plugin Editor - Test Bug Plugin

When the enter key is pressed, several rows are created, when I just want to create one thing at a time:

Screen Recording 2022-09-12 at 2.28.51 PM

I don’t have access rights to see your plugin code but this sounds like multiple event listeners. I would hazard a guess that when you run your Run Event Listener Plugin: TriggerEvent it adds an event listener to #input_id for every cell in the group.

To get around this you can apply the same method as before to only allow one single instance of your plugin to execute.

So if you keep your Index added state alive (i.e. delete the current reset) and pass it as a parameter into your Run Event Listener Plugin: TriggerEvent action, as well as the Current cell's index then you can add the same check at the head of your action’s script:

if (!current_index || !index_added) return; //if either are empty then don't bother

if (current_index === index_added) {
//add event listener script
}
instance.triggerEvent('listenerAdded', function(err){});
//now you can reset your Index added inside a workflow triggered by this event

See how you get on.
If it is indeed multiple event listeners then you might want to add some extra protection by adding an attribute (setAttribute()) on #input_id e.g. has-listener -> true when you add a listener. You can then add a check (hasAttribute()) every time before you add one.

You’re right, that is how I’m adding event listeners. I have an ID attribute on each multiline input that I’m passing to the plugin.

Using the new method, keeping the added index state until the event listener is added, it appears that some of the new cells don’t ever receive an event listener. That is, when I press enter, the standard behavior to create a new line occurs.

Any thoughts as to why this is? Also, I’d be happy to open up access rights to the plugin, but I’m not exactly sure how when it’s in testing mode.

Quite tricky to debug with the double relay going on.
Might be easier to consolidate things down so that you add the event listener as part of the ‘new row detected’ script… so right before you trigger the revealed event. You can pass the id attribute via a field on the plugin in order to construct your id attribute: var input_id = `input-${properties.obj_id} kind of thing.

Add some logs right through the script so you can keep tabs on how it’s executing… once you’ve got all that you should be able to see the order of things and what’s going on.