4

I want to create a reusable function that could be used in angular templates. I have created a function as:

 export function stringSplit(string : string, separator : string = '/') : any {
    return string.split(separator);
}

I have tried to add into the template like this:

<p> stringSplit('hello/user') </p>

But i am getting this error:

ERROR TypeError: _co.stringSplit is not a function

I am not sure how we can create and use global functions in angular.

Can we perform this operation in angular?

What is the best solution in this situation?

PaladiN
  • 4,625
  • 8
  • 41
  • 66
  • 2
    have a global `@Injectable` service and use the methods there – Aravind Nov 21 '17 at 10:14
  • create a service with `@Injectable({ providedIn: 'root' })`. then add the methods in there. now import the service in required components, so the you can use those methods. – suhailvs Oct 09 '18 at 05:26

3 Answers3

11

The answer is you should not. Dependency Injection is a powerful tool provided by Angular with the sole purpose of sharing functionality across components without maintaining a global scope. What you should really do is create a service, add a method to it, inject your service into any component that needs it, and invoke it there.

Judging by your question it would be nice to have a pipe to perform the operation you need. Pipes are used to manipulate data inside any template (making the function virtually global to all templates that belong to components that belong to modules which either declare or import the pipe). You can write this:

@Pipe({name: 'splitString'})
export class SplitString implements PipeTransform {
  transform(value: string, separator: string): string[] {
     return value.split(separator);   
  }
}

And in your html:

<p>{{ myString | splitString : ',' }} </p>

Read more about pipes here.

Armen Vardanyan
  • 3,214
  • 1
  • 13
  • 34
  • I am aware of the pipes but i am searching for other methods rather than pipes. As i need to do some manipulations before transforming using pipes. – PaladiN Nov 21 '17 at 11:28
  • 1
    You can combine pipes – Armen Vardanyan Nov 21 '17 at 11:29
  • So how do you combine pipes in the template without additional custom pipe?? – PaladiN Nov 21 '17 at 12:04
  • 1
    @PaladiN It looks like you have XY problem. If combining pipes was a real problem, it should be specified in the question. You can combine pipes like `{{ 'foo' | splitString | bar | baz }}`. That's why they are called pipes. – Estus Flask Nov 21 '17 at 12:21
  • @estus I was doing the same but there i had added pipe to the wrong location. Anyways thanks. – PaladiN Nov 21 '17 at 12:39
3

In general it is considered a bad practice.
But if you have to use this global function you can just add it as a member inside your component. Somewhere in the code:

export function stringSplit(string : string, separator : string = '/') : any {
    return string.split(separator);
}

In your component:

import {stringSplit} from '....'
...
class MyComponent {
  public stringSplit = stringSplit;
}

Then in template:

<p> stringSplit('hello/user') </p>

But as I already mentioned it is a bad practice. Consider using service/pipe instead.

JeB
  • 11,653
  • 10
  • 58
  • 87
2

Global functions cannot and shouldn't be used in templates. If stringSplit needs to be used in template, it has to be component property. Inheritance can be used to make it available in multiple components and keep them DRY:

abstract class BaseComponent {
  stringSplit(...) { ... }
}

@Component(...)
class FooComponent extends BaseComponent { ... }

And the proper way to do this is to make stringSplit a pipe, because this is what pipes are for. stringSplit is pure function, and pure pipe (default) allows to skip change detection when pipe inputs are unchanged and pipe output is expected to be the same, e.g. {{ 'foo' | stringSplit }}. While {{ stringSplit('foo') }} will execute a helper function on each change detection cycle.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565