Hi @lbviana ,
I think it is not possible to create a dynamically widgets- on the fly - at runtime to add or to remove widgets. Better to say it is not possible in a supported way. So, the most supported approach which you can use is to you to create everything - different layouts version and to blank and to display them depending on your inputs.
In some cases it is possible to use a functionality of repeat region to create reports (only 2D elements /widgets ). So we can use repeater to show a Thing Worx Info Tables. So the repeater are mostly intended to be linked to services /added in the external data section / which result are Info Tables. The infoTables itself handled as JSON object in the AngularJS environment in Studio.
Therefore we can try to provide directly a data as global variable in Studio or we can read it via the http service from a project directory (e.g. upload). So the follow example will read a json file "ItemList.json" from the upload folder and will set to the variable $scope.itemList:
//Global Variables
var pjson ="ItemList.json"; //JSON File Name without extension
$scope.itemList={}; //global $scope variable
gotJSON=function(data){
{
$scope.itemList=JSON.parse(data);}
catch(ex){ console.warn(ex);}
}
doRead=function (jsonFile){
fetch(jsonFile)
.then(response=>response.text())
.then(data=>gotJSON(data))
}
$scope.Init=function() {
doRead('app/resources/Uploaded/'+pjson);
}
/////
$scope.$on('$ionicView.afterEnter',function(){
$scope.Init();}) //event: when 2d View loaded
//the code will read the complette JSON File and
//assignee it to a jsonData global variable
Of course we can also use a static list to set it to a variable e.g.
var ItemList = [
{"display":"France","id_num":0,"checked":true,"value":"Paris" ,"src":"test.svg","someText":"some Text123"},
{"display":"Italy","id_num":1,"checked":false,"value":"Rome" ,"src":"test1.svg","someText":""},
{"display":"Spain","id_num":2,"checked":false,"value":"Madrid" ,"src":"test2.svg","someText":""},
{"display":"UK","id_num":3,"checked":false,"value":"London" ,"src":"test3.svg","someText":""},
{"display":"Germany","id_num":4,"checked":false,"value":"Berlin" ,"src":"test4.svg","someText":"-->"},
{"display":"Norway","id_num":5,"checked":false,"value":"Oslo" ,"src":"test.svg","someText":""},
{"display":"Switzerland","id_num":6,"checked":false,"value":"Bern" ,"src":"test1.svg","someText":""},
{"display":"Greece","id_num":7,"checked":false,"value":"Athens" ,"src":"test2.svg","someText":""},
{"display":"France","id_num":8,"checked":true,"value":"Paris" ,"src":"test3.svg","someText":"other Text"}
];//some list got from anywhere
:
So now when we have the data in Studio as value of a scope variable or global variable we can try to set it to an repeat region and create something similar as simple report:

The clue here is to set the list to an app parameter and to link then the application parameter to the repeater data and also to the different repeater elements /widgets in the row/columns of the repeater. This is not trivial because it is not intent usage of the repeater but for such simple case it will work

To be able to link the elements to the correct repeater row we need a filter. Here an example of filter function. I need a window area because this is the only way to pass variable between 2 different calls of the filter. Here an example for filter definition for a label:
//filter for the checkbox element
//console.warn("filterLabel1");
if(!window.my_filter3) window.my_filter3=1;
else {
if(window.my_filter3>= value.length) window.my_filter3=1;
else {window.my_filter3++;} }
return(value[window.my_filter3-1]['someText']);
e.g. for a image widget:
//filter for the Image Widget element //
//console.warn("filterImage1");
if(!window.my_filter3) window.my_filter3=1;
else {
if(window.my_filter3>= value.length) window.my_filter3=1;
else {window.my_filter3++;} }
return('app/resources/Uploaded/'+value[window.my_filter3-1]['src']);
With little more work we can also implment a function which could change the value on click - e.g. a checkbox to set it to true or false and to update the list:
//==================================================================
$scope.changeValueInJson= function (obj,id_num,field2change, new_value)
{
if(new_value==undefined) return;
try{if( obj[0][field2change]==undefined) return;}catch(wrong){console.error("error::"+wrong);return;}
for (var i = 0; i < obj.length; i++){
if (obj[i]['id_num'] == id_num){
obj[i][field2change]= new_value;}}
$scope.app.params["ItemList"] = "";
$scope.app.params["ItemList"] = JSON.parse(JSON.stringify(obj));//check value
$scope.$applyAsync();
}
//==================================================================
twx.app.fn.clickItemInRepeater = function(item,list,isMultiSelect)
{
console.warn("called clickItemInRepeater()");
$scope.changeValueInJson(list,item.id_num,'checked', item.checked?false:true)
console.log("clickItemInRepeater::ROW Selected:: "+JSON.stringify(item))
$scope.setWidgetProp('textArea-2','text',JSON.stringify(item))
$scope.$applyAsync();
};
//==================================================================
The callback twx.app.fn.clickItemInRepeater = function(item,list,isMultiSelect) {... will fire when an element is clicked.
At the end we will have a list with labels where their content and values and number of rows is defined from a Json object- here the number of row is flexible but the number of column is fixed. Of course, we can define more columns in a row and then with filter (similar to the example) to drive their visibility.
I attached a sample project to this post.