Search code examples
javascriptangularjsangular-ngmodel

Angular JS form model value changed to an array


I have a fairly normal form in angular with a title, body field and also has a dropdown select with a list of options. The options are hard coded, but the backend only accepts an array of objects while the body accepts on key with object.

My input currently looks as so:

<label for="platform">Platform</label>
<select id="platform" name="platform" class="form-control" ng-model="lfg.field_platform">
    <option value="1183">Option 1</option>
    <option value="1184">Option 2</option>
    <option value="1182">Option 3</option>
    <option value="1188">Option 4</option>
    <option value="1186">Option 5</option>
    <option value="1185">Option 6</option>
</select>

As expected this returns:

{
  "title": "test",
  "body": "here is the body",
  "field_platform": "1184"
}

However I need field_platform to return:

{
  "type": "dataset",
  "title": "Just a title",
  "body": {
    "value": "Detailed text goes here"
  },
  "field_platform": [
    {
      "id": 1184
    }
  ]
}

Can I properly format this using just the ng-model directive or will I have to do some more work in the controller to format body and field_platform?


Solution

  • See plunker for both solutions

    Solution 1:

    If you are using angular v1.3 you can use ngModelOptions with gettersetter option set to true. Then restructure your model to have getters and setters:

      $scope.lfg = {
        field_platform1: null,
        fieldPlatformFn: function(value) {
          return arguments.length ? this.setFieldPlatForm(value): this.getFieldPlatForm();
        },
        getFieldPlatForm: function() {
          return this.field_platform1 && this.field_platform1.length > 0 && this.field_platform1[0].id;
        },
        setFieldPlatForm: function(value) {
          return this.field_platform1 = [{"id": parseInt(value)}];
        }
      };
    

    and your select will have to reference the gettersetter function in ng-model

    <select
        id="platform"
        name="platform"
        class="form-control"
        ng-model="lfg.fieldPlatformFn"
        ng-model-options="{getterSetter: true}">
    

    Solution 2:

    Create your own directive to formatter and make use of the ngModelController parsers and formatters

    app.directive('toArray', [function() {
      return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, elem, attr, ngModelCtrl) {
          ngModelCtrl.$formatters.push(function(value) {
            return value && value.length > 0 && value[0].id;
          });
    
          ngModelCtrl.$parsers.push(function(value) {
            return [{id: parseInt(value)}];
          });
        }
      }
    }]);
    

    With markup:

      <select
        id="platform2"
        name="platform"
        class="form-control"
        ng-model="lfg.field_platform2"
        to-array="">