3

I have a problem using angular 1.6.5 and tried everything but without any noticeable progress...

I made a directive that implement the HTML SELECT tag, the component seems to work until I try to get the entire object in option value attribute instead of a single value or ID. I can output the text of the option tag both as a property of the object or trough a function the return some string.

Here is a complete fiddle with the component and the problem. There are 3 examples:

  1. The 1st one seems to work correctly, it print the correct text and return the correct value

  2. The 2nd: do not work, I'd like to set to the model the entire OBJECT selected and not a property

  3. The 3rd: do not work, I'd like to set to the model the entire OBJECT selected and not a property but it print correctly the text from a function in parent controller.

How can I change my component that it can return both a property (like ID) both the entire object (JSON format is good)?

angular.module("myApp", ['customDrop']).controller("TestController", ['$scope', function($scope) {
  var ITEM_SELECTED = {
    ID: 3,
    VALUE: "VALUE3"
  };
  $scope.LIST = [{
      ID: 1,
      VALUE: "VALUE1"
    },
    {
      ID: 2,
      VALUE: "VALUE2"
    },
    ITEM_SELECTED,
  ];

  $scope.OBJ = {
    LOTTO1: ITEM_SELECTED,
    LOTTO2: ITEM_SELECTED,
    LOTTO3: ITEM_SELECTED

  };

  $scope.getCompleteValue = function(obj) {
    return obj.ID + " - " + obj.VALUE;
  }
}]);

angular.module('customDrop', []).directive('customDrop', function() {
  return {
    restrict: 'E',
    scope: {
      dropid: '@',
      dropvalue: '&',
      list: '=',
      ngModel: '='
    },
    require: 'ngModel',
    template: '<select class="drop" ng-model="ngModel">' +
      '<option ng-repeat="val in list" value="{{getId(val)}}">{{getValue(val)}}</option>' +
      '</select>',
    controller: ['$scope', '$parse', '$timeout',
      function($scope, $parse, $timeout) {
        $scope.getId = function(obj) {
          return obj[$scope.dropid];
        }

        // Can print text option as proerty of through function in parent scope.
        $scope.getValue = function(obj) {
          return !angular.isFunction($scope.dropvalue(obj)) ?
            $scope.dropvalue(obj) :
            $parse($scope.dropvalue(obj))(obj);
        }
      }
    ]
  }
});
.drop {
  width: 400px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>


<div ng-app="myApp" ng-controller="TestController">
  <strong>Simple Text Property (drop id intended to return the ID): (working)</strong><br>
  <custom-drop dropvalue="VALUE" dropid="ID" list="LIST" ng-model="OBJ.LOTTO1"></custom-drop><br> Selected Value: {{OBJ.LOTTO1}}
  <br><br><br>
  <!-- using property as dropValue -->
  <strong>Simple Text Property (drop id intended to return an object): (not working)</strong><br>
  <custom-drop dropvalue="VALUE" dropid="" list="LIST" ng-model="OBJ.LOTTO2"></custom-drop><br> Selected Value: {{OBJ.LOTTO2}}
  <br><br><br>
  <!-- using function as dropValue -->
  <strong>Function Text Property: (not working)</strong><br>
  <custom-drop dropvalue="getCompleteValue" dropid="" list="LIST" ng-model="OBJ.LOTTO3"></custom-drop><br> Selected Value: {{OBJ.LOTTO3}}
</div>

1
  • becide your question, so many issues here - do not even include jquery, prefer component, do not use additional ngModel, do not use method in templates, prefer ng-options... Finally - do not write such component at all - it will take you age to make it viable. (I.e. in this implementation you can not add validator to field) Commented Sep 5, 2017 at 12:04

1 Answer 1

1

To set to the model the entire OBJECT selected you have to modify your getId() method to return the object in case $scope.dropid was not passed through the bindings (since this method is used to generate the value of the option). Also I recommend using ngOptions to generate the list of option elements. See the snippet below:

angular.module("myApp", ['customDrop']).controller("TestController", ['$scope', function ($scope) {
    var ITEM_SELECTED = {
        ID: 3,
        VALUE: "VALUE3"
    };
    $scope.LIST = [{
        ID: 1,
        VALUE: "VALUE1"
    },
        {
            ID: 2,
            VALUE: "VALUE2"
        },
        ITEM_SELECTED,
    ];

    $scope.OBJ = {
        LOTTO1: ITEM_SELECTED.ID,
        LOTTO2: ITEM_SELECTED,
        LOTTO3: ITEM_SELECTED

    };

    $scope.getCompleteValue = function (obj) {
        return obj.ID + " - " + obj.VALUE;
    }
}]);

angular.module('customDrop', []).directive('customDrop', function () {
    return {
        restrict: 'E',
        scope: {
            dropid: '@',
            dropvalue: '&',
            list: '<',
            ngModel: '='
        },
        require: 'ngModel',
        template: '<select class="drop" ng-model="ngModel" ng-options="getModelValue(val) as getOptionText(val) for val in list"></select>',
        controller: ['$scope', '$parse',
            function ($scope, $parse) {
                $scope.getModelValue = function (obj) {
                    return !!$scope.dropid ? obj[$scope.dropid] : obj;
                };

                $scope.getOptionText = function (obj) {
                    return !angular.isFunction($scope.dropvalue(obj)) ?
                        $scope.dropvalue(obj) :
                        $parse($scope.dropvalue(obj))(obj);
                }
            }
        ]
    }
});
.drop {
  width: 400px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>

<div ng-app="myApp" ng-controller="TestController">
  <strong>Simple Text Property (drop id intended to return the ID): </strong><br>
  <custom-drop dropvalue="VALUE" dropid="ID" list="LIST" ng-model="OBJ.LOTTO1"></custom-drop><br> Selected Value: {{OBJ.LOTTO1}}
  <br><br><br>
  <!-- using property as dropValue -->
  <strong>Simple Text Property (drop id intended to return an object): </strong><br>
  <custom-drop dropvalue="VALUE" dropid="" list="LIST" ng-model="OBJ.LOTTO2"></custom-drop><br> Selected Value: {{OBJ.LOTTO2}}
  <br><br><br>
  <!-- using function as dropValue -->
  <strong>Function Text Property: </strong><br>
  <custom-drop dropvalue="getCompleteValue" dropid="" list="LIST" ng-model="OBJ.LOTTO3"></custom-drop><br> Selected Value: {{OBJ.LOTTO3}}
</div>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.