如何使用另一个指令中的ngClick函数在一个指令中切换数据?

时间:2017-01-18 23:36:30

标签: javascript angularjs angularjs-directive angularjs-scope

我正在使用Angular 1.5.8构建天气应用程序,并且需要让用户能够在英制和公制测量之间来回切换温度和风速。

切换选项和所有天气信息(从外部API获取)都位于单独的指令中,但我想过将临时和风速数据移动到与切换选项相同的指令,然后使用$ broadcast或$ emit显示天气指令中的数据和转换。这是最好的方法吗?如果没有,会是什么?

切换位置的指令:

app.directive('topBar', topBar);

function topBar() {
    return {
        template: 
        '<div class="changeTemp" ng-click="vm.changeTempUnit()">' +
            '<span ng-class="vm.fahrClass">&deg;F</span>' +
            '<span>/</span>' +
            '<span ng-class="vm.celsClass">&deg;C</span>' +
    '</div>',
        restrict: 'E',
        scope: {},
        controller: TopBarController,
        controllerAs: 'vm'
    };
}

function TopBarController() {
    var vm = this;

    vm.celsClass = 'unselected';
    vm.changeTempUnit = changeTempUnit;
    vm.fahrClass = 'selected';
    vm.temp;
    vm.windSpeed;

    function changeTempUnit() {
        if (vm.fahrClass === "selected") {
            vm.fahrClass = 'unselected'; //F unselected
            vm.celsClass = 'selected'; //C selected
            vm.temp = Math.round((vm.temp - 32) * 5 / 9); //Celsius
            vm.windSpeed = (vm.speed * 0.44704).toFixed(0); // M/S
        } else if (vm.celsClass === 'selected') {
            vm.celsClass = 'unselected'; //C unselected
            vm.fahrClass = 'selected'; //F selected
            vm.temp = Math.round(vm.temp * 1.8 + 32); //Fahren
            vm.windSpeed = (vm.speed / 0.44704).toFixed(0); //MPH
        }
    }
}

天气显示的指令

app.directive('weather', weather);

function weather() {
    return {
        template:
  '<div>' +
      'Temp: {{vm.temp}}&deg;' + '<br>' +
      'Wind Speed: {{vm.windSpeed}}' +
  '</div>',
        restrict: 'E',
        scope: {},
        controller: WeatherController,
        controllerAs: 'vm'
    };
}

WeatherController.$inject = ['weatherService'];

function WeatherController(weatherService) {
    var vm = this;

    vm.temp;
    vm.windSpeed;

    activate();

    function activate() {
        return weatherService.getWeather().then(function(data) {
                weatherInfo(data);
            });
    }

    function weatherInfo(data) {
        vm.temp = Math.round(data.main.temp); //Fahren
        vm.windSpeed = (data.wind.speed).toFixed(0); //MPH
    }
}

Plunker link

1 个答案:

答案 0 :(得分:0)

使用组件

我的第一个建议是使用AngularJs 1.5 + component api。组件假设您已经选择了几个指令定义对象值。

如果您对这些问题的回答是肯定的,那么您应该使用component api。

  1. 您的指令是否有模板?
  2. 你的指令是否有一个孤立的范围?
  3. 您的指令是否有控制器?
  4. 您的指令是否仅限于元素?
  5. <top-bar>转换为组件将如下所示

    app.component('topBar', {
        template: 
                '<div class="changeTemp" ng-click="$ctrl.changeTempUnit()">' +
                '<span ng-class="$ctrl.fahrClass">&deg;F</span>' +
                '<span>/</span>' +
                '<span ng-class="$ctrl.celsClass">&deg;C</span>' +
                '</div>',
        controller: TopBarController,
        bindings: {}
    });
    
    function TopBarController() {
    ...
    }
    

    注意模板如何使用$ctrl来引用控制器而不是vm。对于组件,$ctrl是默认值。

    可能的解决方案

    可以使用

    emitbroadcast,这可能是使用它们的理想场所!但如果你能避免它们,那么就不要依赖它们。

    这是一个选项

    将计算移至服务

    <强>顶栏

    app.component('topBar', {
        template: 
                '<div class="changeTemp" ng-click="$ctrl.changeTempUnit()">' +
                '<span ng-class="$ctrl.fahrClass">&deg;F</span>' +
                '<span>/</span>' +
                '<span ng-class="$ctrl.celsClass">&deg;C</span>' +
                '</div>',
        controller: ['conversionService', TopBarController],
        bindings: {
    
        }
    })
    
    function TopBarController(conversionService) {
        var vm = this;
    
        vm.celsClass = 'unselected';
        vm.changeTempUnit = changeTempUnit;
        vm.fahrClass = 'selected';
    
        function changeTempUnit() {
            if (vm.fahrClass === "selected") {
                vm.fahrClass = 'unselected'; //F unselected
                vm.celsClass = 'selected'; //C selected
                conversionService.selectedUnit = conversionService.tempUnits.celsius;
            } else if (vm.celsClass === 'selected') {
                vm.celsClass = 'unselected'; //C unselected
                vm.fahrClass = 'selected'; //F selected
                conversionService.selectedUnit = conversionService.tempUnits.farhenheit;
            }
        } 
    }
    

    <强> ConversionService

    app.service('conversionService', function() {
        var service = this;
    
        service.tempUnits = {
            farhenheit: 'farhenheit',
            celsius: 'celsius'
        };
    
        service.selectedUnit = 'farhenheit';
    
        service.convertTemperature = function(temp, tempUnit) {
            if (service.selectedUnit === tempUnit) {
                return temp;
            } else if (service.selectedUnit === service.tempUnits.farhenheiht) {
                return Math.round(temp * 1.8 + 32);
            } else if (service.selectedUnit === service.tempUnits.celsius) {
                return Math.round((temp - 32) * 5 / 9);
            } else {
                throw Error("Invalid unit");
            }
        } 
    });
    

    <强>天气

    app.component('weather', {
        template:
            '<div>' +
                'Temp: {{ $ctrl.getTemp() }}&deg;' + 
                '<br>' +
                'Wind Speed: {{ $ctrl.windSpeed }}' +
            '</div>',
        controller: ['conversionService', 'weatherService', WeatherController],
        bindings: {}
    });
    
    function WeatherController(conversionService, weatherService) {
        var ctrl = this;
    
        ctrl.temp;
        ctrl.windSpeed;
    
        ctrl.conversionService = conversionService;
    
        activate();
    
        function getTemp() {
            return ctrl.conversionService.convertTemperature(ctrl.temp, ctrl.conversionService.tempUnits.farhenheit);
        }
    
        function activate() {
            return weatherService.getWeather()
                .then(weatherInfo);
        }
    
        function weatherInfo(data) {
            ctrl.temp = Math.round(data.main.temp); //Fahren
            ctrl.windSpeed = (data.wind.speed).toFixed(0); //MPH
        }
    }
    

    Updated version of your plunk

    由于当ng-click之类的指令评估其绑定表达式时,Angular会进行脏检查,因此<weather>的模板也将被检查并且表达式

    {{ $ctrl.conversionService.convertTemperature($ctrl.temp, $ctrl.conversionService.tempUnits.farhenheit) }}
    

    将被评估。