Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ng-options as directive parameter

So, I have the same question asked on this question, sadly, no one has answered, so, here it goes again

I'm trying to create a select directive, where I can send the ng-options as a parameter.

This is my directive

app.directive('dropDown', function () {
    return {
        restrict: 'E',
        template: function (element, attrs) {
            return '<div class="col-sm-{{labelCol}} control-label">' +
                        '<label>{{label}}:</label>' +
                    '<div>' +
                    '<div clas="col-sm-{{controlCol}}">' +
                        '<label style="cursor:pointer" ng-show="!edit && forEdit" ng-disabled="disabled" ng-click="edit = true;">{{ngModel}}</label>' +
                        '<i ng-show="!edit && forEdit && !disabled" class="fa fa-pencil-square-o" style="cursor:pointer" aria-hidden="true" ng-click="edit = true;"></i>' +
                        '<select name="{{name}}" ng-change="ngChange" ng-blur="edit = false" ng-show="edit || !forEdit" class="form-control" ng-model="ngModel" ng-required="required" ng-options={{options}}/>' +
                    '</div>'
        },
        replace: true,
        scope: {
            ngModel: '=',
            ngChange: '&',
            label: '@',
            labelCol: '@',
            controlCol: '@',
            type: '@',
            name: '@',
            disabled: '=',
            required: '=',
            forEdit: "=",
            options: "@"
        },
        link: function (scope, element, attrs) { },
        compile: function (element, attrs) {
            if (!attrs.labelCol) attrs.labelCol = '4';
            if (!attrs.controlCol) attrs.controlCol = '8';
            if (!attrs.required) attrs.required = false;
            if (!attrs.disabled) attrs.disabled = false;
            if (!attrs.forEdit) attrs.forEdit = false;
            attrs.edit = !attrs.forEdit;
        }

    }
})

And this is a implementation of the directive

<div class="row">
    <drop-down ng-model="site" for-edit="true" label="Site Test" options="x.SITE_CODE as x.SITE_NAME for x in sites"></drop-down>
</div>
<div class="row">
    <drop-down ng-model="site1" for-edit="true" label="Site Test" options="x for x in sites1"></drop-down>
</div>

And I'm getting the same response

Error: [$parse:syntax] Syntax Error: Token 'in' is an unexpected token at column 3 of the expression [x in sites1] starting at [in sites1].

Error: [$parse:syntax] Syntax Error: Token 'as' is an unexpected token at column 13 of the expression [x.SITE_CODE as x.SITE_NAME for x in sites] starting at [as x.SITE_NAME for x in sites].

Any idea how to achieve my desired result?

Edit1:

If it help, here's the arrays that should be filling the selects

$scope.sites = JSON.parse("[{\"SITE_CODE\":\"1\",\"SITE_NAME\":\"SITE1\",},{\"SITE_CODE\":\"2\",\"SITE_NAME\":\"SITE2\"},{\"SITE_CODE\":\"3\",\"SITE_NAME\":\"SITE3\"},{\"SITE_CODE\":\"4\",\"SITE_NAME\":\"SITE4\"}]");
$scope.sites1 = ["SITE1", "SITE2", "SITE3", "SITE4"];

Edit 2:

Added the error for the more complex ng-options sentence

Edit 3:

So, I just realized that, I'm setting the ngOptions as a 2 way databinding field on the scope, as, it's not necesary, so I changed it from = to @ and now, I'm getting another error message

Error: [$compile:ctreq] Controller 'select', required by directive 'ngOptions', can't be found!

Which, it's unreasonable, as I'm indeed setting the ngOptions, and I can verify it on the compile

Edit 4:

So, after some testing, I'm finally getting my controls rendered, but sadly, withouth values

The selects are clearly on the controller div

<div class="content" ng-controller="testController">   
    <div class="row">
        <drop-down ng-model="site" for-edit="true" label="Site Test" options="x for x in sites"></drop-down>
    </div>
    <div class="row">
        <drop-down ng-model="site" label="Site Test" options="x for x in sites"></drop-down>
    </div>
    <div class="row">
        <drop-down ng-model="site1" for-edit="true" label="Site Test" options="x for x in sites1"></drop-down>
    </div>
</div>

The controller indeed has this collections

app.controller('testController', ['$scope', function ($scope) {
    $scope.sites = JSON.parse("[{\"SITE_CODE\":\"1\",\"SITE_NAME\":\"SITE1\",},{\"SITE_CODE\":\"2\",\"SITE_NAME\":\"SITE2\"},{\"SITE_CODE\":\"3\",\"SITE_NAME\":\"SITE3\"},{\"SITE_CODE\":\"4\",\"SITE_NAME\":\"SITE4\"}]");
    $scope.sites1 = ["SITE1", "SITE2", "SITE3", "SITE4"];
}]);

But my rendered controls comes without any values enter image description here

This is the rendered html for one of the controls

<div ng-model="site" label="Site Test" options="x for x in sites" class="ng-isolate-scope ng-valid">
    <div class="col-sm-4 control-label"><label class="ng-binding">Site Test:</label></div>
    <div class="col-sm-8">
        <label style="cursor:pointer" ng-show="!edit &amp;&amp; forEdit" ng-disabled="disabled" ng-click="edit = true;" class="ng-binding ng-hide"></label>
        <i ng-show="!edit &amp;&amp; forEdit &amp;&amp; !disabled" class="fa fa-pencil-square-o ng-hide" style="cursor:pointer" aria-hidden="true" ng-click="edit = true;"></i>
        <select name="" ng-change="ngChange" ng-blur="edit = false" ng-show="edit || !forEdit" class="form-control ng-pristine ng-valid ng-valid-required ng-touched" ng-model="ngModel" ng-required="required" ng-options="x for x in sites">
            <option value="?" selected="selected"></option>
        </select>
     </div>
</div>

At least now I'm getting my controls rendered, now, on to show some values on them

like image 686
CJLopez Avatar asked Sep 14 '25 23:09

CJLopez


2 Answers

The syntax ng-options="x in sites1" is incorrect.

In it's most simplest form it should be label for value in array:

ng-options="x for x in sites1"

Also check out the angular docs for ngOptions to see all of the permitted argument forms.

like image 185
Matthew Cawley Avatar answered Sep 17 '25 12:09

Matthew Cawley


Well, after much testing, I finally am able to achieve my desired result.

I'll leave the directive here to whoever might want to use it, as it allows to

  1. Set a desired options string

  2. Set a property to show in case we store the complete object in the model

  3. Disabled status, that will only show the model value
  4. Inline edit of the value

var app = angular.module("app", []);

app.controller('testController', ['$scope', function($scope) {
  $scope.sites = JSON.parse("[{\"SITE_CODE\":\"1\",\"SITE_NAME\":\"TEST 1\"},{\"SITE_CODE\":\"2\",\"SITE_NAME\":\"TEST 2\"},{\"SITE_CODE\":\"3\",\"SITE_NAME\":\"TEST 3\"},{\"SITE_CODE\":\"4\",\"SITE_NAME\":\"TEST 4\"}]");
  $scope.sites1 = ["TEST 1", "TEST 2", "TEST 3"];

}]);

app.directive('dropDown', function() {
  return {
    restrict: 'E',
    require: 'ngOptions',
    template: function(element, attrs) {
      return '<div>' +
        '<div class="col-sm-{{labelCol}} control-label">' +
        '<label>{{label}}:</label>' +
        '</div>' +
        '<div class="col-sm-{{controlCol}}">' +
        '<label ng-show="!edit && forEdit">{{ngModel[textValue] !== undefined ? ngModel[textValue] : ngModel}}</label> ' +
        '<span ng-show="!edit && forEdit && !disabled" class="fa fa-pencil-square-o" style="cursor:pointer" aria-hidden="true" ng-click="edit = true;">click here for edit</span>' +
        '<select name="{{name}}" ng-change="ngChange" ng-blur="edit = false" ng-show="edit || !forEdit" class="form-control" ng-model="ngModel" ng-required="required" ng-options="{{options}}"/>' +
        '</div>' +
        '</div>';
    },
    replace: true,
    scope: {
      ngModel: '=',
      ngChange: '&',
      label: '@',
      labelCol: '@',
      controlCol: '@',
      type: '@',
      name: '@',
      disabled: '=',
      required: '=',
      forEdit: "=",
      options: "@",
      items: "=",
      textValue: "@"
    },
    compile: function(element, attrs) {
      if (!attrs.labelCol) attrs.labelCol = '4';
      if (!attrs.controlCol) attrs.controlCol = '8';
      if (!attrs.required) attrs.required = false;
      if (!attrs.disabled) attrs.disabled = false;
      if (!attrs.forEdit) attrs.forEdit = false;
      if (attrs.disabled)
        attrs.forEdit = "true";
      attrs.edit = !attrs.forEdit;
    },
    link: function(scope, element, attrs) {

    },

  }
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
  <div class="" ng-controller="testController">
    <div class="row">
      <drop-down ng-model="site" for-edit="true" label="Site Test Inline" text-value="SITE_NAME" options="x.SITE_NAME for x in items" items="sites"></drop-down>
      <drop-down ng-model="site1" for-edit="false" label="Site Test Select" options="x for x in items" items="sites1"></drop-down>
      <drop-down ng-model="site1" disabled="true" label="Site Test Disabled" options="x for x in items" items="sites1"></drop-down>
    </div>
  </div>
</div>
like image 38
CJLopez Avatar answered Sep 17 '25 14:09

CJLopez