【问题标题】:select option when the model is updated before ng-options is loaded在加载 ng-options 之前更新模型时选择选项
【发布时间】:2015-08-12 04:12:56
【问题描述】:

我有一个“状态选择”指令,它使用基于国家代码的状态列表填充选择元素。该指令监视 countryCode 的更改以更新提供给 ng-options 的属性。

我现在正在尝试从我的控制器设置 model.countryCode 和 model.sateCode,但是当 countryCode 更改时填充状态选择,模型值会在选项有机会加载之前更新。

在我加载选项后,如何确保 select 确实选择了其 ng-model 中引用的选项?

这是我的指令:

.directive( 'stateSelect', [ 'CDN_VIEW', 'locationService', function( CDN_VIEW, locationService ) {
    return {
        restrict: 'E',
        scope: {
            'ngModel': '=',
            'country': '=',
        },
        link: function stateSelect( $scope, elements, attrs ) {
            $scope.states = null;
            function loadCountryStates( countryCode ) {
                if ( !countryCode ) {
                    return false;
                }

                $scope.ngModel = undefined;
                locationService.getCountryStates( countryCode ).then ( function getStates( states ) {
                    $scope.states = states;
                } );
            }

            $scope.$watch( 'country', loadCountryStates );
        },
        templateUrl: 'states.html'
    };
} ] )

模板:

<select ng-model="ngModel" ng-options="s.code as s.name for s in states">
    <option value="" disabled>select state</option>
</select>

指令的用法如下:

<state-select ng-model="info.stateCode" country="info.countryCode">

这是我在控制器中所做的:

function setDetectedLocation( location ) {
    $scope.info.countryCode = location.countryCode;
    $scope.info.stateCode = location.stateCode;
    $scope.info.city = location.city;
}

locationService.getLocation().then( setDetectedLocation, locationError );

当我手动填写选择时,它可以工作,如果我运行 getLocation 两次,当国家/地区的州已经加载时,它也可以工作。

任何指针?

【问题讨论】:

  • 我通过将控制器的info.stateCode 从选择ngModel 中取消链接并观察前者的变化来稍微改善了这种情况。这修复了州列表的第一次加载,但是当国家选择改变时问题仍然存在。

标签: javascript angularjs angularjs-directive ng-options


【解决方案1】:

我终于解决了这个问题。诀窍是分离控制器模型(持有实际值的模型)和指令的选择模型(持有选定选项的模型)。这样我就可以手动观察两者的变化,并在需要时更新值。

以下是对指令的更改:

scope: {
    'ngModel': '=',
    'country': '=',
},
link: function stateSelect( $scope, element, attrs ) {
    $scope.states = null;
    $scope.state = { 'code': undefined };

    function loadCountryStates( countryCode ) { ... }

    $scope.$watch( 'country', loadCountryStates );

    // watch manual change on select
    $scope.$watch( 'state.code', function( stateCode ) {
        $scope.ngModel = stateCode;
    } );

    // watch further changes to the model
    $scope.$watch( 'ngModel', function( stateCode ) {
        if ( stateCode ) {
            $scope.state.code = stateCode;
        }
    } );
}

这是对模板的更改:

<select ng-model="state.code" ng-options="s.code as s.name for s in states">
</select>

注意选择现在如何链接到指令的state.code,然后通过ngModel 与控制器属性进行监视和同步。

我不知道为什么原来的方法不起作用!

【讨论】:

    【解决方案2】:

    您可以创建一个 initStateTo 参数,该参数在设置时将初始化指令中的状态值。

         $scope.info.initStateTo = "CA";
    
         <state-select ng-model="info.stateCode" country="info.countryCode" 
                  initStateTo="info.initStateTo">
    
                $scope.ngModel = undefined;
                locationService.getCountryStates( countryCode ).then (
                    function getStates( states ) {
                       $scope.states = states;
                       if($scope.initStateTo) {
                          $scope.ngModel = $scope.initStateTo;
                          $scope.initStateTo = undefined;
                       }
                     } );
    

    【讨论】:

    • 对不起,我不明白这一点。 ngModel 和 initStateTo 范围属性之间有什么区别,如果两者都从控制器同时设置为相同的值?这不等于指令中的 $scope.ngModel = $scope.ngModel 吗?谢谢。
    • 您指出“模型值在选项有机会被加载之前更新”,这是因为设置国家会导致调用一个服务来填充所有状态。我建议的解决方案将在国家服务设置所有状态后设置状态值,以便该值正确并在加载所有值后设置。如果这不是你想要做的,那么我误解了这个问题。
    • 我确实尝试过这个,但令人惊讶的是 countryCode 的手表回调没有按时调用。我猜 Angular 会等到摘要周期结束来处理回调,所以似乎没有办法在设置模型值之前加载选项:\
    • 不可能。位置服务调用的承诺在调用完成之前不会返回。这就是诺言的运作方式。也许您应该发布 getCountryStates() 的代码,但它的执行方式有问题。
    • Scott,promise 没有问题,而是当 watch 回调被执行时——这不是在值被修改后立即发生的。所以一旦 promise 被解决,两个作用域属性就会被更新,然后 watch 回调就会被执行。至此,stateCode 已经设置好了,所以再根据设置的 countryCode 值来确定状态选项已经太迟了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-09
    • 1970-01-01
    • 1970-01-01
    • 2016-03-08
    • 2014-07-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多