0

I am new to AngularJS. I want to return template to directive with addition and subtraction of two numbers. I am passing $scope in function but it is not working.

I'm learning from Angular Modules with Directive

here is the code :

<html>

<head>
    <title>Angular JS </title>
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
</head>

<body>
    <div ng-app="Compl">
        <input type=number ng-model="no1" placeholder="Enter the First Number" />
        <input type=number ng-model="no2" placeholder="Enter the First Number" />
        <NoSum></NoSum>
        <NoSub></NoSub>
    </div>
    <script>
        var app = angular.module("Compl", []);
        app.directive("NoSum", function($scope) {
            return {
                template: "Sum of Two Number" + ($scope.no1 + $scope.no2)
            };
        });
        app.directive("NoSub", function($scope) {
            return {
                template: "Sub of Two Number" + ($scope.no1 - $scope.no2)
            };
        });
    </script>
</body>

</html>
Wasif Ali
  • 886
  • 1
  • 13
  • 29
Chirag Suthar
  • 178
  • 1
  • 13
  • 2
    You can't pass $scope directly in your directive. Instead create a link function and use scope. For more details https://docs.angularjs.org/guide/directive – Vivz Jul 27 '17 at 07:03

3 Answers3

0

What you can do is

a) use the 'parent scope' .. so te scope of the controller of the view which contains your directive and so like this:

     app.directive("NoSum",function($scope){
                return {
                template: "Sum of Two Number" + (scope.no1 + scope.no2) //<-- don't use scope with $ ... but only scope
              link: function(scope, element, attrs) {
                element.bind('error', function() {
                    if (attrs.src !== attrs.errSrc) {
                        attrs.$set('src', attrs.errSrc);
                    }
                });
            }
        };
   });

2 - use 'isolated scope' .. so you force to pass the scope trought your item like so:

     app.directive("noSum",function($scope){
                    return {
restrict:'EAC'
                    template: "Sum of Two Number" + (item.no1 + item.no2) //<-- here you use item and in html you use like: <no-sum item="myvarscoped"></no-sum>
scope:{ item : "="}
                  link: function(scope, element, attrs) {
                    element.bind('error', function() {
                        if (attrs.src !== attrs.errSrc) {
                            attrs.$set('src', attrs.errSrc);
                        }
                    });
                }
            };
       });
federico scamuzzi
  • 3,708
  • 1
  • 17
  • 24
0

As Vivz has already mentioned, you can't pass scopes. Best practice is to share data between controllers/directives is to use factories. See this link for particular example.

Andrew
  • 449
  • 3
  • 7
  • 1
    Passing properties from a parent component to a child component is perfectly fine. Using factories/services for inter-component communication is only best practice if you want to share data between components that isn't already in a parent/child relationship. The use of a factory in this case would be overkill. – Nikolaj Dam Larsen Jul 27 '17 at 07:27
  • I can see just two same-level directives in this case. And as far as I'm concerned using `$rootScope` is not the best practice either. But I agree using factories is overkill in this particular case. But if you'd like to extend app functional in the future factories and services would be the best option in my opinion. – Andrew Jul 27 '17 at 07:31
  • The two directives doesn't communicate with each other, they communicate with the parent scope. That the parent scope in this case happens to be the $rootScope is irrelevant. If a component (or directive in this case) is a child, then it is best practice for the parent to communicate directly with the child, through attributes. That's the best separation of concern, since the child component wont have any kind of coupling. We could argue, that he should be using isolated scope, but I didn't want to complicate things since the question author is still just learning. – Nikolaj Dam Larsen Jul 27 '17 at 07:38
  • I could be wrong but directives are designed to be on their own and work as standalone components. Sharing parent scope is fine. But in this case parent scope is `$rootScope` that is global scope of all application. I agree that in this particular case it's better to avoid making things complicated because author is still learning. But I believe it is still reasonable to let him know that in general (and not his particular case) using `$rootScope` is considered bad practice. – Andrew Jul 27 '17 at 07:47
  • Sure, but the author could have wrapped it all in a controller and it wouldn't make a difference to the directives. Then it would be using the controller scope as parent, instead of rootScope. So whether it was the rootScope or not in this case, is completely irrelevant. I'm not even sure the author knew the `no1` and `no2` variables would be declared in the rootScope. So whether it is rootScope or parent scope doesn't have anything to do with the coupling of the directive, but everything to do with the directives having a non-isolated scope. – Nikolaj Dam Larsen Jul 27 '17 at 07:57
  • Agree. Wrapping in a controller would be the best solution for this case. – Andrew Jul 27 '17 at 08:06
  • My point is the opposite really. Wrapping it in a controller wouldn't make a difference at all regarding the coupling of the directives. They would just be tightly coupled to the controller's scope instead. Making the directives use an isolated scope though, would decouple them from the parent and turn them into "standalone components". But that would work equally well without wrapping it in a controller. – Nikolaj Dam Larsen Jul 27 '17 at 08:10
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/150267/discussion-between-nikolaj-dam-larsen-and-blewherself). – Nikolaj Dam Larsen Jul 27 '17 at 08:11
0

If you're not using isolated scope, you should be able to just use no1 and no2 directly in the template. assuming those are variables in the parent scope.

<script>
    var app = angular.module("Compl", []);
    app.directive("noSum",function(){
        return{
            template : "Sum of Two Number {{(no1 + no2)}}"
        };
    });
    app.directive("noSub",function(){
        return{
            template : "Sub of Two Number {{(no1 - no2)}}"
        };
    });
</script>

You should also rename your directives, since capitalized letters have special meaning in angular. So with my changed names above, your html should look like this:

<no-sum></no-sum>
<no-sub></no-sub>

Here is a Plunker showing it working as expected

This works because without isolated scope, your directives inherit the scope of their parent, which in your case is the $rootScope. If you used isolated scope instead, you would have to pass in the variables through html attributes.

Nikolaj Dam Larsen
  • 5,455
  • 4
  • 32
  • 45