1

Im trying to find a way to change some html lines of a component dynamically.

<li *ngFor="p in persons" [attr.id]="p.id">
   <span> {{ p.name }} </span>                      
   <a (click)="getAge(p.id)">Get Age<a/>     
</li>

If the user clicks on the Get Age link i would like to replace the content inside of the corresponding li tag to something like:

<span> {{ p.OtherProperty }} </span> 
<a (click)="OtherMethod(p)">Call OtherMethod<a/>

I found that ComponentFactoryResolver to create dynamic components, but i found it too overwhelming for just 2 lines of html. And i tried to change it by hand using jquery but it does not work to create the event bindings:

getAge(id) { 
    //some work
    //remove the corresponding <li> content
    $('#' + id).append('<a (click)="getAnotherValue(p.name)">GetAnotherValue<a/>');
    $('#' + id).append('<span> {{ p.age}} </span>'); //this obviously doesnt work. But thats the ideia.
 }

So how can i replace some html tags with angular attributes dynamically?

2
  • 2
    Please use angularjs tag for version 1.x only (Already retagged this question). Thanks Commented Jul 5, 2017 at 14:05
  • 2
    it is a better practice in angular to avoid DOM manipulations like this, there are ng directives for dynamic html. A angular way to do this is to bind the html code to a controller variable, and the function click will modify the content of the variable. The changes should reflect automatically Commented Jul 5, 2017 at 14:08

2 Answers 2

1

You could access the person's Object property dynamically like this:

object[property]; // Where property is a string
// If property equals 'name', the above sentence would equal this:
object.name; // or `object['name'];`

So, following your example, you could do this:

export class App {
  persons = [
    {
     id: 1,
     name: 'John',
     age: 25
    },
    {
     id: 2,
     name: 'Mike',
     age: 30
    }
  ];
  selectedProperty = 'name';

  constructor() {
  }

  getProperty(prop) {
    this.selectedProperty = prop;
  }
}

And in your template you could:

<div>
  <li *ngFor="let p of persons" [attr.id]="p.id">
    <span> {{ p[selectedProperty] }} </span>
    <br>
  </li>
  <button (click)="getProperty('age')">Get Age</button> 
  <button (click)="getProperty('name')">Get Name</button>
</div>

If I understood well, this should do the trick. You can't use ngIf because if you have 60 properties or persons then will be somewhat caothic.

Check the Plunker

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

3 Comments

Good workaround. This works well for the person property, but im not sure if can resolve the button replacement.
You could replace the button with a <select> where each <option> is a property of the person object, such as: Age, Name, Surname, etc. And, onChange() of the select, you trigger getProperty() passing as parameter the value of the <option>.
That way you'll have many <li> elements (one for each person in your persons object) and a simple dropdown (<select>).
0

Use ngIf to activate the code as shown:

     <li *ngFor="p in persons" [attr.id]="p.id">

        <div *ngIf=!p?.touched>

             <span> {{ p.name }} </span>
             <a (click)="getAge(p)">Get Age<a/>
        </div>

        <div *ngIf=p?.touched>
            <span> {{ p.age}} </span> 
            <a (click)="getAnotherValue(p.name)">GetAnotherValue<a/>
       </div>  

     </li>

    isGetAgeClicked=false;

        getAge(person) { 
            //some work
            //remove the corresponding <li> content
         person.touched=true
         }

2 Comments

but if i have 10 <li> itens rendered. All of them will change if i clicked in one of them?
@gog Try the edited answer, I hope it will work for your case

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.