简体   繁体   中英

Angular: updating view with value passed from directive to controller

Budding web developer here struggling with updating the view from my controller.

I'm using highmaps and angular to build a neat selection tool for my web app. I've got a directive nested inside the scope of a controller. I would like this directive to update a value ( selectedCountry ) stored in the controller. Then, I'd like the controller to display the up to date selectedCountry value on the view.

I've checked that the directive is passing the correct selectedCountry value to the parent controller. However, the controller is not updating the view to match the updated value. I would greatly appreciate if someone could take a look at this.

Demo Here: http://jsfiddle.net/frauLLmr/5/

index.html

<div ng-app="myApp">
  <div ng-controller="GraphController as graphCtrl">
    <div> {{graphCtrl.showSelectedCountry()}} </div>
    <div> {{graphCtrl.selectedCountry}} </div>
    <high-chart-directive update-selected-country='graphCtrl.updateSelectedCountry(newCountry)'></high-chart-directive>
  </div>
</div>


app.js

var myApp = angular.module('myApp', []);
myApp.controller('GraphController', function() {
  var self = this;
  self.selectedCountry = 'unselected';
  var outsideScopeTest = function() {
    alert('selectedCountry (from controller scope): ' 
        + self.selectedCountry);
  };
  self.updateSelectedCountry = function(newCountry) {
    self.selectedCountry = newCountry;
    outsideScopeTest();
  };
  self.showSelectedCountry = function() {
    return self.selectedCountry;
  };
});

myApp.directive('highChartDirective', function () {
  return {
    restrict: 'E',
    scope: {
      updateSelectedCountry: '&'
    },
    link: function(scope, element) {
      Highcharts.mapChart(element[0], getMapOptions(mapClick));

      function mapClick(event) {
        scope.updateSelectedCountry({newCountry: event.point.name});
        alert('selectedCountry (from directive scope): ' 
        + event.point.name);
      }
    }
  };

  function getMapOptions(callback) {
    return {
      title: {
        text: ''
      },
      mapNavigation: {
        enabled: true,
        buttonOptions: {
          verticalAlign: 'bottom'
        }
      },
      series: [{
        data: getTestCountries(),
        mapData: Highcharts.maps['custom/world-highres'],
        // TODO-chantelle: figure out how geoJSON joinBy works
        joinBy: 'hc-key',
        name: 'Emission per capita',
        states: {
          hover: {
            color: '#9370DB'
          }
        },
        dataLabels: {
          enabled: false,
          format: '{point.name}'
        }
      }],
      plotOptions: {
        series: {
          events: {
            click: function(event) {
              callback(event);
            }
          }
        }
      }
    };
  }

  function getTestCountries() {
    return [{
      "hc-key": "ca",
      "value": 0
    }, {
      "hc-key": "br",
      "value": 1
    }, {
      "hc-key": "ru",
      "value": 2
    }];
  }
});

the issue is that Highcharts.mapChart(element[0], getMapOptions(mapClick)); is not part of the angular scope. So any calls here will not trigger the angular app to refresh. You need to force angular to update using $scope.apply();

var outsideScopeTest = function() {
    alert('selectedCountry (from controller scope): ' 
    + selfc.selectedCountry);

    // force angular update
    $scope.$apply();

};

Try this

<div ng-app="myApp">
  <div ng-controller="GraphController as graphCtrl">
    <div> {{graphCtrl.showSelectedCountry()}} </div>
    <div> {{graphCtrl.selectedCountry}} </div>
    <high-chart-directive update-selected-country='graphCtrl.updateSelectedCountry(newCountry)'></high-chart-directive>
  </div>
</div>

the js

var myApp = angular.module('myApp', []);
myApp.controller('GraphController', function($scope) {
  var self = this;
  self.selectedCountry = 'unselected';
  var outsideScopeTest = function() {
    alert('selectedCountry (from controller scope): ' 
        + self.selectedCountry);
      $scope.$apply();
  };
  self.updateSelectedCountry = function(newCountry) {
    self.selectedCountry = newCountry;
    outsideScopeTest();
  };
  self.showSelectedCountry = function() {
    return self.selectedCountry;
  };
});

myApp.directive('highChartDirective', function () {
  return {
    restrict: 'E',
    scope: {
      updateSelectedCountry: '&'
    },
    link: function(scope, element) {
      Highcharts.mapChart(element[0], getMapOptions(mapClick));

      function mapClick(event) {
        scope.updateSelectedCountry({newCountry: event.point.name});
        alert('selectedCountry (from directive scope): ' 
        + event.point.name);
      }
    }
  };

  function getMapOptions(callback) {
    return {
      title: {
        text: ''
      },
      mapNavigation: {
        enabled: true,
        buttonOptions: {
          verticalAlign: 'bottom'
        }
      },
      series: [{
        data: getTestCountries(),
        mapData: Highcharts.maps['custom/world-highres'],
        // TODO-chantelle: figure out how geoJSON joinBy works
        joinBy: 'hc-key',
        name: 'Emission per capita',
        states: {
          hover: {
            color: '#9370DB'
          }
        },
        dataLabels: {
          enabled: false,
          format: '{point.name}'
        }
      }],
      plotOptions: {
        series: {
          events: {
            click: function(event) {
              callback(event);
            }
          }
        }
      }
    };
  }

  function getTestCountries() {
    return [{
      "hc-key": "ca",
      "value": 0
    }, {
      "hc-key": "br",
      "value": 1
    }, {
      "hc-key": "ru",
      "value": 2
    }];
  }
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM