Accessing bucket data from AngularJS controller for HTML Timeseries widget

Hi!

I’d like to inquire if there is any recommendation on how to access and manipulate data array from bucket in the AngularJS controller of a dashboard view.

I’ve been expanding from the original helloWidget example in documentation and trying to apply it to a HTML Timeseris widget. In this type of widget I find the data is made available via AngularJS expressions and can be accessed using numeric indexes. For example:

  <p><strong>Timestamp</strong> is: {{value[0].ts}}</p>
  <p><strong>Temperature</strong> is:... {{value[0].temperature}}</p>
  <p>Value: {{value}}</p>

Will display the ‘ts’ and ‘temperature’ records in the ‘value’ bi-dimensional array.

displayedvalues

But I need a way to access and consume this data in another js script. So I thought I could put a function in the controller to create a JSON in the HTML that I can use it in another separate script in the dashboard.

But so far all my attempts were not successful and result in ‘undefined’ error, even though the data is available in the $scope.value. This sequence will produce the following results:

console.log('Value: ', $scope.value);
console.log('Value[0]: ', $scope.value[0]);
console.log('Value[0].ts: ', $scope.value[0].ts);

Console:

I admit I’m pretty new to AngularJS and pretty much learning as I go. However I can’t find the reason why I’m unable to access de data rad from bucket from inside the controller even though the values appear to be there.

Any ideas that can point me in the right direction?

For context this is a screenshot of the dashboard, configuration and source code.

helloWidget.js:

angular.module('helloWidget', []).directive('helloWidget', function () {
    return {
        restrict: 'EA',
        scope: {
            source : "=",
            ts:      "=",
            value:   "="
        },
        templateUrl: function(){
            let url = document.querySelector("script[src*='helloWidget.js']");
            return url.src.replace('.js','.html');
        },
        controller: ["$scope", function($scope){
            console.log("controller initialized! scope is", $scope);
            
            // listeners for process source changes (if required)
            $scope.$watch('source', function(newVal, oldVal) {
                console.log("Source has changed:", newVal, oldVal);
            });
            
            // listeners for process value changes (if required)
            $scope.$watch('value', function(newVal, oldVal) {
                console.log("Value has changed:", newVal, oldVal);
            });
            
        
            console.log('THE SCOPE: ', $scope);

            console.log('Value: ', $scope.value);
            console.log('Value[0]: ', $scope.value[0]);
            //console.log('Value[0].ts: ', $scope.value[0].ts);            
            
            
            let myValue = [];
            myValue.push($scope.value);
            
            
            console.log('MyValue: ', myValue[0]['temperature']);
            console.log('Source: ', $scope.source);
            
            $scope.sayHello = function () {
                console.log("hello!");
            }
            


        }]
    }
});
helloWidget.html:

<div>
  <h3>Hello World from AngularJS directive!</h3>
  <p><strong>Timestamp</strong> is: {{value[0].ts}}</p>
  <p><strong>Temperature</strong> is:... {{value[0].temperature}}</p>
  <p>Value: {{value}}</p>
  <canvas id="myChart"></canvas>
  <canvas id="myChart2"></canvas>
</div>
.
.
.

Thanks!

Hi @jjo458

Try having the console.log inside the listener for value:

// listeners for process value changes (if required)
$scope.$watch('value', function(newVal, oldVal) {
  console.log("Value has changed:", newVal, oldVal);

  console.log('THE SCOPE: ', $scope);
  console.log('Value: ', $scope.value);
  console.log('Value[0]: ', $scope.value[0]);
});

On load, $scope.value is empty and will update once the data from the API is received. When the value changes, you then know for a fact that $scope.value is populated. You can then call a function each time the value changes.

function parseValue() {
  console.log("Checking if value is populated ", $scope.value[0]);
  // Insert here your functionality
 // ...
}

// listeners for process value changes (if required)
$scope.$watch('value', function(newVal, oldVal) {
  console.log("Value has changed:", newVal, oldVal);

  parseValue();
});

Hi @jaimebs, thanks for the suggestions, they make sense. I did a quick test by trying to access the array from inside the listener, but had the same results as before.

If I print $scope.value I see the data is in there as “0:{“temperature”: 29, “ts”: 1712145602000}”, but if i try to get the element 0 as $scope.value[0] it returns an ‘undefined’. Same if I try to use the argument ‘newVal’.

Here is a couple of data points demonstrating this intriguing behavior:

listener:

            // listeners for process value changes (if required)
            $scope.$watch('value', function(newVal, oldVal) {
                console.log("Value has changed:", newVal, oldVal);

                console.log('$scope.value: ', $scope.value);
                console.log('$scope.value[0]: ', $scope.value[0]);
                
                console.log('newVal: ', newVal);
                console.log('newVal[0]: ', newVal[0]);
            });

Result:

Hi @jjo458

Okay, I know what the issue might be, in this case where you are using the HTML Time Series widget the correct watcher would be $watchCollection instead of $watch, as the object being watched is an array.

// listeners for process value changes (if required)
$scope.$watchCollection('value', function(newVal, oldVal) {
  console.log("Value has changed:", newVal, oldVal);

  console.log('THE SCOPE: ', $scope);
  console.log('Value: ', $scope.value);
  console.log('Value[0]: ', $scope.value[0]);
});

From my tests this should now print the correct values

Indeed! That did the trick! I guess my issues here were the lack of experience with asynchronous programming plus not understanding the difference between an array and an array of arrays in the context of AngularJS ‘watch’ in controller. Hopefully this post will help others stumbling the same trail.

Muchas gracias Jaime, saludos!

1 Like