0

I am building an Angular 9 app. In this app I let my users save "placeholders" in text into the database.

I want to present these placeholders but replace it with real data when rendering.

For example. The object that holds the data is called Model so normally I present the data on page like this which shows the users name.

{{model.fullname}}

Basically I want to save this placeholder into the database and then render it. So my question is how I can make {{model.fullname}} "active" when rendering the page even though it is coming from the database/JSON instead of being hard coded into the page.

Update

I tried the Pipe suggestion posted below and it kind of works. The problem is that it prints that real data alone and not in context inside the larger string. In other word, I need to replace placeholder value within the text at their real places within the string.

This is the Pipe code:

import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
  name: 'template',
})
export class TemplatePipe implements PipeTransform {
  transform(value: string, args: any): any {
    if (value.indexOf('.name') !== -1) {
      return args.name;
    }
    if (value.indexOf('.id') !== -1) {
      console.log(args.id);
      return args.id;
    }
    return null;
  }
}

This is a typical text that I want to use:

The name of the user is {{model.name}} and got the ID of {{model.id}}.

The result must be:

The name of the user is Paul Palmer and got the ID of 123456.
Mark Denn
  • 2,236
  • 5
  • 22
  • 20
  • Does this answer your question? https://stackoverflow.com/q/34784778/1260204 – Igor Nov 05 '20 at 16:46
  • Thank you, but it does not look like that. I don´t want to dynamically render component but only small variables. – Mark Denn Nov 05 '20 at 16:55

1 Answers1

1

A simple solution is to make use of pipes.

So for example you have an object like

export class Candidate{
    public id: number;
    public name: string;
}

And you want to store the keys in database or in json file or whatever (the key is that they will be rendered dynamically), to illustrate lets say my key is stored in a variable in component like this

public key: string = "{{candidate.name}}";

Now I've created a pipe that will check the key and return the corresponding object property, like this.

export class TransformkeyPipe implements PipeTransform {
  transform(value: any, args: any): any {
if (value == "{{candidate.name}}") {
  return args.name;
}
if (value == "{{candidate.id}}") {
  return args.id;
}
return null;
  }
}

In the component file, I'll apply the pipe along with the actual object that has the data. Something like this

<p>{{key | transformkey: candidate}}</p>

EDIT:

In case you want to replace placeholders in a string, then simply you'll have to use javascript match function to extract out the placeholders using some regex. And then one by one replace them with actual data. Something like this.

export class Transformkey2Pipe implements PipeTransform {
  transform(value: string, args: any): any {
const regexp = /{{[a-z]*.[a-z]*}}/g;
const array: string[] = value.match(regexp);

array.forEach(x => {
  switch (x) {
    case "{{candidate.name}}":
      value = value.replace(x, args.name);
      break;
    case "{{candidate.id}}":
      value = value.replace(x, args.id);
      break;
  }
});

return value;
}
}

EDIT 2 In case you want to use multiple data-sources, one approach could be to pass the objectType parameter to your pipe, and based on that decide which field of datasource to picke. Something like this

export class Transformkey3Pipe implements PipeTransform {
  transform(value: string, args: any, objectType: string): any {
const regexp = /{{[a-z]*.[a-z]*}}/g;
const array: string[] = value.match(regexp);

array.forEach(x => {
  switch (x) {
    case "{{key.name}}":
      if (objectType == "candidate") {
        value = value.replace(x, args.name);
      }
      if (objectType == "employee") {
        value = value.replace(x, args.emp_name);
      }
      break;
    case "{{key.id}}":
      if (objectType == "candidate") {
        value = value.replace(x, args.id);
      }
      if (objectType == "employee") {
        value = value.replace(x, args.emp_id);
      }
      break;
  }
});

return value;
  }
}

Please find the updated stackblitz.

Obaid
  • 2,563
  • 17
  • 15
  • 1
    Very interesting! Almost exactly what I need. One thing though, it will never match for example {{candidate.name}} alone but this variable is always part of a larger string like for example: "The name of the user is {{candidate.name}}". How can I use your Pipe with a larger string that just the {{candidate.name}} alone? – Mark Denn Nov 05 '20 at 17:14
  • In other words. How can I use your pipe to replace theme place holder where it is within a larger text? – Mark Denn Nov 05 '20 at 17:30
  • Worked perfectly! Last thing, is it possible to make it more dynamic so I don´t have to use a switch? Like if {{candidate.id}} contains .id it will always return args.id? – Mark Denn Nov 05 '20 at 17:40
  • 1
    You mean the key could extract values from multiple data sources. In that case you can pass a third argument to your pipe mentioning the type of object, say its name is "objectType". So for example you can say if(objectType=='candidate') then use args.id if(objectType=='employee') then use arge.emp_id etc. – Obaid Nov 05 '20 at 17:45
  • 1
    Brilliant, this was exactly what I needed! Thank you so much! – Mark Denn Nov 05 '20 at 17:52