javascriptangularjsangularjs-ng-click

Angular JS ng-click not being triggered, using multiple controllers


I'm trying to get ng-click from one of my views to work globally.

I started with this Plunker

and I've looked at these answers already:

ng-click not firing in AngularJS while onclick does

Angular ng-click not firing

AngularJS : ng-click not working

From what I can tell, all of these have a ng-click in the same controller whereas the function I'm trying to call is in a different controller, but it has $scope, so that function should be reachable anywhere if I'm not mistaken.

Relevant Code(sorry its alot):

index.html:

<!doctype html>
<html lang="en" ng-app="floorForceApp">
  <head>
    <meta charset="utf-8">
    <title>Floor Force Web</title>
    <link rel="stylesheet" href="floorForceApp.css" />
    <script src="lib/angular/angular.js"></script>
    <script src="lib/angular-route/angular-route.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
  <!-- <script src="floorForceApp.js" ></script> -->
    <script src="app.module.js"></script>
    <script src="app.config.js"></script>
    <script src="header-bar/header-bar.module.js"></script>
    <script src="header-bar/header-bar.component.js"></script>
    <script src="cabinet-page/cabinet-page.module.js"></script>
    <script src="cabinet-page/cabinet-page.component.js"></script>
    <script src="checkout-page/checkout-page.module.js"></script>
    <script src="checkout-page/checkout-page.component.js"></script>
    <script src="floor-page/floor-page.module.js"></script>
    <script src="floor-page/floor-page.component.js"></script>
    <script src="home-page/home-page.module.js"></script>
    <script src="home-page/home-page.component.js"></script>
    <script src="wall-page/wall-page.module.js"></script>
    <script src="wall-page/wall-page.component.js"></script>
  </head>
  <body>

    <header-bar></header-bar>

    <div ng-view></div>

  </body>
</html>

app.module.js:

'use strict';

angular.module('floorForceApp', [
  'headerBar',
  'ngRoute',
  'cabinetPage',
  'checkoutPage',
  'floorPage',
  'homePage',
  'wallPage'
]);

app.config.js:

'use strict';

angular.
  module('floorForceApp').
  config(['$routeProvider',
    function config($routeProvider) {
      $routeProvider.
        when('/home', {
          template: '<home-page></home-page>'
        }).
        when('/floors', {
          template: '<floor-page></floor-page>'
        }).
        when('/cabinets', {
          template: '<cabinet-page></cabinet-page>'
        }).
        when('/walls', {
          template: '<wall-page></wall-page>'
        }).
        when('/checkout', {
          template: '<checkout-page></checkout-page>'
        }).
        otherwise('/home');
    }
  ]);

checkout-page.module.js(floor-page.module.js looks the same as this, except it references 'floorPage'):

'use strict';

angular.module('checkoutPage', [
    'ngRoute'
]);

checkout-page.component.js (the function I'm trying call is in this file - $scope.addToCart) :

'use strict';

angular.
    module('checkoutPage').
    component('checkoutPage',{
        templateUrl: 'checkout-page/checkout-page.template.html',
        controller: function checkOutController($scope){

            $scope.cart = [];
            $scope.total = 0;
            $scope.totalCount = 0;

            $scope.addToCart = function(item,count){
                if(!count) count = 1;
                if($scope.cart.filter(function (e){ return e.itemNo === item.itemNo})){
                    $scope.cart.filter(function (e){ return e.itemNo === item.itemNo})[0].count = $scope.cart.filter(function (e){ return e.itemNo === item.itemNo})[0].count + count;
                }else{
                    $scope.cart.push(item);
                    $scope.cart.filter(function (e){ return e.itemNo === item.itemNo})[0].count = 1;
                }
                $scope.total = parseFloat($scope.total + (item.itemPrice * count));
            }

            $scope.removeFromCart = function(item,count){
                let workingItem = $scope.cart.filter(function (e){ return e.itemNo === item.itemNo});

                if(!count) count = 1;
                if(workingItem){
                    workingItem[0].count = workingItem[0].count - count;
                    $scope.total = parseFloat($scope.total - (item.itemPrice * count));
                }else{
                    //If No Item found, do nothing
                }
            }

            $scope.checkOut = function(){

            }
        }
    })

floor-page.component.js

'use strict';

angular.
    module('floorPage').
    component('floorPage',{
        templateUrl: 'floor-page/floor-page.template.html',
        controller: function headerBarController($scope,$http){
            let self = this;

        $http.get('/items/floorForceData.json').then(function(resp){
            self.items = resp.data;
        });

    }
})

floor-page.template.html(this is where the ng-click is,second input tag):

<div>
    <div ng-repeat="item in $ctrl.items|filter:{itemType:'floor'}" style="height:30em;">
        <div class="container-fluid h-100" >
            <div class="row h-100">
                <div class="col-sm-6 h-100 ">
                    <div class="row prodImage h-100"></div>
                </div>
                <div class="col-sm-6 h-100">
                    <div class="row h-100 ">
                        <div class="col-sm-12 prodDesc h-50 paddingZero">
                            <div class="titleDiv">{{item.itemName}}</div>
                            <div class="descDiv">{{item.itemDesc}}</div>
                        </div>
                        <div class="col-sm-12 addToCart h-50 paddingZero">
                            <div class="row h-100 marginAuto">
                                <div class="col-sm-6 h-100 paddingZero">
                                    <div class="addDiv">
                                        <input class="addAmount" type="number"/>
                                    </div>
                                </div>
                                <div class="col-sm-6 h-100 paddingZero">
                                    <div class="row marginAuto h-100">
                                        <div class="col-sm-12"></div>
                                        <div class="col-sm-4"></div>
                                        <div class="col-sm-4">
                                            <input class="addToCartButton btn btn-success" ng-click="$scope.addToCart(item)" type="button"value="Add to Cart"/>
                                        </div>
                                        <div class="col-sm-4"></div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

Solution

  • You are using components and therefore each $scope is isolated. From the docs:

    Components only control their own View and Data: Components should never modify any data or DOM that is out of their own scope. Normally, in AngularJS it is possible to modify data anywhere in the application through scope inheritance and watches. This is practical, but can also lead to problems when it is not clear which part of the application is responsible for modifying the data. That is why component directives use an isolate scope, so a whole class of scope manipulation is not possible.

    The line ng-click="$scope.addToCart(item)" would not work anyway as you would need to access the function through the controller alias which defaults to $ctrl. So you would write something like $ctrl.addToCart(item).

    If I were you I would continue to use components and restructure the app so that communication between components is explicit, either through input/output bindings, or through services.

    Hope this helps