Sukhmeet Singh
Sukhmeet Singh

Reputation: 130

Communication between Controller and Directive in angularjs

I am trying to create a small app using AngularJS which consists of users and issues posted by the users respectively.

I am trying to show issues when a particular user is clicked.

I have created the following code so far:

index.html

  <div class="container" ng-controller="issueContainer as issueTrack">

      <div class="leftContainer" ng-controller="issueForm as issueformCtrl">
          <issue-form></issue-form>

          <user-issues ng-repeat="issue in user.issues"></user-issues>    
      </div>

      <div class="rightContainer" ng-controller="userForm as userformCtrl">

          <form name="userform" ng-submit="userform.$valid && userformCtrl.addUsers()">
              <div class="form-group">
                <label for="addUser">Username</label>
                <input type="text" id="addUser" ng-model="userformCtrl.name" class="form-control" placeholder="Username">
              </div>
              <div class="form-group">
                <input type="submit" class="btn btn-primary" value="Submit" />
              </div>
          </form>

          <h3 class="usersTitle">Users</h3>

          <div class="users" ng-show="issueTrack.users.length">
              <div ng-repeat="user in issueTrack.users track by $index" value="{{user.username}}" ng-click="userformCtrl.userclickCtrl(user.username)">
                  {{user.username}}
              </div>
          </div>
      </div>
  </div>

app.js

(function(){

var app = angular.module("Issuetracker",[]);

var users=[];

if (localStorage.getItem('users')!==null){

    users = JSON.parse(localStorage.getItem("users"));
    console.log(users);
}

app.controller("issueContainer", function(){

    var issuetrack = this;
    this.users = users;

});

app.controller("userForm", function(){

    this.addUsers = function(){

        users.push({'username':this.name, 'issues':[]});
        this.name='';
        console.log(users);
        localStorage.setItem("users", JSON.stringify(users));
    };      

    this.userclickCtrl= function(data){

        var allUsers = JSON.parse(localStorage.getItem("users"));

        for(var i=0;i< allUsers.length;i++){

            if(allUsers[i].username == data){

                var userData = allUsers[i];
                break;
            }
        }
    };
});

app.controller("issueForm", function(){

    this.issue={};
    this.addIssues = function(){

        console.log(this.issue);
        var allUsers = JSON.parse(localStorage.getItem("users"));

        for(var i=0;i< allUsers.length;i++){

            if(allUsers[i].username == this.issue.User){

                allUsers[i].issues.push(this.issue);
                break;
            }
        }            

        this.issue={};

        localStorage.setItem("users", JSON.stringify(allUsers));
    };                
});

app.directive("userIssues", function(){

   return{

        restrict: 'E',
        templateUrl: 'userissues.html'
   }  
});

app.directive("issueForm", function(){

   return{

        restrict: 'E',
        templateUrl: 'issueform.html' 
   }  
});

})()

userissues.html

<div class="issues">
    <div ng-repeat="issue in user.issues">
        <h3>{{issue.Summary}}<span class="label label-primary" style="margin-left:2%">{{issue.Type}}</span></h3>
        <p>{{issue.Description}}</p>
    </div>
</div>

Whenever any user is clicked, userclickCtrl function is called where i am getting the user object from localStrorageand want to pass it to the userissues directive for the template.

Any leads would be appreciated!!!

Upvotes: 2

Views: 2697

Answers (3)

Sukhmeet Singh
Sukhmeet Singh

Reputation: 130

I am glad that @KevinWang and @Rick helped me with the answer i was looking for. Along with these, i found an awesome tutorial on Understanding Scope in Directives, which explains and complements @Rick's answer. I am sharing the link over here for elaborate understanding.

http://www.undefinednull.com/2014/02/11/mastering-the-scope-of-a-directive-in-angularjs/

Upvotes: 0

rick
rick

Reputation: 1895

Don't know if I got your problem but maybe this is a possible solution.

You can pass the issue as argument to your directive in this way:

app.directive("userIssues", function(){

return{

    restrict: 'E',
    scope: { issue: '=' },
    templateUrl: 'userissues.html'

}
});

and you can use it like this:

<user-issues ng-repeat="issue in issues" issue="issue"></user-issues>

Try this fiddle for an example

Hope this is what you need

Upvotes: 1

Kevin
Kevin

Reputation: 2893

Not sure what you are using localStorage for, for sharing data between the controller and the directive? why not just use window.users.. But that is bad practice too.

There are two ways I can think of to make possible Controller-Directive communication.

1.Using event publish/subscribe ($on, $broadcast and $emit)

In the controller, use $scope.$broadcast('eventName',eventData) to send a message to all its child scopes, and in the directive, use $scope.$on('eventName',callback) to listen for it. The directive can also send message to the controller by using scope.$emit('eventName',eventData), please do some googling or refer to the official docs for more details.

If you can figure out ways to get the reference of the directive scope, use broadcast on the directive scope directly, it will be more efficient since the event will not be broadcast to irrelevant scopes.

Also, for efficiency concerns, when you use $emit in the directive, the $on callback in the controller should contain event.defaultPrevented = true;, to stop the propagation of the event into irrelevant higher class scopes.

2.Pass into the directive the reference of a object (we can call the object a handler/delegate/etc. not so sure) in controller via directive attribute.

I'm not sure whether it's a good practice but it's an effective practice that I often use.

E.g.

the directive:

js:

  app.directive('userIssues', function () {
      return {
          restrict: 'E',
          templateUrl: 'templates/user-issues.html',
          scope: {
              delegate: '='
          },
          link: function (scope, element, attr) {
              scope.issues = [];
              scope.delegate.addIssue = function (issue) {
                  scope.issues.push(issue);
                  console.log("An issue is added to the directive !!");
              };
              scope.issueClicked = function (id) {
                  scope.delegate.issueClicked(id);
              }  
          }
      }
  });

html:

 <div>
     {{issues}} //I will change when notified from controller
     <button ng-click="issueClicked(123)">
         click me to notify controller
     </button>
 </div>

the controller:

js:

app.controller('myController', function ($scope, $timeout) {
    $scope.issueDirectiveDelegate = {
        issueClicked: function (id) {
            console.log("received message from the directive that issue with id ", id, 'is clicked');
        }
    };

    $timeout(function(){
        getMoreIssues().then(function (issue) {
            $scope.issueDirectiveDelegate.addIssue(issue);
        });
    },1000);
});

html:

<div> <div>blahblah</div>
   <user-issues delegate="issueDirectiveDelegate"></user-issues>
</div>

Upvotes: 3

Related Questions