0

Is there a way to pass a boolean value (dataLoading) from an isolated scope directive to another element to show a progress bar when data is loading during login operations?

index.html

<div class="progress-line" ng-show="dataLoading"></div>
<login-user email = "email" password = "password" show-nav-bar="showNavBar" recover-password="recoverPassword(email)" data-loading="dataLoading"></login-user>

login.component.js

angular
    .module('login')
    .directive('loginUser', [function() {
        return {
            scope: {
                email: '=email',
                password: '=password',
                showNavBar: '=showNavBar',
                dataLoading: '=dataLoading',
                recoverPassword: '&'
            },
            controller: 'LoginController',
            templateUrl: 'login/login.template.html',

        };
    }]);

login.controller.js

function recoverPassword(email) {
    console.log("recoverPassword email: " + email);
    $scope.dataLoading = true;
    authenticationService.recoverPassword(email, function (response) {
        console.log("Response success, status: " + angular.toJson(response.data.status) + " message: " + angular.toJson(response.data.message));
        $scope.message = response.data.message;
        $scope.dataLoading = false;
    });
}
Daniele
  • 69
  • 5

3 Answers3

1

Usually it is a better practice to make your data to flow in one direction. Therefore, the owner of the dataLoading variable should be the common parent of the 2 components.

If the logic of that boolean should be inside user-login component, you can pass it an callback (via &), then user-login component will call it when ever it starts to fetch the data, then the parent will change the value of that boolean, and propagate it to the relevant children.

const app = angular.module('app', []);

app.directive('parentComponent', function() {
    return {
      controllerAs: 'parentVM',
      controller: function() {
        this.isLoading = false;
        this.onLogin = () => {
          this.isLoading = true;
        }
      },
      template: '<div><child on-login="parentVM.onLogin()"></child><other-child is-loading="parentVM.isLoading"></other-child></div>'
    };
  })
  .directive('otherChild', function() {
    return {
      scope: {
        localLoading: '=isLoading'
      },
      template: '<div ng-class="{\'is-loading\':localLoading}">{{localLoading? \'Loading...\': \'\'}}</div>'
    }
  })
  .directive('child', function() {
    return {
      scope: {
        onLogin: '&'
      },
      template: '<button ng-click="onLogin()">Login</button>'
    };
  })
.is-loading {
  background-color: rgba(0, 200, 0, 0.2);
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>

<div ng-app="app">
  <parent-component></parent-component>
</div>
felixmosh
  • 32,615
  • 9
  • 69
  • 88
0

You can use EventEmitter to send data to your controller.

EventEmitter({loading: true })

Add a binding on your component to catch changes:

onDataChanges: '&'

And you catch your data on component controller :

callbackdata(data) {
    this.loading= data.loading;
}

And your view :

<login ... onDataChanges="callbackdata($event)" ...></login>
brahimfes
  • 112
  • 7
0

Yes, absolutely. You can create a service that exposes a say 'loading' property, then inject the service to both your controller and your directive. Inside your directive set the 'loading' property of your service. That's all for your directive. Now inject the same service you injected into your directive to your controller for the element. So if the service was called myloadingservice you would do something like $scope.myloadingservice = myloadingservice. As soon as you have than that you can bind directly to the loading property of your service in your element, like this: ng-show="myloadingservice.loading"

Hope this helps.