Ahh! So it’s not necessary for publishing objects
Only when you want to publish a state or trigger an event in 1 plugin element from a different element
It’s an edge case. Not necessary in 90% (probably a lot higher) of plugins
@jared.gibb this thread helped me alot! Thankyou for putting it together.
Creating the datatype from the API is so useful. It’s not particularly intuitive and I am glad someone worked it out
Man this is genius and boy did it save me time overall. From your notes, I can tell we are fighting with the same thing (Google calendar data). It’s such a pain to deal with JSON data in Bubble.
Thank you again!
Really smart approach for the client side stuff. Mind boggling that it’s 2024 and this is what we need to do in Bubble to return a json object.
I’m guessing this isn’t possible but thought I’d ask anyway.
I am trying to set up my plugin to return a simple object:
{“date”: “some date”,
“bubble_object”: “some custom bubble data type”
}
Like this:
However, when you save this, in the dropdowns you don’t get any ability to specify custom data types (or any app types you specified in the element fields)
Given that bubble plugin editor only gives us access to the basic types, I’m guessing what I’m trying to do isn’t possible.
But hopefully someone has a clever solution
I’m no pro so maybe there is a better way, but right now if your response is:
{
"date": "Jan 12, 2024",
"booking": "unique id"
}
You could turn it into
{
"date": "Jan 12, 2024",
"booking": {
"field1": "value1",
"field2": "value2",
"field3": "value3"
}
}
Then in the actual app if you create a new Time slot map everything one-for-one so field1 of the API type to the field1 of the app type, etc.
Thanks for the suggestion tyler by I’m not looking to create a new thing. I’m looking to pass in that thing to the plugin and then have it be returned inside my object.
The solution I came up with is to keep “booking” as a text field. My plugin returns a list of those objects, i.e.:
[
{“date”: <date_1>,
“booking”: <booking id 1>
},{“date”: <date_2>,
“booking”: <booking id 2>
},
…
]
This then populates a rpeating group. Inside that repeating group, I created another custom element that has two fields. One is the app type and one is a dynamic field of type “as app type”.
Then I put that element into each cell of the RG and populate the value with “current cells booking”. This element converts the text id into the actual bubble thing.
I have a plugin which returns app type data to client side. plugin works well in testing more but when i published the plugin it stopped working.
can anybody help to understand me whats the problem with it?
Hi @jared.gibb, Thanks for the post. This was very helpful. I use to publish object on client-side and it works perfectly while I test the plug-in. The moment I publish the plug-in data type (defined in API section of plug-in editor) doesn’t show up and plug-in does not work! any clue?
API in plug-in
API response
Fields and states in Element type
Code in update
function(instance, properties, context) {
function objectMapper(item){
let newObj = {};
for (let key in item) {
newObj['_p_' + key] = item[key];
}
return newObj;
}
function custom_sort(a, b) {
return new Date(a.date).getTime() - new Date(b.date).getTime();
}
let list_length = properties.idata.length();
var result_array=[];
if(properties.idata!=null){
var OraData=properties.idata.get(0,properties.idata.length());
var OraDates=properties.idates.get(0,properties.idates.length());
var TimeZ=properties.timezone;
for(i=0;i<OraDates.length;i++){
let curDate=OraDates[i];
let curDay=curDate.getDate();
let curMonth=curDate.getMonth()+1;
let curYear=curDate.getFullYear();
let partial_result=[]
for(k=0;k<OraData.length;k++){
//Actual event data
let startDate=OraData[k].get('start_date_date');
let endDate=OraData[k].get('end_date_date');
let duration=OraData[k].get('duration_number');
let repeat=OraData[k].get("event_repeat_option_os_event_repeat").get("display").toLowerCase();
let unique_id=OraData[k].get('_id');
let title=OraData[k].get('title_text');
let eventType=OraData[k].get('booking_type_option_os_event_type').get("display");
let eventColor=OraData[k].get('event_color_text');
//event duration overlap objects
let eventSartDate=luxon.DateTime.fromJSDate(startDate).setZone(TimeZ);
let eventEndDate=luxon.DateTime.fromJSDate(endDate).setZone(TimeZ);
let EventDay=eventSartDate.day;
let EventMonth=eventSartDate.month;
let EventYear=eventSartDate.year;
let EventEndDay=eventEndDate.day;
let EventEndMonth=eventEndDate.month;
let EventEndYear=eventEndDate.year;
let EventHour=eventSartDate.hour;
let EventMinute=eventSartDate.minute;
let EventEndHour=eventEndDate.hour;
let EventEndMinute=eventEndDate.minute;
let EventWeekday=eventSartDate.weekday;
let AdjustedStartDate=new Date(curYear,curMonth-1,curDay,EventHour,EventMinute);
let AdjustedEndDate=new Date(curYear,curMonth-1,curDay,EventEndHour,EventEndMinute);
if(repeat==="never"){
if(EventDay===curDay && EventMonth===curMonth && EventYear===curYear){
partial_result.push(objectMapper({"uniqid": unique_id,"title": title,"startdate": startDate,"enddate": endDate,"eventrepeat": repeat,"eventtime": "8:15 PM","eventtype": eventType,"filterdate":curDate,"adjustedstartdate":AdjustedStartDate,"adjustedenddate":AdjustedEndDate,"roundoffdate":curDate,"eventcolor":eventColor}));
}
}else{
let CurEndTime=new Date(curDate);
CurEndTime.setHours(23,59,59);
let CompareDate=new Date(EventYear, EventMonth-1,EventDay,EventHour,EventMinute);
if(repeat==="daily"){
if(CompareDate<=CurEndTime){
partial_result.push(objectMapper({"uniqid": unique_id,"title": title,"startdate": startDate,"enddate": endDate,"eventrepeat": repeat,"eventtime": "8:15 PM","eventtype": eventType,"filterdate":curDate,"adjustedstartdate":AdjustedStartDate,"adjustedenddate":AdjustedEndDate,"roundoffdate":curDate,"eventcolor":eventColor}));
}
}else if(repeat==="weekly"){
let curWeekday=curDate.getDay();
if(curWeekday===0){
curWeekday=7;
}
if(CompareDate<=CurEndTime && curWeekday===EventWeekday){
partial_result.push(objectMapper({"uniqid": unique_id,"title": title,"startdate": startDate,"enddate": endDate,"eventrepeat": repeat,"eventtime": "8:15 PM","eventtype": eventType,"filterdate":curDate,"adjustedstartdate":AdjustedStartDate,"adjustedenddate":AdjustedEndDate,"roundoffdate":curDate,"eventcolor":eventColor}));
}
}else{
if(CompareDate<=CurEndTime && curDay===EventDay){
partial_result.push(objectMapper({"uniqid": unique_id,"title": title,"startdate": startDate,"enddate": endDate,"eventrepeat": repeat,"eventtime": "8:15 PM","eventtype": eventType,"filterdate":curDate,"adjustedstartdate":AdjustedStartDate,"adjustedenddate":AdjustedEndDate,"roundoffdate":curDate,"eventcolor":eventColor}));
}
}
}
}
partial_result.sort(custom_sort);
for(j=0;j<partial_result.length;j++){
result_array.push(partial_result[j]);
}
}
window.myinstance.publishState("result",result_array);
//instance.publishState("result",result_array);
}
}
Any idea. Anyone else faced this problem. Plug-in working while test but not after published?
I tried with obfuscation and without. Tried publishing as private and public both. Still no luck!
are you sure that you’re result_array matches the format that the api connector expects. can you print that value out to the console or return it
additionally, you shouldn’t need to reference window.myinstance unless you are intentionally passing data to a different plugin element.
BUT, are you saying that the api data type does not appear in drop downs after you publish the plugin?
Hello everyone,
I was struggling with this issue as well, and thanks to jared.gibb for the well-documented solution you provided.
Here is another way of publishing an object as a state.
1. Create a Data Type
In this example, I’ve created a Data Type called Shared with one field.
2. Add the following to your element
- A field:
shared_typeand ‘App Type’ as the ‘Editor’ value. - A state:
sharedand ‘as shared_type’ as the ‘Type’.
3. Prepare the object to publish using these rules
- Turn every key to lowercase:
- Example: Fullname → fullname, isVerified → isverified
- Add the corresponding suffix to each key based on its type:
var to_publish = {
"name_text": "Robert",
"isverified_boolean": true,
}
4. Publish your states using the little trick below
// Function update
function(instance, properties, context) {
var currentUser$__original = context.currentUser.__original
var to_publish = {
"name_text": "Robert",
"isverified_boolean": true,
}
instance.publishState('shared', {
__original() {
var db = currentUser$__original().db;
var res = db.create(properties.shared_type, to_publish);
return res;
}
})
}
I hope this helps!
Damn, thank you so much, this woulve took me so long if i wouldnt have found your Post ![]()
Fiu this was some time ago, im late to the party
One thing that maybe no one mentioned here, is that bubble.io converts dots (‘.’) in attribute names to __dot__ when converting the example to type
ie:
{
"@odata.context" : "asdfadsfa"
}
would get converted to
"types": "{\"plugin_api.AAC\":{\"caption\":\"\",\"fields\":{\"_p_@odata__dot__context\":{\"ret_btype\":\"text\",\"caption\":\"@odata.context\",\"sample_value\":\"string value\",\"path\":[\"@odata.context\"]}
For people using json-to-bubble-object ( GitHub - Lottemint/json-to-bubble-object: Convert a JSON object to a Bubble object for plugin purposes. (Bubble.is) ) i have made a fork / pull request solving this issue.
Also, using several object definitions in different rest api calls is perfectly fine.






