Radu Andrei
Radu Andrei

Reputation: 1073

angularjs directive on bind output

I have something like this:

.controller('contr',['$scope', '$http',function($scope, $http){
    $http.post(...).success(function(){
       $scope.myTextVar = "some text here";
       $scope.completed == true;
    });
}]);

an HTML snippet like so:

<div class="myClass" ng-if="completed == true" manipulate-header>
  <p>{{myTextVar}}</p>
</div>

and the directive, for simplicity sake let's say it looks like this:

.directive('manipulateHeader',function(){
    return{
        restrict: 'A',
        link: function(scope, elem){
                console.log(angular.element(elem).find('p'));
              }
    }
});

The manipulate-header directive is supposed to do some manipulation of the text inside the <p></p> tag, however, it runs before {{myTextVar}} gets replaced and hence it outputs {{myTextVar}} instead of some text here.

How may i get around this problem? (i can pass the variable inside the directive scope, but i'm thinking there must be another way).

EDIT: the controller is there and working as intended. Issue is not related to it. I didn't include it to shorten the post.

Upvotes: 0

Views: 3520

Answers (4)

RIYAJ KHAN
RIYAJ KHAN

Reputation: 15292

I am not sure whether you defined $scope.myTextVar in correct scope. Like, if you defined it in any controller, then directive should be under the controller scope.

Here is the updated HTML

<div ng-controller ="MainController">
     <div class="myClass" manipulate-header>
        <p>{{myTextVar}}</p>
    </div>
    </div> 

JS :

app.controller('MainController', ['$scope', function($scope) {

$scope.myTextVar = "some text here"; }]);

app.directive('manipulateHerader',function(){
    return{
        restrict: 'A',
        link: function(scope, elem){
                console.log(angular.element(elem).find('p'));
              }
    }
});

Here is the plunker

Upvotes: 1

Shushanth Pallegar
Shushanth Pallegar

Reputation: 2862

If you need to change the $scope variable from your controller you need to isolate scope ,

 scope:{

        myattr='@', // this will provide one way communication , you can define in your template as <p myattr="hello"><p> 
        message:'&',  //This allows you to invoke or evaluate an expression on the parent scope of whatever the directive is inside 
        message:'=' // sets up a two-way binding expression between the directive's isolate scope and the parent scope. 
    }     

refer https://docs.angularjs.org/guide/directive

Upvotes: 3

Dan
Dan

Reputation: 10538

If it MUST be a directive

If you're trying to do string manipulation in your link function, you're going to have a bad time. The link function is executed before the directive is compiled (that's the idea of the link function), so any bindings (ng-bind or otherwise) will not have been compiled inside of link functions.

To execute code after the compilation stage, you should use a controller. However, you cannot access the DOM in controllers (or rather, you shouldn't). So the logical solution is to instead modify the scope argument instead. I propose something like this:

angular.directive('manipulateHeader', function() {
  return {
    scope: {
      myTextVar: '='
    },
    controller: function($scope, myFilter) {
      // you can't use bindToController here because bindToController executes *after*
      // this function
      this.modifiedText = myFilter($scope.myTextVar);
    },
    controllerAs: 'ctrl',
    // display the modified text in a template
    template: '<span ng-bind="ctrl.modifiedText"></span>'
  };
 })
 .filter('myFilter', function() {
   return function(inputText) {
     // do some text manipulation here
   };
 });

Usage:

<manipulate-header myTextVar='myTextVar'></manipulate-header>

Or:

<p>{{ myTextVar | myFilter }}</p>

You could, of course, make this an attribute instead, but best practice indicates that directives that have a template should be an element instead.

The above is only if you need this to be a directive. Otherwise, it should almost definitely be a filter.

Upvotes: 3

David Votrubec
David Votrubec

Reputation: 4156

As suggested by @DanPantry - you most likely want a filter not a directive

Read this guide about using filters https://docs.angularjs.org/guide/filter

Here is an example of such a filter (from documentation)

    angular.module('myStatefulFilterApp', [])
    .filter('decorate', ['decoration', function(decoration) {

      function decorateFilter(input) {
        //This is the actual modification of text
        //That's what you are looking for
        return decoration.symbol + input + decoration.symbol;
      }
      decorateFilter.$stateful = true;

      return decorateFilter;
    }])
    .controller('MyController', ['$scope', 'decoration', function($scope, decoration) {
      $scope.greeting = 'hello';
      $scope.decoration = decoration;
    }])
    .value('decoration', {symbol: '*'});

Upvotes: 1

Related Questions