How to programatically add ionic component

Hi everyone ! I’m new to ionic and I would like to add Ionic component programatically.

For example, i would add the equivalent of this html code

	<ion-item>
		<ion-label>chk</ion-label>
		<ion-checkbox></ion-checkbox>
	</ion-item>

I use this

	var component = document.createElement('ion-item');
	component.className = "item item-checkbox";
	var ionchk = document.createElement('ion-checkbox');
	//ionchk.innerHTML = champ.Description;
	//ionchk.className = "item item-checkbox";
	var ionlbl = document.createElement('ion-label');
	ionlbl.innerHTML = champ.Description;
	component.appendChild(ionlbl);
	component.appendChild(ionchkcomponent);
	 document.getElementsByClassName('ContentMain')[0].firstElementChild.appendChild(component);

But with this kind i should dev all the ionic work. Is there a way to directly add ionic component ?

Thanks in advance

WHy don’t you use Angular 2’s capabilities of doing that stuff for you?

<ion-item *ngFor="let option of optionsArray">
  <ion-label>{{option}}</ion-label>
  <ion-checkbox></ion-checkbox>
</ion-item>
<ion-item *ngIf="<Please append this html to DOM by my trigger>">
  <ion-label>chk</ion-label>
  <ion-checkbox></ion-checkbox>
</ion-item>

Thanks for your answer.

In fact i would like to generate my page thanks to my database record. I would generate lots of component (checkbox, input text, radio-buton) in a certain order. All of theses information are store in my Db and now i would create the assiocated form.

Never mind. You opinion is wrong. You no need work with DOM.

Try understand this:
https://angular.io/docs/ts/latest/api/core/DynamicComponentLoader-class.html

I don’t understand all of this topic but I try tu use the DOM. When i load a component of a checkbox for example, i get a simple HTML checkbox not the ionic checkbox.

Could you give me a sample example of a checkbox component and the call of this component if you think that’s possible. Or help me to find the right way.

Thanks in advance.

your linke is out of date

https://angular.io/guide/dynamic-component-loader

I remain firmly convinced that this is a very bad idea, and anybody who comes across this thread looking for solutions would be much better served rethinking their design to make all templates available at compile time. That makes for much more stable, testable, maintainable, and performant apps.

2 Likes

When working with realtime database one needs a good way of removing/editing/adding dom nodes though.

Any developments occurred since this thread ended? I see its been a year.

In my example I have objects coming in on every update/deleting/addition in my db. These objects are modelled into ion-cards and styled based on the object’s property values. Their position in a ion-list also communicates age of objects.

It would be nice If there is some way to hook into the events and restyle/rearrange/add new cards in real time

That is why they invented observables through rxjs

Check them out on angular.io and async template binding

The go to technique also for the OP of this chain of messages

Removing and adding I agree with, and the ngFor and ngIf structural directives do a good job of that. Editing I’m not seeing the need for.

I think it makes sense to think first about what you want your users to see; ignoring how one would implement that. So can we generally say that you want users to see a list of cards, each card representing a thingy? If so, then the overall structure of our template can look like:

<ion-card *ngFor="let thingy of thingies" [color]="thingy.color">
  <ion-card-header>
    <ion-card-title [innerText]="thingy.title"></ion-card-title>
  </ion-card-header>
</ion-card>

Change detection and property binding are two of Angular’s most important features, and I think they are capable of cleanly delivering what you are really looking for, albeit not in the exact manner you seem to be seeking.

I would suggest forgetting about “hooking into events”. Your template describes how to convert a Thingy into markup. The ngFor directive leverages that into turning a Thingy[] into markup, so if we add, remove, or reorder thingies in the backing Thingy[] in the controller (TypeScript side of a component), Angular’s change detection takes care of reflecting those changes in the DOM.

The final piece is “restyling”. In the example above, each card has a color attribute, which is bound to a property in the backing Thingy. So, thingies[5].color = 'red', and the fifth card becomes red. No manual DOM interaction or component instantiation needed whatsoever.

Thank you for the insightful response.

If I understand you correctly then my problem might root from some place else and I am looking from the wrong angle.

I do have a thinghies[] in my controller which does get dynamically updated and I do use the *ngFor to make the thinghy cards. But it does not update the template the way I expected angular to update it(not at all).

This lead me to think it is because once the template is rendered the nodes wont change unless I reload.

The colors do update however… but the order and removal/addition of thingies does not work.

Here is what I am aiming for:

The idea is that the user will be having this page open on a tv or monitor somewhere. People in the field will be taking points. The points are bundled into sessions. Whenever an “open session” updates it’s card should move to the top. And when a session gets completed its card should pop up under “completed sessions”.

But alas this is where I am stuck.

So you are saying angular should actually be detecting my thingies[] and thus re invoke the for loop in the template without reloading the page? If so then I am maybe doing something else wrong and the manual node manipulation isn’t needed…

here is a my ngFor for the left list of cards:

<ion-list inset style="margin-top:20%">
            <ng-container *ngFor="let session of this.curSession.livesessionsDataList">
              <ion-card *ngIf="session.status=='incomplete' && session.test=='itest-leaf'"
                (click)="itemTapped($event, session)" id="{{ session.session_id }}"
                [ngClass]="{ 'hidden': session.test!='itest-leaf'}" style="background: #d2d2d2;">
                <ion-card-header
                  [ngClass]="{ 'complete': session.status=='complete','incomplete': session.status=='incomplete'}"
                  style="color:white;">
                  <h1 style="color:white;">
                    {{session.farm_id}} - Week {{ session.week_num }}
                  </h1>
                  <ion-icon name="checkbox-outline" [ngClass]="{'hideicon': session.status=='incomplete'}"></ion-icon>
                  <ion-icon name="warning" [ngClass]="{'hideicon': session.status=='complete'}"></ion-icon>
                </ion-card-header>
                <img src="../../assets/icon/ITEST_Leaf_Icon_white.png" />
                <ion-card-content>
                  <ion-card-title>
                    {{session.last_time_saved}}
                  </ion-card-title>
                  <p>

                    <ion-list>
                      <ion-item *ngFor="let info of session.session_variables">
                        <strong *ngIf="info.name != 'Client Contact Number'"> {{info.name}}: <span
                            style="color:#579057;">{{ info.value}}</span></strong>
                        <strong *ngIf="info.name == 'Client Contact Number'"> {{info.name}}: <button ion-button
                            icon-only (click)="Authenticate()">
                            <ion-icon name="eye-off"></ion-icon>
                          </button></strong>
                      </ion-item>
                    </ion-list>
                  </p>
                  <p>
                    <ion-list>
                      <ion-item>
                        <strong> Points collected: <ion-badge>{{ session.session_points.features.length}}</ion-badge>
                        </strong>
                      </ion-item>
                    </ion-list>
                  </p>

                </ion-card-content>

                <ion-grid>
                  <ion-row no-padding>
                    <ion-col col-4>
                      <button ion-button clear small color="primary" icon-start
                        (click)="addSessionPoints(session.session_points)">
                        <ion-icon name='map'></ion-icon>

                      </button>
                    </ion-col>
                    <ion-col col-4 text-center>
                      <button ion-button clear small color="primary" icon-start>
                        <ion-icon name='paper'></ion-icon>

                      </button>
                    </ion-col>
                    <ion-col col-4 text-right>
                      <button ion-button clear small color="primary" icon-start>
                        <ion-icon name='pin'></ion-icon>

                      </button>
                    </ion-col>
                  </ion-row>
                </ion-grid>

              </ion-card>
            </ng-container>
          </ion-list>

Yes. Try this:

interface Fruit {
    name: string;
    color: string;
}

export class HomePage {
    fruits: Fruit[] = [
        {name: "apple", color: "success"},
        {name: "banana", color: "warning"},
        {name: "cherry", color: "danger"},
    ];

    newName = "";
    newColor = "";

    nuke(i: number): void {
        this.fruits.splice(i, 1);
    }

    primarize(fruit: Fruit): void {
        fruit.color = "primary";
    }

    add(): void {
        this.fruits.push({name: this.newName, color: this.newColor});
    }
}
<ion-list>
    <ion-item *ngFor="let fruit of fruits; index as ix">
        <ion-label [innerText]="fruit.name" [color]="fruit.color"></ion-label>
        <ion-button (click)="nuke(ix)" slot="end">x</ion-button>
        <ion-button (click)="primarize(fruit)" slot="end">o</ion-button>
    </ion-item>
</ion-list>

<ion-list>
<ion-item>
    <ion-label>new fruit name</ion-label>
    <ion-input name="newName" [(ngModel)]="newName"></ion-input>
</ion-item>

<ion-item>
    <ion-label>new fruit color</ion-label>
    <ion-input name="newColor" [(ngModel)]="newColor"></ion-input>
</ion-item>

<ion-item button (click)="add()">
    <ion-label>add</ion-label>
</ion-item>
</ion-list>

You should see a green apple, yellow banana, and red cherry. Clicking the “o” button next to any of them should change the color of the existing fruit to the default Ionic primary Dodger blue. Clicking the “x” button should remove the fruit from the list. Entering a new fruit name and color (such as “blackberry”/“dark”) and pressing the “add” button should add a new fruit to the end of the list.

There may be some pitfalls involving deeply nested objects, but even in a worst-case scenario, you can inject a ChangeDetectorRef and manually call detectChanges on it to goose change detection on a component.

The code in the controller that does the addition/removal of thingies may be of relevance; another possibility is that it’s somehow being triggered from outside of the proper zone. Ordinarily, Angular (and Ionic) conspire to make that hard to do, but it’s not unheard of, and there are other mitigation strategies for that.

1 Like