1

I have a directive for uploading files. I am calling this in my view called "UploadRecords.html". I have a button called "Upload" in "UploadRecords.html". On click of this button, I want to call the "UploadAll" method defined inside the link function in my directive. What are the ways to achieve this.

Basically I want to call a directive function on click of a root scope element.

Note: I am using isolated scope in my directive

angular.module('fileUpload', [])
.directive(
    "fileUpload",
    function () {
        return ({
            restrict: 'E',
            scope: {                
                onSuccess: '&',
                onError: '&',
            },
            templateUrl: 'Templates/FileUploadTemplate.html',
            link: function (scope, element, attrs) {
                scope.files = [];
                scope.addFile = function (element, documentType) {
                    if (element.files.length > 0) {
                        $.each(element.files, function (index, file) {
                            scope.files.push(file);
                        });
                    }
                    scope.$apply();
                }

                scope.uploadAll = function () {

                    //This is where I upload the files to the web api using a FormData post

                }
            }

        });
    }
    );


<file-upload on-success="onFileUloadAllSuccess()" on-error="onFileUloadAllError()"></file-upload>

<button type="button" class="btn btn-default">Upload All</button>

Thanks, Sam.

5
  • I'm confused. Does the click happen on the parent's directive or the child's directive? And the response is on the other unclicked directive? Commented Sep 23, 2014 at 19:04
  • I am sorry, i confused by using the word parent. What I meant by parent is the view where the directive is called. Commented Sep 23, 2014 at 19:07
  • Can you provide a markup of how your structure is? It is very hard to understand what is going and what is clicked and what needs to be done. Commented Sep 23, 2014 at 19:08
  • I have updated this. Okay. I will add a bit of code as well. Commented Sep 23, 2014 at 19:09
  • With your current implementation, there is NO way. Read my answer. Tell me which option you like, and I can expand on that. Commented Sep 23, 2014 at 19:26

2 Answers 2

2

The way you have setup your HTML, there is no way for your button to communicate with your directive, since they are completely separate. You have a few options:

  1. Move the button inside the FileUploadTemplate.html so that it is now under the directive's scope. If you do so, all you have to do is add ng-click="uploadAll()" to the attribute:

    Upload All

  2. Define a directive for your button. Then use $emit to communicate between the two directive.

  3. Define a directive for your button. Define a "parent" directive that has the two children, button and your current template. This way ,the scope inside the parent is accessible to both children, and they can communicate via the parent.

Here is how you can use $emit. Define your button html as:

<button type="button" class="btn btn-default" ng-click="uploadAll()" button-upload>
    Upload All
</button>

Now add a directive for this:

app.directive('buttonUpload', ['$rootScope', 
    function($rootScope)
    {
        return {
            restrict: 'A',
            link: function(scope, element, attrs)
            {
                scope.uploadAll = function() {
                    $rootScope.$emit('UPLOAD_ALL');
                }
            }
        }
    }
]);

Then in your fileUpload directive, you can have:

app.directive('fileUpload', ['$rootScope', 
    function($rootScope)
    {
        return {
            // Your restrict, templateUrl, scope
            link: function(scope, element, attrs)
            {
                // All your other code
                // remove scope.uploadAll


                // This will get called everytime $emit is broadcasted
                $rootScope.$on('UPLOAD_ALL', function(event) {
                    // Your upload code goes here
                });

            }
        }
    }
]);

This is NOT a really good approach: you shouldn't really use $emit and $broadcast. You should consider my third option of having a parent of the two directive.

Sign up to request clarification or add additional context in comments.

8 Comments

I would have loved to move the button inside my template, but wont be able to do it since that comes below a lot of other html stuffs. I mean, in between <file-upload> and <button> there are lot of other Html things which are not part of the directive. Let me try the second approach. I havent done $emit yet. Let me read about it once and I will do the second approach. I will update you about the progress.
@sam113, by other "html" things, do you mean there are other HTML tags present that you have not included in the markup above? And I will quickly just post an example of how you can use $emit.
yes Kousha. I had excluded them here to avoid confusion. Also, it would be great if you can explain a bit more on how the $emit is done.
thanks for that Kousha. I will try that now. Btw, I was reading some articles and came to know that broadcasting on the root scope is not a good way. Any comments on that. @DeadCalimero, if you can also comment on this, it would be good.
@sam113, yes $broadcast on rootScope is bad (which is why I used $emit in my code above). The difference is that $emit travels up the branch, and $broadcast down the branch. So $emit on $rootScope will go up just one level (since $rootScope is the top branch). But $broadcast will go down ALL the way to your last scope. And so your $digest cycle will be longer.
|
1

Broadcast can be in my opinion a good solution to your problem

You can do something like that :

Root Controller -> Directive

Root Controller

$scope.$broadcast('go');

Directive

$scope.$on('go', function () { alert('event is clicked') });

JsFiddle

Directive -> Root Controller

Root Controller :

$scope.$on('go', function () { alert('event is clicked') });

Directive :

$scope.$emit('go');

** This is not necessarily the most elegant solution, that we agree but it will solve your problem

6 Comments

In my opinion, broadcast and emit are not he best practice, since they are not really the "Angular Way". This problem can be solved by having a parent directive that the other two directives are part of it, and they can communicate through that. Or even the use of a service.
Also, you need a $ for your broadcast and emit. And generally, if you do want to use $broadcast, i suggest to use $emit on $rootScope since it will up on one branch only (unless you really need your broadcast to go down multiple branches).
Thank you ! I had actually made ​​a mistake. Yes, the technique that you suggest is more elegant, my technique is to solve the current problem and not the problem of design.
Okay. that was nice info. So, rather than going for a parent and 2 directives as part of it, will be it possible to create the button directive as child and the fileupload as the parent and then use $emit
@sam113, yes. Read my comment on my post about the difference of $emit and $broadcast. They are not interchangeable. The positioning of the scopes are very important for them to work.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.