javascriptangularjsangularjs-ng-repeatangularjs-ng-modelangularjs-ng-init

AngularJS revert selected value of control nested in ng-repeat on dialog cancel


I want to revert a select tag value that is inside a ng-repeat after cancelling a confirm dialog.

Here is what I have so far:

Relevant HTML:

<table>
  <tbody>
    <tr ng-repeat="application in rows">
      <td>
        <select
                ng-model="application.selectedVersion"
                ng-options="apk.versionName for apk in application.versions | orderBy : 'id' : true"
                ng-init="application.selectedVersion=application.versions.filter(currentVersion, application.apkUpdates)[0]"
                ng-change="selectionChanged(application, '{{application.selectedVersion}}')"
                style="padding:0 1em;" />
      </td>
    </tr>
  </tbody>
</table>

Javascript logic:

$scope.selectionChanged = function(application, previousVersion) {
  var dialog = confirm('Change version?');

  if (dialog) {
    console.log('change version confirmed');
  } else {
    application.selectedVersion = previousVersion;
  }
};

Passing '{{application.selectedVersion}}' to the function instead of application.selectedVersion passes the previously selected value instead of the current (explained here: https://stackoverflow.com/a/45051464/2596580).

When I change the select value, perform the dialog interaction and cancel it I try to revert the value by setting application.selectedVersion = angular.copy(previousVersion);. I can see the value is correct by debugging the javascript but the select input is set to blank instead of the actual value.

What am I doing wrong?

JSFiddle demo: https://jsfiddle.net/yt4ufsnh/


Solution

  • You have to correct couple of things in your implementation

    1. When you pass '{{application.selectedVersion}}' to selectionChanged method, it becomes raw string. When you re assigns back to the application.selectedVersion you have to first parse that previousVersion to JSON using JSON.parse method
    2. Use track by apk.id on ng-options collection. This is needed because the JSON parsed object is not recognized as the same instance of the object used to build the select, so this works as if overriding an intrinsic equals function to use only its id property

    Final Version

    ng-options="apk.versionName for apk in (application.versions | 
                                               orderBy : 'id' : true) track by apk.id" 
    

    Code

    $scope.selectionChanged = function(application, previousVersion) {
        var dialog = confirm('Change version?');
        if (dialog) {
          console.log('change version confirmed');
        } else {
          application.selectedVersion = previousVersion ? JSON.parse(previousVersion) : null;
        }
    };
    

    Updated Fiddle