user4870812
user4870812

Reputation:

AngularJS - Directive for getting a value in Object

Currently I am using this for loop for getting parent

angular.forEach(queryTicketCategories, function(category) {
    if(category.id === $scope.ticketCategory.parentId) {
        $scope.parent = category;
    }
});

Please suggest common directive that will return category. Here queryTicketCategories is an object of arrays. And I wanna assign a array to $scope.parent that equals $scope.ticketCategory.parentId

Html code is

   <input type="text" ng-model="parent" 
   placeholder="{{'PARENT_CATEGORY' | translate}}" 
   typeahead="category as category.name for category in getTicketCategories($viewValue)" 
   typeahead-loading="loading" class="form-control"> 

Upvotes: 7

Views: 513

Answers (5)

Christos Baziotis
Christos Baziotis

Reputation: 6035

I am not sure what you want, you have to update your answer and provide an example with what you want: i have A, i pass B, i expect C.

In any case here is a simple directive that implements the logic in the code in your question. And here is the jsfiddle.

var app = angular.module('HelloApp', [])

app.controller('MyController',

  function MyController($scope) {

    $scope.myCategoryId = 11;

    $scope.myParentCategory;

    $scope.myCategories = [{
      "id": 1,
      "name": "Tara"
    }, {
      "id": 11,
      "name": "Opal"
    }, {
      "id": 21,
      "name": "Whitfield"
    }, {
      "id": 31,
      "name": "Alta"
    }, {
      "id": 41,
      "name": "Tucker"
    }, {
      "id": 51,
      "name": "Sims"
    }, {
      "id": 61,
      "name": "Bradshaw"
    }];

  });



app.directive('parentCategory', function() {
  return {
    restrict: "AE",
    scope: {
      categories: "=",
      categoryId: "=",
      parent: "="
    },
    link: function(scope, iElement, iAttrs, controller, transcludeFn) {

      scope.$watch('categoryId', findParent);

      function findParent() {
        var parent;
        angular.forEach(scope.categories, function(category) {
          if (category.id === scope.categoryId) parent = category;
        });
        scope.parent = parent;
      }

    }
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="HelloApp">
  <div ng-controller="MyController">
    <label for="">CategoryId:</label>
    <input type="number" ng-model="myCategoryId">

    <h3>Parent</h3>
    <pre>{{myParentCategory|json}}</pre>


    <parent-category categories="myCategories" category-id="myCategoryId" parent="myParentCategory"></parent-category>
  </div>
</div>


<!--     or you can use it like this, as an attribute

<input type="number" ng-model="myCategoryId" parent-category categories="myCategories" category-id="myCategoryId" parent="myParentCategory">
-->

Upvotes: 3

whoknows
whoknows

Reputation: 306

angular.forEach(queryTicketCategories, function(category) {
    if(category.id === $scope.ticketCategory.parentId) {
        $scope.parent = category;
    }
});

From your code, queryTicketCategories must be an array of objects. Since you can not loop an object. So try using,

angular.forEach(queryTicketCategories, function(category) {
    if(angular.equals(parseInt(category.id), parseInt($scope.ticketCategory.parentId)) {
        $scope.parent = category;
        return;
    }
});

Here make sure that queryTicketCategories is in the format,

[  { ... }
   , { ... }
   , { ... }
]

in order to category.id to work, and we are using parseInt since there might be a chance that category.id or $scope.ticketCategory.parentId might be in String.

Note that, '===' and angular.equals() has the same implementation.

Upvotes: 5

allenhwkim
allenhwkim

Reputation: 27738

For your case, it's better to look into typeahead directive and make max use of it.

http://angular-ui.github.io/bootstrap/#/typeahead

Instead of creating your own directive or service, you can use the existing directive with callback, typeahead-on-select

typeahead-on-select($item, $model, $label) (Defaults: null) : 
A callback executed when a match is selected

This is the example that I created without using callback. It enables you to select a google address from what you type.

Without typeahead-on-select :
http://plnkr.co/edit/GMnzod9MQZWxsKSuJUJu?p=preview

The following is going step further by changing the selected address to uppercase. You can do whatever you want in this callback.

http://plnkr.co/edit/jaeSZdSKucMQgIF05KwD?p=preview

I used this function to change the selected address to uppercase.

$scope.myFunc = function($item, $model, $label) {
    $scope.asyncSelected = $item.toUpperCase();
}

For your case you can make like the following

$scope.myFunc = function(category) {
    if(category.id === $scope.ticketCategory.parentId) {
        $scope.parent = category;
    }
}

HTML

typeahead-on-select="myFunc($item)"

In summary, your use case and data might be different from the example that I used above, but the main approach is the same. There is a callback after you select an item, and you can manipulate your data control more with the callback typeahead-on-select.

Upvotes: 7

gafi
gafi

Reputation: 12739

If I understand correctly, you want to set the $scope.parent object that appears in the text box based on $scope.ticketCategory.parentId

If so, then a directive is not the best way to do this. Directive are meant for DOM manipulation or logic that affects your view. But this functionality has nothing to do with updating view. It just happens that the view binds to $scope.parent, but if you just set this object in code the view will update automatically (or maybe with an $apply() call)

In that case, you should create a service or filter to make this operation reusable (also make sure to return once a match is found as there is no need to continue the loop after that, right?)

However, if you insist on using a directive. You can make a directive that depends on ng-model, and set the value of the model based on other attributes (the category list, the selected id). So the usage will be like this maybe

<input type="text" ng-model="parent" set-model="ticketCategory.parentId" set-model-list="queryTicketCategories" >

and the directive code will basically find the object from queryTicketCategories that has the same id as ticketCategory.parentId and set the model with this object.

You should probably set a flag or so in the directive to run this code only once and not every $apply() loop. But with the service/filter approach you get to set the parent value whenever you want (maybe after a server request or in a callback) so I recommend you use that instead of a directive.

Upvotes: 6

Vaibhav Shah
Vaibhav Shah

Reputation: 528

You can have watch expression on $scope.ticketCategory.parentId. Once the value for $scope.ticketCategory.parentId is changed then update $scope.parent to the category having the same id.for searching you can create filter.

Example -

app.filter('getById', function() {
  return function(queryTicketCategories, id) {
    var i=0, len=queryTicketCategories.length;
    for (; i<len; i++) {
      if (queryTicketCategories[i].id == +id) {
        return queryTicketCategories[i];
      }
    }
    return null;
  }
});

 $scope.$watch('ticketCategory.parentId', function() {
        // do something here
       var found = $filter('getById')(queryTicketCategories, ticketCategory.parentId);
         console.log(found);
         $scope.parent = found;
    }, true);

Upvotes: 4

Related Questions