Currently in Vuforia Studio 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 users can use - is to to create everything - different layouts version and to blank and to display them depending on the current inputs.
In some cases, it is possible to use a functionality of repeat region to create reports. So, we can use repeater widget (container ) to show a ThingWorx InfoTables. So, the repeater are mostly intended to be linked to services /added in the external data section / which result are InfoTables. The infoTables itself are handled as JSON object in the AngularJS environment in Vofria 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
When we have the data in Studio as value of the scope variable or as 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']);
and here an examle definition 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 implement 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.
A sample project demonstrating the suggested techniques is attached to this this post.
View full tip