web-dev-qa-db-ja.com

Angularjs:ng-modelの更新時に更新しないを選択

次の例を作成したので、何が起きているのかを正確に確認できます。 http://jsfiddle.net/8t2Ln/101/

Ng-optionsを使用しても同じことが起こります。この方法で行う理由は異なりますが、例の簡略化のため、その部分は省略しました。

ご覧のとおり、デフォルトでは2つのオプションがあります。 ngモデルの選択された値をselectの隣に表示しているので、それが何であるかを見ることができます。上部のピースを使用して3番目のオプションを追加すると、選択の横に表示されるng-model値によって証明されるように、値がその新しいオプションの値に設定されますが、選択自体は変更されず正しい値を表示します選択されました。

以下は、リンクのサンプルコードです。

var testApp = angular.module('testApp', ['ngRoute']);

testApp.controller('Ctrl', function ($scope) {

    $scope.newInput = '';
    $scope.inputDevice = [
        {
            value: '1',
            label: 'input1'
        },
        {
            value: '2',
            label: 'input2'
        }
    ];
    $scope.selectedDevice = '';

    $scope.addType = function () {
        var newElem = {
            label: $scope.newInput,
            value: '3'
        };
        $scope.inputDevice.Push(newElem);
        $scope.selectedDevice = newElem.value;
    };


});

そして、ここにhtmlがあります:

<div ng-app="testApp">
    <div ng-controller="Ctrl">
        <p>
            <input type="text" ng-model="newInput" />
            <br />
            <button ng-click="addType()">Add Type</button>
        </p>
        <select ng-model="selectedDevice">
            <option></option>
            <option ng-repeat="i in inputDevice" value="{{ i.value }}">{{ i.label }} - {{ i.value }}</option>
        </select>
        {{ selectedDevice }}</div>
</div>
61
Jhorra

これが、選択オプションのレンダリングにngRepeatを使用すべきではない理由です。代わりにngOptionsを使用する必要があります。

<select ng-model="selectedDevice" 
        ng-options="i.value as (i.label + '-' + i.value) for i in inputDevice">
    <option></option>
</select>

一般に、選択オプションのレンダリングにngRepeatを使用しないでください。少なくとも2つの理由があります。 ngRepeatは、反復ごとに個別の子スコープを作成します。これは、オプションタグの場合には必要ありません。もう1つの重要な注意点は、ngRepeatを使用すると、selectを文字列などのプリミティブにのみバインドできますが、オブジェクトをngModelに書き込むことはできないということです。

以下にデモを示します。

angular.module('demo', []).controller('DemoController', function($scope) {

    $scope.newInput = '';
    $scope.inputDevice = [
        {value: '1', label: 'input1'}, 
        {value: '2', label: 'input2'}
    ];
    
    $scope.selectedDevice = '';
    $scope.addType = function() {
        var newElem = {
            label: $scope.newInput,
            value: Number($scope.inputDevice[$scope.inputDevice.length - 1].value) + 1
        };
        $scope.inputDevice.Push(newElem);
        $scope.selectedDevice = newElem.value;
        $scope.newInput = '';
    };

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js"></script>
<div ng-app="demo" ng-controller="DemoController">
    <form ng-submit="addType()">
        <input type="text" ng-model="newInput" />
        <button type="submit">Add Type</button>
    </form>
    <select ng-model="selectedDevice" ng-options="i.value as (i.label + ' - ' + i.value) for i in inputDevice">
        <option>Select</option>
    </select>
    {{ selectedDevice }}
</div>
92
dfsq

問題は、ng-optionsを使用していないため、新しいselectedDeviceを設定した時点でブラウザーがレンダリングを完了していないことです。 ng-optionsの使用をオンに設定している場合、この回避策を使用できます。 $timeoutを使用して$scope.selectedDevice = newElem.value;をラップし、ブラウザーがng-repeatで変更のレンダリングを完了した後に実行されるようにします。

また、連続した追加で次の値をインクリメントするコードを追加しました。「3」にハードコーディングすると、さらに追加しても3番目のオプションが継続的に選択されるためです。

var testApp = angular.module('testApp', ['ngRoute']);

testApp.controller('Ctrl', function($scope, $timeout) {

  $scope.newInput = '';
  $scope.inputDevice = [{
    value: '1',
    label: 'input1'
  }, {
    value: '2',
    label: 'input2'
  }];
  $scope.selectedDevice = '';

  $scope.addType = function() {
    var last = Number($scope.inputDevice[$scope.inputDevice.length - 1].value) + 1;
    var newElem = {
      label: $scope.newInput,
      value: last.toString()
    };
    $scope.inputDevice.Push(newElem);
    $timeout(function() {
      $scope.selectedDevice = newElem.value;
    }, 0);
  };

});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular-route.js"></script>

<div ng-app="testApp">
  <div ng-controller="Ctrl">
    <p>
      <input type="text" ng-model="newInput" />
      <br />
      <button ng-click="addType()">Add Type</button>
    </p>
    <select ng-model="selectedDevice">
      <option></option>
      <option ng-repeat="i in inputDevice" value="{{ i.value }}" ng-selelected="{{ selectedDevice == i.value }}">{{ i.label }} - {{ i.value }}</option>
    </select>
    {{ selectedDevice }}
  </div>
</div>
8
JME

私は同様の問題を抱えていて、その理由は私のキーが数字だったのですが、別の値を設定しようとしたときに文字列を送信していました。この場合の回避策は、モデル値をキーと同じタイプに強制的に設定することです。

例えば:

<select ng-model="model" ng-options="option.{{ key }} as option.{{ label }} for option in options">
    <option value="">{{ emptyLabel }}</option>
</select>
if (scope.options.length > 0) {
    scope.keyType = typeof(scope.options[0][scope.key]);
}

...

if (scope.keyType == 'number') {
    scope.model = parseInt(newVal, 10);
} else {
    scope.model = newVal;
} 
4
Romain

Ng-modelが更新されたときにselectが更新されないという同じ問題がありました。キーと値のペアに基づいて配列からオブジェクトを抽出した関数からng-modelの値を取得していました。

これを行う際に、返されたオブジェクトにはhashkeyプロパティ$$hashKey: "object:115"がありました

この問題は、angular.copyを使用してこの「ハッシュキー」プロパティを削除したオブジェクトのコピーを作成したときに発生し、選択されませんでした。

Angle.copy後にng-model値を取得するためにコードを再編成した後、問題は解決しました

ConstructorReviewers: function (oItem) {
      this.PERSON_ID = oItem.PERSON_ID;
      this.CHAIR_PERSON = oItem.CHAIR_PERSON;

      /* // Commented this part and added it to EditItem function      
      this.oDepartment = CommonFactory.FindItemInArray(vm.oCommittee.arrDepartments, 'NAME', this.DEPARTMENT, 'item');
      */    
      this.EditItem = function () {
           vm.EditItemOriginal = this;
           angular.copy(this, vm.EditItem); // After this update the ng-model into vm.EditItem.oTitle object
           vm.EditItem.oTitle = CommonFactory.FindItemInArray(vm.oCommittee.arrTitles, 'TITLE', vm.EditItem.TITLE, 'item');
           vm.Popup.ShowPopup(true, 'new_edit', Constants.Mentoring.Popup.Edit);
      }
}
1
Mahesh

同じ問題がありました。私にとってそれを解決したのは、数値を文字列に変換することです。例:

$scope.selectedDevice = "" + newElem.value; 
1
Malek Hijazi