1

I have the following code in my directive.

//Directive Code
var BooleanWidgetController = function ($scope, $filter) {

    $scope.booleanOptions = [
        {
            displayText: '-- ' + $filter('i18n')('Widgets.Generics.Select') + ' --'
        },
        {
            value: 1,
            displayText: $filter('i18n')('Widgets.Generics.Yes')
        },
        {
            value: 0,
            displayText: $filter('i18n')('Widgets.Generics.No')
        }
    ];

    //Added inside watch because query was not being updated if filterUpdated was called using ng-change
    $scope.$watch('query', $scope.filterUpdated);
};

app.directive('acxBooleanColumnHeaderFilter', function () {
    return {
        restrict: 'A',
        replace: true,
        controller: ['$scope', '$filter', BooleanWidgetController],
        scope: {
            query: '=',
            filterUpdated: '&submit',
            columnHeading: '@'
        },
        templateUrl: 'mailSearch/directives/columnHeaderWidgets/boolean/booleanColumnHeaderWidget.tpl.html'
    };
});

//Template
<div class="columnHeaderWidget">
<div class="title pull-left">{{columnHeading}}</div>
<div style="clear:both"></div>
<select ng-model="query" ng-options="option.value as option.displayText for option in booleanOptions">
</select>

The current way is working fine. But when I try to do something like this.

<select ng-model="query" ng-change="filterUpdated" ng-options="option.value as option.displayText for option in booleanOptions">

The $scope.query is not updating fast enough. So the $scope.query is being updated after $scope.filterUpdated is being called. What am I missing here?

1 Answers1

0

This is far more complicated than what it seems, if you want to understand the real problem have a look at this: "Explaining the order of the ngModel pipeline, parsers, formatters, viewChangeListeners, and $watchers".

To summarize, the issue is that: when the ng-change function gets triggered the bound scope properties of your directive (in your case query) have been updated in the scope of the directive, but not in the scope from where they were inherited from.

The workaround that I would suggest would be:

  • Change your filterUpdated function so that it will take the query from a parameter, rather than taking it from its scope, because its scope hasn't been updated yet.

  • Create an intermediate function in the scope of your directive in order to catch the ng-change event and the updated scope properties.

  • Use that intermediate function to call the filterUpdated function and pass the query as a parameter.

Something like this:

var BooleanWidgetController = function ($scope, $filter) {

    $scope.booleanOptions = [
        {
            displayText: '-- ' + $filter('i18n')('Widgets.Generics.Select') + ' --'
        },
        {
            value: 1,
            displayText: $filter('i18n')('Widgets.Generics.Yes')
        },
        {
            value: 0,
            displayText: $filter('i18n')('Widgets.Generics.No')
        }
    ];

    $scope._filterUpdated = function(){ $scope.filterUpdated({query:$scope.query}); };        

    /** Remove this, you won't need it anymore
     ** $scope.$watch('query', $scope.filterUpdated);
     **/
};

Change your HTML, make it look like this:

<select ng-model="query" ng-change="_filterUpdated" ng-options="option.value as option.displayText for option in booleanOptions">

And remember to change the filterUpdated to use the query as a parameter, like this:

function filterUpdated(query){
   ...
}
Community
  • 1
  • 1
Josep
  • 12,926
  • 2
  • 42
  • 45
  • My code is already working as mentioned in the question, But what I am not able to understand is why the query scope variable not updating fast enough. If I do a cascaded call like $scope.query = 0; $scope.filterUpdated();, the filterUpdated function will not have the $scope.query as 0 rather $scope.query will have previous value. – Mohit Suman Sep 25 '14 at 07:08