How to detect the state change in the status bar?


I would like to ask question regarding to kibana plugin.

I am trying to detect the change every time the filter in status bar is changed for dashboard.

I wrote the code in the controller as below but the result is not I have expected.

  $scope.$watch(getAppState, function (appState) {
    $scope.state = appState;

    var type = typeof($scope.state)
    var length = $scope.state.filters.length

    $scope.length = "Type : " + type + " Len : " + length

I wrote the template as below.

<div ng-controller="PluginController">
<!--  <h1 ng-repeat="i in bucket">{{i.label}} ,  {{i.value}}</h1> -->
<h3>Current timerange minimum : {{min._d}}</h3>
<h3>Current timerange maximum : {{max._d}}</h3>
<h3>Current : {{state['filters']}} Length : {{state['filters'].length}}</h3>
<h3>Length : {{length}}</h3>

In the template , Length : {{state['filters'].length}} , detects the number of filters properly but Length : {{length}} does not.

I am referencing the same object but I dont know why but results differently.

May I ask why this is happening?

I first tried
$scope.$watch('state.$newFilters', function (filters) { });
but it only picked up when the filter was initially added.
So I am now trying using watching appState.

Is state.filters defined by anything else before assignment in the appState watcher? What's the stringified version of the length 2 filter? Maybe duplicate app state and global state filters?

Hello @jbudz

Thank you for the reply.

I found that I am unable to accessing to the filters (array object).
$scope.state is returning the correct value.

Below is my current code in controller.

module.controller('PluginController', function ($scope,timefilter,getAppState,Private) {
  // Example of getting time range
  $scope.min = timefilter.getBounds().min;
  $scope.max = timefilter.getBounds().max;

  $scope.str1= "Accessed to the controller!";

  $scope.$watch(getAppState, function (appState) {
    $scope.state = appState;

    var val               = $scope.state;

    $scope.val1           = val;
    $scope.val1_type      = typeof( val );
    $scope.val1_isArray   = Array.isArray(val.filters);

    $scope.val1_filter1   = val.filters[0];
    $scope.val1_filter2   = val.filters[1];


In template , val1 returns correct value in every change in status bar which is like,

val1 : {"title":"New Dashboard","panels":[{"id":"datatable-sample","type":"visualization","panelIndex":1,"size_x":10,"size_y":2,"col":1,"row":1},{"id":"New-Visualization","type":"visualization","panelIndex":2,"size_x":10,"size_y":4,"col":1,"row":3}],"options":{"darkTheme":false},"uiState":{"P-1":{"vis":{"params":{"sort":{"columnIndex":null,"direction":null}}}}},"query":{"query_string":{"query":"*","analyze_wildcard":true}},"filters":[{"meta":{"index":"filebeat-*","key":"beat.hostname.keyword","value":"Kibana-dev","disabled":false,"negate":false,"alias":null},"query":{"match":{"beat.hostname.keyword":{"query":"Kibana-dev","type":"phrase"}}},"$state":{"store":"appState"}}]}

However , val.filters[0]; and val.filters[1]; returns nothing.

Array.isArray returned true.

Could you please educate me how to access the objects in side filters array from the controller?

Can you check if the watcher for getAppState is triggering when a filter is changed? I'm guessing it runs once on page load but isn't firing after, leaving $scope.val1_filter1 with its initial page load value while $scope.state is updated by reference. If this is what's happening, you can add true to the 3rd watch argument to perform a deep comparison, see$rootScope.Scope#$watch.

Hi @jbudz.

Your assumption is right. watcher for getAppState is not called everytime.

Timestamp in the below screenshot had not changed even if I change the filters. But the object for $scope.state was changing everytime.

I was able to correctly reference the filters object by setting objectEquality to true.

  $scope.$watch(getAppState, function (appState) {
    $scope.state = appState;

    $            = new Date();
    $scope.val1           = $scope.state;
    $scope.val1_type      = typeof( $scope.state );
    $scope.val1_isArray   = Array.isArray($scope.state.filters);

    $scope.str2           = JSON.stringify($scope.state.filters);
    $scope.val1_filter1       = $scope.state.filters[0];
    $scope.val1_filter1_query = $scope.state.filters[0].meta;
    $scope.val1_filter2       = $scope.state.filters[1];
    $scope.val1_filter2_query = $scope.state.filters[1].meta;


So the problem was ,

  1. I was not properly understanding javasript passes reference when setting object to variable.
  2. watcher was not processing for getAppState in status bar when objectEquality was set to false.

Thanks for the support!