basith
basith

Reputation: 830

Custom directive calling issue

I have written a custom directive to format a value, which is given below

var directiveapps = angular.module('myApp.currencyValues', []);
directiveapps.directive('currencyValue', function () {
return{
    scope: {
        data: '=items'
    },
    template: '<div>$ {{value|number}}</div>',
    link: function(scope){
      scope.value = Math.round(scope.data* 100) / 100;
    }
};
}); 

This directive will format a value to a currency and also it will round off the decimal points.This directive works fine, but my issue starts when calling the directives. i calls the directive from the view like this

<div class="overallsummary_meter_txt left">
  Total Price<br>
  <span currency-value items="totalPrice" class="orange_txt"></span>
</div>

the price amount coming from the db is assigned to 'items' and it will be passed in to the directive,this works in some case and getting formatted price value. now my issues are

  1. In some cases i am getting empty value (only $ sign without formatted value) while calling the directive.But in this same case if i hard code some values to items(items=8888), then it works. what is wrong with this directive?

  2. I think this directive is not two way binded, if not how can i make that?

  3. A label added after calling a directive is not displaying. I will give an example

<div currency-value items="downPayment">/Month</div> here the "/Month" is not displaying,but the formatted value is showing. How to add something in the same div after calling a directive?

  1. I want call this directive in a span where it shows a price range, for example,

view:- Price Range : $ 1000 - $ 500

<span class="price_range">{{maxMarcketPrcie}} - {{minMarcketPrice}}</span>

in this case how can i pass two values in to 'items' at a time? is there any alternate way to achieve this?

Upvotes: 2

Views: 78

Answers (2)

gyc
gyc

Reputation: 4360

1- I see nothing wrong with your directive. In the snippet below I haven't changed much from your example. (only replaced scope variable by controllerAs syntax) The only thing is, if you just want to round a number you can use a filter instead of a directive.

2- items uses two way binding. Nothing strange there. Maybe there's something in your controller that causes bugs?

function currencyValue() {
  return{
      scope: {
          data: '=items'
      },
      template: '<div>$ {{value|number}}</div>',
      link: function(scope){
        scope.value = Math.round(scope.data* 100) / 100;
      }
  };
};
function MyController() {
  this.items = 123.666;
}

angular.module('myApp', []);
angular
    .module('myApp')
    .controller('MyController', MyController)
    .directive('currencyValue', currencyValue);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<div ng-app="myApp">
    <div ng-controller="MyController as ctrl" class="overallsummary_meter_txt left">
      Total Price<br>
      <span currency-value items="ctrl.items" class="orange_txt"></span>
    </div>
</div>

3- The "label" you want to add is made by transclusion. You need to add transclude: true and ng-transclude in your directive. It will copy all the elements from your directive to your template:

function currencyValue() {
  return{
      transclude: true,
      scope: {
          data: '=items'
      },
      template: '<div>$ {{value|number}}<span ng-transclude></span></div>',
      link: function(scope){
        scope.value = Math.round(scope.data* 100) / 100;
      }
  };
};
function MyController() {
  this.items = 123.666;
}

angular.module('myApp', []);
angular
    .module('myApp')
    .controller('MyController', MyController)
    .directive('currencyValue', currencyValue);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<div ng-app="myApp">
    <div ng-controller="MyController as ctrl" class="overallsummary_meter_txt left">
      Total Price<br>
      <span currency-value items="ctrl.items" class="orange_txt">/Month</span>
    </div>
</div>

4- To pass a range to your directive you have 2 possibilities:

  • Just like you passed items, you can pass itemsMin="itemsMin" and itemsMax="itemsMax"
  • Or better you change your items variable to an object:

    this.items = {rangeFrom:1000, rangeTo:5000};

Your directive then becomes something like:

  return{
      transclude: true,
      scope: {
          data: '=items'
      },
      template: '<div>$ {{value.rangeFrom|number}} - $ {{value.rangeTo|number}}<span ng-transclude></span></div>',
      link: function(scope){
        scope.value = {};
        scope.value.RangeFrom = Math.round(scope.data.rangeFrom* 100) / 100;
        scope.value.RangeTom = Math.round(scope.data.rangeTo* 100) / 100;
      }
  };

Upvotes: 2

Amir Suhail
Amir Suhail

Reputation: 1304

1) Since you are telling the price is empty in some cases and works fine when you hardcode, then the problem is with db response. Check the response is giving the totalPrice.

Still its better to write your directive below format:

directiveapps.directive('currencyValue', function () {
return{
    scope: {
        items: '='
    },
    template: '<div>$ {{value|number}}</div>',
    link: function(scope){
      scope.value = Math.round(scope.items* 100) / 100;
    }
};
});

and call it as

<div class="overallsummary_meter_txt left">
  Total Price<br>
  <span currency-value items="totalPrice" class="orange_txt"></span>
</div>

Same way what you did.

Note: In directive

scope: {
   items: '='
}

items: '=' means its two way binding from a scope, you can also use '<' for one way binding from a scope, or '@' for one way binding from a string.

2) /Month this won't work because the directive will replace the content inside the div with its template. The quickest way for solving your issue is to move the content into directive's template. Like:

change

template: '<div>$ {{value|number}}</div>',

to

 template: '<div>$ {{value|number}} /month</div>',

JFYI: We can also use ngTransclude for adding dynamic content.

Upvotes: 0

Related Questions