11

Is it possible to passing a function to a component and call this function inside the component passing a parameter?

Example:

List of posts

<post-list posts="blog.posts"
           loading="blog.loadingPosts"
           get-post-url="blog.getPostUrl" 
           is-user-authenticate="blog.user">
</post-list>

getPostUrl is a function (inside the container controller):

const getPostUrl = (postId) => {
    const protocol = $location.protocol();
    const host = $location.host();
    const port = $location.port();

    return protocol + "://" + host + "" + (port !== 80 ? ":" + port : "") + "/blog/post/" + postId;
};

List of posts: component

const PostList = {
  "bindings": {
    "posts": "<",
    "loading": "<",
    "getPostUrl": "&", //Function getPostUrl
    "isUserAuthenticate": "<"
  },
  "template": `<div>
                <div class="col-md-9 text-center" data-ng-if="$ctrl.loading">
                  <i class="fa fa-spinner fa-spin fa-2x"></i>
                </div>

                <div class="col-md-9 posts" data-ng-if="!$ctrl.loading">
                  <div data-ng-repeat="post in $ctrl.posts">
                    <post creation-date="{{post.creationDate}}"
                          content="{{post.content}}"
                          post-url="{{$ctrl.getPostUrl(post.creationDate)}}"
                          is-user-authenticate="$ctrl.user">
                    </post>
                  </div>
                </div>
              </div>`,
   "transclude": false
};

 angular
  .module("blog")
  .component("postList", PostList);

In this line:

post-url="{{$ctrl.getPostUrl(post.creationDate)}}" I want to call the function passing a parameter and this function is returning a string.

In post component (not PostList) the postUrl is a string attribute @.

But... Is not working!

angular.js:13550 Error: [$interpolate:interr] Can't interpolate: {{$ctrl.getPostUrl(post.creationDate)}} TypeError: Cannot use 'in' operator to search for 'blog' in 1459329888892 Error Link

Is it possible to do it? And how?

Thank you so much!

3
  • You don't need the {{ }} for an & binding - see this section of the docs for a good example of how to achieve what you're looking to do: docs.angularjs.org/guide/… Commented Apr 27, 2016 at 8:37
  • But the return of this function is a string... post-url is a string. I want to call the function that return this string Commented Apr 27, 2016 at 8:45
  • I changed now... But now appears this error: Cannot use 'in' operator to search for 'blog' Commented Apr 27, 2016 at 8:53

4 Answers 4

23

You can pass functions to components, but you must define the function arguments as object with the correct arguments names as its keys. example:

<post-list posts="blog.posts"
           loading="blog.loadingPosts"
           get-post-url="blog.getPostUrl(postId)" 
           is-user-authenticate="blog.user">
</post-list>

const PostList = {
 "bindings": {
  "posts": "<",
  "loading": "<",
  "getPostUrl": "&", //Function getPostUrl
  "isUserAuthenticate": "<"
 },
 "template": `<post creation-date="{{post.creationDate}}"
                      content="{{post.content}}"
                      post-url="{{$ctrl.getPostUrl({postId:post.creationDate})}}">
                </post>
Sign up to request clarification or add additional context in comments.

1 Comment

this should really be the accepted solution as it is the proper function binding. Thanks for the tip. I didn't know the inner component had to pass the param back as a named object.
6

If you want to call the function from inside a component and have it return a value then you need two-way binding:

"bindings": {
  "posts": "<",
  "loading": "<",
  "getPostUrl": "=", // <-- two-way binding
  "isUserAuthenticate": "<"
},

However, this is probably not very good idea. Consider passing data to component rather than making component request data from outside. This will make much better isolated component.

Comments

0

To return a value to the binding function you must pass it as a object literal.
self.selected({id: '42', firstname: 'Douglas', lastname: 'Adams'});

angular.module('webapp').component('myComponent', {
    templateUrl: 'myComponent.html',

    bindings: {
        selected: '&'
    },
    controller: function () {
        var self = this;

        self.someEvent= function(){
            self.selected({id: '42', firstname: 'Douglas', lastname: 'Adams'});
        };
    }
});

Afterwards you can access the object literal values by it's properties.
id, firstname, lastname.
You can also pass additional parameters to the function. (myVariable)

<div>
    <span ng-init="myVariable='Universe'">
    <my-component selected="myFunction(id, firstname, lastname, myVariable)"></my-component>
</div>


$scope.myFunction = function(id, firstname, lastname, myVariable){
    console.log(id, firstname, lastname, myVariable);    
}

Comments

0

According to Todd Motto's Standards, it is not suggested to use '=' instead try using '&' that is passing a method from parent to child component and calling the method in the child will trigger back in the parent. Let's take an example.

Parent Component's template(HTML):

<child take-me-to-school="$ctrl.searchBikeKeyAndStart>

Child Component's controller:

public someFunction = () => {
  this.takeMeToSchool();
}

Once the function is called from the child component's controller then the function mapped in the parent will get triggered.

Parent Component's controller(HTML):

public searchBikeKeyAndStart = () => {
  .....
}

When you want to pass an argument to the same function

Parent Component's template(HTML):

<child take-me-to-school="$ctrl.searchBikeKeyAndStart(**key**)>

Child Component's controller:

public someFunction = () => {
  this.takeMeToSchool({key: parameterValue});
}

Once the function is called from the child component's controller then the function mapped in the parent will get triggered.

Parent Component's controller(HTML):

public searchBikeKeyAndStart = (**key**) => {
  console.log(**key**) //will print the param passed
}

Comments

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.