cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Community Tip - New to the community? Learn how to post a question and get help from PTC and industry experts! X

How to create 2D components using Javascript from a array of objects (JSON-like structure)

100% helpful (1/1)

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:

 

2020-04-29_17-43-23.jpg

 

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

2020-04-29_18-18-04.jpg

 

 

 

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.

Comments

Hi, Roland

 

I have some rather basic questions to ask.

 

1, How do you choose between these two? What is the pros and cons of one another?

  • var aVariable = 'variable';
  • $scope.aVariable = 'variable';

2, Should "$scope.itemList=JSON.parse(data);" be "$scope.itemList=JSON.parse(JSON.stringify(data));"?

thanks a lot.

Uploaded 2 additional Vuforia Studio Projects where the handling was demonstrated

Version history
Last update:
‎Jan 16, 2024 04:57 AM
Updated by:
Labels (1)
Attachments
Contributors