0

This is a reduction of my directive:

app.directive('myDirective', function() {
  return {
    restrict: 'E',
    replace: true,
    template:
      '<form name="form" action="{{action}}" method="post" target="_blank">' +
        '<input type="hidden" name="item_name" value="{{itemname}}">' +
      '</form>',
    scope: {
      action: '@action',
      itemname: '@itemname',
    },
    link: function(scope, element, attrs) {
      scope.action = attrs.action || 'http://www.example.com';
      scope.itemname = attrs.itemname();
    }
  };
});

and I use it this way:

<div ng-if="itemWasSelected">
  <my-directive
     action="{{ 'http://www.example.com' }}"
     itemname="itemNameBuildFunction"
  />
</div>

In my controller, I have:

$scope.itemNameBuildFunction = function() {
  return $scope.value1 + $scope.value2;
};

I would expect my directive, when it is linked (it is inside an ng-if clause, so, I mean, when the ng-if condition evaluates to true), to call attrs.itemname() $scope function, to assign scope.itemname variable in the controller's link function.

Instead, what I get is the error:

TypeError: attrs.itemname is not a function

Can you please give me some directions? As you can see, I'm quite confused, with angular directives... :-(

MarcoS
  • 17,323
  • 24
  • 96
  • 174
  • Have you closed the directive and also try scope.itemname = attrs.itemname; – Mandeep Singh Jul 18 '16 at 14:16
  • what is this function `attrs.itemname()`? never saw it defined... also if it was defined as a function attrs convert into JSON objects. so you would have to use angular.fromJson(attrs.itemname) – Zargold Jul 18 '16 at 14:17
  • @MandeepSingh: first advise: thanks, just corrected my answer; second advise: that way, in the produced form I get the string: `itemname`, which is not what I expect... :-( – MarcoS Jul 18 '16 at 14:24
  • @Zargold: `attrs.itemname` contains a string (`itemNameBuildFunction`) which is a $scope function name... – MarcoS Jul 18 '16 at 14:26
  • @MandeepSingh: no, it is not: I get the **function name**, and not the evaluated function result... :-( – MarcoS Jul 18 '16 at 14:36

2 Answers2

2

You don't need this statement attrs.itemname().

Your function reference passed in directive is bind to to the variable itemname on scope that is passed as first parameter in link function which isolated scope

Just change the statement from

scope.itemname = attrs.itemname();

To :

scope.itemname();  // this will call the function `itemNameBuildFunction`

EDIT :

You have used @ operator ofr binding function which is used in case passing primitive or object.You are passing function, so , you should use & operator,will evaluate as function.

scope: {
      action: '@action',
      itemname: '&itemname',
    }

EDIT 2: Yous should passed function itemNameBuildFunction() and not itemNameBuildFunction

<my-directive action="{{ 'http://www.example.com' }}" 
    itemname="itemNameBuildFunction()" />

Working Plunker

RIYAJ KHAN
  • 15,032
  • 5
  • 31
  • 53
  • @Zargold What is wrong?Can u elaborate or fixed it and what is duplicate – RIYAJ KHAN Jul 18 '16 at 14:22
  • Duplicate means: Someone else answered the exact same thing 2 minutes before you did. Wrong means: It seems like the person asking the question does have a function for itemname but he didn't define it in the right place or something though can't be sure. – Zargold Jul 18 '16 at 14:26
  • `scope.itemname()` produces: `TypeError: scope.itemname is not a function` – MarcoS Jul 18 '16 at 14:28
  • man first thing please check the right answer and mine one.Please check what duplicate you find there.Second one `attrs.itemname` will not evalute to expression that is why there is isolated scope is used.That is why is stating such error – RIYAJ KHAN Jul 18 '16 at 14:32
  • I **need** an isolated scope. – MarcoS Jul 18 '16 at 14:33
  • @MarcoS you already defined isolated scope.Just need to call it on `scope` like `scope.itemname()` and it will call `itemNameBuildFunction ` function – RIYAJ KHAN Jul 18 '16 at 14:38
  • As I already told, `scope.itemname()` produces: `TypeError: scope.itemname is not a function` – MarcoS Jul 18 '16 at 14:40
  • Thanks for your effort. I did change `itemname: '@itemname'` to `itemname: '&itemname`, but `scope.itemname` is always a string, in my directive link function, so I can't *call* it... :-( – MarcoS Jul 18 '16 at 14:53
  • It is unrecommended to use `` use – Zargold Jul 18 '16 at 15:19
  • Thanks for your plunker, RIYAJ... It seems to reproduce my use case... I even added an `ng-if` clause around directive (here: https://plnkr.co/edit/oyn3UWjbBw6BI63i7Qqk?p=preview), and it keeps working. Unfortunately, I can't apply your solution to my use case... :-( As soon as I can I'll accept your answer! – MarcoS Jul 18 '16 at 15:20
  • OK looks a lot better and not a duplicate anymore great work. – Zargold Jul 18 '16 at 15:22
  • I +1'd you just it looks like he may have really needed to call the function in the controller. – Zargold Jul 18 '16 at 15:40
  • Thanks... The problem was I were using `action`, which seems to clash with form's `action`... :-). Changed `action` to `actionValue`, everything works for me, too, THANKS! – MarcoS Jul 18 '16 at 16:02
0

Seems to me that you actually want '=' type which will take in javascript objects and (without requiring JSON.parse) allow you to use them in your scope. A function is javascript object which can be run using the ();

So the best solution is: scope: { action: '@', itemname: '=', }, This will allow you to take a callback for the item name and then run it in the scope as you see fit.

https://plnkr.co/edit/cKzLhP4SwHey266Flr5w?p=preview.

Also, how would someone submit the form you offer? It doesn't seem to make sense you should have a <input type='submit'/> if you want to submit a hidden input name. Also, you probably want to use templateURL and include an HTML template instead of having a big dynamic form in you js.

Zargold
  • 1,892
  • 18
  • 24