Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular - Passing an object from one directive to another directive

I am new to angular so apologies up front if a question is too newbie. I am trying to make a custom directive, and since I am already using an angular-youtube-embed directive, inside my new directive, I need to pass a player object from youtube-video directive, to my new directive, for the function playVideo in my scope to use it. I wonder how to do that? This is how my directive looks:

angular.module('coop.directives')
.directive('youtubePlayer', function () {
    return {
        restrict: 'E',
        scope: {
          videoPlaying: '=videoPlaying',
          playVideo: '&playVideo',
          playerVars: '=playerVars',
          article: '=article'
         },
        templateUrl : 'templates/youtube-player.html'
    };
}); 

This is my youtube-player.html:

<img ng-hide='videoPlaying' ng-src='http://i1.ytimg.com/vi/{{ article.external_media[0].video_id }}/maxresdefault.jpg' class='cover'>
<youtube-video ng-if='videoPlaying' video-url='article.external_media[0].original_url' player='player' player-vars='playerVars' class='video'></youtube-video>
<div ng-hide='videoPlaying' class='iframe-overlay' ng-click='playVideo({player: player})'>
  <img ng-hide='videoPlaying' class='play' src='icons/play.svg'/>
  <img ng-hide='videoPlaying' class='playButton' src='icons/playRectangle.svg'/>
</div>

And this is the function from the controller that I would like to use in my directive:

  $scope.playVideo = function(player) {
    $scope.videoPlaying = true;
    player.playVideo();
  };

Where player is an object of youtube-video directive that I am using from angular-youtube-embed package. So, whenever a user clicks on an element below, $scope.videoPlaying should become true and a playVideo() function should start the video:

<div ng-hide='videoPlaying' class='iframe-overlay' ng-click='playVideo(player)'>

This is how I call my directive in the view:

<youtube-player video-playing="videoPlaying" play-video="playVideo()" player-vars="playerVars" article="article"></youtube-player>

I should somehow pass a player object from youtube video to my new directive because now I get an error of:

ionic.bundle.js:26794 TypeError: Cannot read property 'playVideo' of undefined:

like image 304
Ludwig Avatar asked Aug 16 '16 09:08

Ludwig


People also ask

How do you transfer data from one directive to another?

The best way to pass an object to an angular directive is by using the &. When you use &, angular compiles the string as an expression and sets the scope variable in your directive to a function that, when called, will evaluate the expression in the context of the directive's parent's scope.

Can we import directives in Angular?

You can put commonly used directives, pipes, and components into one module and then import just that module wherever you need it in other parts of your application. Notice the following: It imports the CommonModule because the module's component needs common directives.

What does $compile do in AngularJS?

The $compile service is the service to use for compilation. Invoking $compile against markup will produce a function you can use to bind the markup against a particular scope (what Angular calls a linking function). After linking, you'll have DOM elements you can place into the browser.

What are the three types of directives in Angular?

The three types of directives in Angular are attribute directives, structural directives, and components.

How to pass data from parent component to child component in angular?

Angular provides us @Input decorator by using that we can pass data from parent component to child component. In the above code first, we imported an Input decorator from the @angular/core package and added it in front of name property so that it can available to pass data from the parent component.

How to return data from app-Register component in angular?

The app component is a root component generated by Angular itself. We have added app-register component in app.component.html with the properties tableDataValues. Data will return from the app-register component by submitting values. It will hold and pass to a method that is submitted ($event).

How to connect two components to one service in angular?

This way, if two components want to access (either by pulling or pushing, see Functional Reactive Programming for Angular Developers) they just need to declare a dependency on the service, removing the need to create intermediate @Input () or @Outputs, regardless where in the angular component tree hierarchy each component is located.

What is [ngclass] directive in Bootstrap?

NgClass is a directive where we can set classes dynamically. Below is a screenshot in which there is a sample Form to add values. Added values will display in the card. I have created Forms and Cards with the help of Bootstrap. In this scenario, I am covering the few topics, including @input (), @Output () and [ngClass] with Form validation.


2 Answers

You can use $broadcast to achieve this.

Below is the diagram explaining the concept.

enter image description here

In youtubePlayer Directive use broadcast -

$rootscope.$broadcast('player-object', $scope.player);

And receive it in your custom directive.

$scope.$on('player-object', function (event, player) {
    $scope.videoPlaying = true;
    player.playVideo();
 });

Sample Example -http://jsfiddle.net/HB7LU/10364/

like image 107
Vaibhav Shah Avatar answered Oct 22 '22 11:10

Vaibhav Shah


You can use '&' type for passing function in directives:

angular.module('coop.directives')
  .directive('youtubePlayer', function () {
    return {
        restrict: 'E',
        scope: {
          action: '&', //<- this type of parameter lets pass function to directives
          videoPlaying: '@videoPlaying',
          ...

so you directive will accept a parameter as a function, like this:

<coop.directives action="playVideo" videoPlaying="video" ...> </coop.directives>

and you'll be able to call that function normally:

      article: '=article'
     },
 template : "<img ng-hide='videoPlaying' ng-src='http://i1.ytimg.com/vi/{{ article.external_media[0].video_id }}/maxresdefault.jpg' class='cover'><youtube-video ng-if='videoPlaying' video-url='article.external_media[0].original_url' player='player' player-vars='playerVars' class='video'></youtube-video><div ng-hide='videoPlaying' class='iframe-overlay' ng-click='playVideo(player)'><img ng-hide='videoPlaying' class='play' src='icons/play.svg'/><img ng-hide='videoPlaying' class='playButton' src='icons/playRectangle.svg'/></div>",
    link: function (scope, element) {
      scope.action();
    }

Edit 1:

If none of those suggestions works, you can try to add () brackets to you action parameter action="playVideo()" or use '=' type parameter (but this way, your function will be double binded. In most cases you don't have to worry about it for functions, anyway).

You can find some examples in this old post: just try either solutions and find which one is working for your case.

like image 39
illeb Avatar answered Oct 22 '22 13:10

illeb