0

Here is my ultimate goal:

I am trying to render input fields from a JSON file. Here is an example string:

{  
    "id": 1,
    "value": "The answer to life is: (INPUT FIELD HERE WITH ngModel). More content..."
}

(Couldn't type the input field out without Stack removing it, but the input field would be typed out of course)

Now, I do get the input field to show with innerHTML plus using a safe pipe to sanitize the HTML, but ngModel is ignored. There is no 2 way binding happening when I console log the form result out. I thought maybe I need to have the fields re-render after the view is loaded, but I'm not sure how to accomplish that. Other things like (blur) also are completely ignored.

I am REALLY hoping someone knows how to accomplish this. My JSON files will have a single value with a lot of HTML markup and multiple input fields.

My project is an ionic3 app.

  • There are some ways to dynamically compile angular templates but I believe that it's not desirable approach, because that means that your data would have parts angular template which is not correct. – Amir Arbabian Jan 27 '19 at 10:07
  • Your data should be just data, and angular template it's only representational part which helps you present your data. – Amir Arbabian Jan 27 '19 at 10:08
  • @AmirArbabian I definitely understand what you are saying, but that may not be an option for me. As I said, there are lots of input fields in these JSON files. It's basically a workbook app that the user fills in the blanks all over the place in the content. Maybe there is another approach? Maybe something like splitting input fields out? Not sure, but I have to make it work this way... – Shane Johnson Jan 28 '19 at 00:19
  • Ok then, could you please create a dummy example with this problem on stackblitz? I will take a look into that and try to figure out something – Amir Arbabian Jan 28 '19 at 06:25
  • @AmirArbabian Yes thank you. Here is a quick stackblitz example: https://stackblitz.com/edit/ionic-dhdtk4 – Shane Johnson Jan 29 '19 at 04:00

1 Answers1

0

EDITED POST

Angular components, directives, event and property bindings only work for HTML added statically to a component template.

With [innerHTML]="..." you can add HTML to the DOM, but Angular won't care what HTML it contains, except for sanitization.

The best option is to compile the HTML with a component template at runtime.

Having said that, I have created a demo application following the references mentioned at the end of this post. This will work for your requirement

https://stackblitz.com/edit/dynami-template-ionic

Code below

home.ts

import {Compiler, Component, NgModule, OnInit, ViewChild,
  ViewContainerRef} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import {FormsModule} from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html'
})
export class App implements OnInit {
  @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;

  constructor(private compiler: Compiler) {}
  section={}
  ngOnInit() {
    this.addComponent(`<p>Sed ut perspiciatis unde omnis <input type="text" [(ngModel)]="section.answer1" name="answer1"/> sit voluptatem accusantium doloremque laudantium.</p><p>Totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt <input type="text" [(ngModel)]="section.answer2" name="answer2"/>`,
      {
        section:this.section,
        increaseCounter: function () {
          this.counter++;
        }
      }
    );
  }

  submitAnswers(answers){
    console.log(answers);
  }

  private addComponent(template: string, properties: any = {}) {
    @Component({template})
    class TemplateComponent {}

    @NgModule({imports: [ FormsModule ],declarations: [TemplateComponent]})
    class TemplateModule {}

    const mod = this.compiler.compileModuleAndAllComponentsSync(TemplateModule);
    const factory = mod.componentFactories.find((comp) =>
      comp.componentType === TemplateComponent
    );
    const component = this.container.createComponent(factory);
    Object.assign(component.instance, properties);
    // If properties are changed at a later stage, the change detection
    // may need to be triggered manually:
    // component.changeDetectorRef.detectChanges();
  }
}

home.html

<ion-header>
  <ion-navbar>
    <ion-title>Home</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
<h1>Dynamic template:</h1>
<h2>Workbook</h2>
  <form (ngSubmit)="submitAnswers(section)">
  <div #container></div>
  <h3>This input below is hard coded in the view and works perfectly. Inputs from string are ignored.</h3>
    <input type="text" [(ngModel)]="section.answer3" name="answer3">
    <br />
    <p><em>** Answers are logged in console **</em></p>
    <button ion-button type="submit" block>Submit Answers</button>
  </form>
</ion-content>

Referneces:

How can I use/create dynamic template to compile dynamic Component with Angular 2.0?

https://stackoverflow.com/a/39507831/6617276

https://stackoverflow.com/a/46918940/6617276

Rathnakara S
  • 1,446
  • 11
  • 17
  • Hey sorry, but this is not what I am looking for. Your example is throwing the entire JSON string into one input field. I have multiple input fields in one string that need to render as individual input fields as well as having 2 way binding working correctly for each one. I created a stackblitz example here of what I have and what the issue is: https://stackblitz.com/edit/ionic-dhdtk4 – Shane Johnson Jan 29 '19 at 04:06
  • I have edited the post and provided a different solution. Hope that helps. – Rathnakara S Jan 29 '19 at 07:20
  • Rathnakara! You are brilliant! I seriously can't thank you enough... This straight up works perfectly. :D I checked this as the right answer but my up votes don't show yet because I'm a new user on Stackoverflow. – Shane Johnson Jan 29 '19 at 07:34
  • Hey Rathnakara! I re-asked this question for Angular 9 and 10. If you get a chance, would you mind checking it out? It would be extremely helpful! https://stackoverflow.com/questions/63162578/ngmodel-fields-in-string-will-not-render-in-dynamic-component – Shane Johnson Jul 29 '20 at 21:31