Angular2 add HTML to dynamic elements - javascript

I have this code:
import { Component, ElementRef, Renderer2 } from '#angular/core';
#Component({
selector: 'my-app',
template: '<button (click)="runR()">Run</button>
<div class="testme">
<div class="somediv">
<div class="dynamically_created_div unique_identifier"></div>
<div class="dynamically_created_div unique_identifier"></div>
<div class="dynamically_created_div unique_identifier"></div>
</div>
</div>',
})
export class AppComponent{
hostEl: any;
constructor(
private el:ElementRef,
private renderer:Renderer2,
) {
this.hostEl = el.nativeElement;
}
runR(){
let change_this;
change_this= this.renderer.createElement('span');
this.renderer.addClass(change_this, 'change_this');
this.renderer.appendChild(this.hostEl, change_this);
}
}
Is there any way in Angular2 to add HTML to the .dynamically_created_div?
Because the above only adds to the end of the HTML of the component.
I also tried with:
import { Component, ElementRef, ViewChild, Renderer, AfterViewInit } from '#angular/core';
#Component({
selector: 'my-app',
template: `<button (click)="runR()">Run</button>
<div class="testme">
<div class="somediv">
<div class="dynamically_created_div">
</div>
</div>
</div>
`,
})
export class AppComponent {
constructor(private renderer:Renderer) {}
runR() {
#ViewChild('dynamically_created_div') d1:ElementRef;
this.renderer.invokeElementMethod(this.d1.nativeElement, 'insertAdjacentHTML', ['beforeend', '<div class="new_div">new_div</div>'] );
}
}
But it's not working because the #ViewChild directive must be outside the function and I can't have control over it anymore
I also tried like this:
<div class="dynamically_created_div" [innerHtml]="newHTML"></div>
this.newHTML = '<div class="new_div">new_div</div>';
Thing I cannot do because my content is dynamic and uses unique IDs and I cannot use [innerHtml] dynamically ( it only works for what I put in themplate for the first time, then anything else that changes can't use innerHtml anymore.
I checked Angular2: Insert a dynamic component as child of a container in the DOM but there is the same problem, the placeholders aren't dynamic
UPDATE:
My code is a little bit more complex:
TS:
import { AfterContentInit, Component, OnInit, OnDestroy, ViewEncapsulation } from '#angular/core';
import { NgForm, FormsModule, ReactiveFormsModule, FormGroup, FormControl, FormBuilder, Validators } from '#angular/forms';
import { SFService } from '../services/sf.service';
import { Injectable, Pipe, PipeTransform } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
providers: [ SFService ],
})
export class AppComponent implements OnInit {
constructor(
private sfservice: SFService,
) {}
ngOnInit(){
this.sfservice.getMembers().subscribe(members => {
this.members = members.members;
});
}
members: Member[];
member_selector: Member[];
member_each: Member;
member_selector_each: Member[];
cases: Case;
runR(){
this.members.forEach(member_each => {
this.member_selector.forEach(member_selector_each => {
if(member_each.Id === member_selector_each.Id){
console.log(member_selector_each.Id);
this.sfservice.getCaseHistory(member_selector_each.Id, "2017-04-25T00:00:00", "2017-04-28T23:59:59").subscribe(cases => {
this.member_each['cases'] = cases;
console.log(this.member_each);
});
}
})
})
}
}
HTML:
<form #myForm="ngForm" novalidate>
<select name="member_selector_name" [(ngModel)]="member_selector" multiple ng-model="selectedValues" style="height:200px;">
<option *ngFor="let member of members" [ngValue]="member">{{member.Name}}</option>
</select>
<button (click)="runR()">Run</button>
</form>
<div id="results">
<div *ngFor="let mem of members" class="member-card-{{mem.Id}}">
<div class="card-container">
<div *ngFor="let case of mem.Cases" class="case-card" id="{{case.Id}}">{{case.Number}}
</div>
</div>
</div>
</div>
I was trying to use only ngFor but now I get
Cannot set property 'cases' of undefined

What's the problem with this approach?
export class AppComponent{
#ViewChild('d1') d1:ElementRef;
#ViewChild('d2') d2:ElementRef;
#ViewChild('d3') d3:ElementRef;
constructor(private renderer:Renderer2) { }
runR(){
let change_this;
change_this= this.renderer.createElement('span');
this.renderer.addClass(change_this, 'change_this');
this.renderer.appendChild(this.d1, change_this);
}
}
Template:
<div class="dynamically_created_div unique_identifier" #d1></div>
<div class="dynamically_created_div unique_identifier" #d2></div>
<div class="dynamically_created_div unique_identifier" #d3></div>

you can use ngfor and create you elements inside it and using index you can create different ids and names.
I do something like this i dont know if you want to do the same but here's my code to create some input's dynamically and add or access their values
<div *ngFor="let comp of templateVals | async;let i=index">
<md-input-container class="example-90" *ngIf="comp.type=='code'">
<textarea rows="4" mdInput name="desc{{i}}" [(ngModel)]="comp.data" placeholder="Description"></textarea>
</md-input-container>
<md-input-container class="example-90" *ngIf="comp.type=='text'">
<textarea rows="4" mdInput name="text{{i}}" [(ngModel)]="comp.data" placeholder="Text"></textarea>
</md-input-container>
<md-input-container class="example-90" *ngIf="comp.type=='title'">
<input mdInput name="title{{i}}" [(ngModel)]="comp.data" placeholder="Title">
</md-input-container>
<span class="example-90" *ngIf="comp.type=='upload'">
<input-file *ngIf="!comp.data" [acceptId]="comp.id" (onFileSelect)="addedFileInfo($event)"></input-file>
<span *ngIf="comp.data">{{comp.data}}</span>
</span>
<span class="example-10">
<button md-mini-fab (click)="removeThis(comp)"><md-icon>remove circle</md-icon></button>
</span>
</div>

Related

Need dynamically created buttons to work independently in Angular

In Angular i have dynamically created a group of buttons that all have the same action (to show text when clicked) everything works fine yet when I click one button they all perform the action. I need them to work independently of each other. I have dynamically made a different id for each button and was wondering if there was a way to us the id to have them work independently.
Button HTML and TS files:
<button id="{{index}}" class="btn btn-secondary" style="float: right;" (click)="onClick()">Discription</button>
import { Component, EventEmitter, OnInit, Output, Input } from '#angular/core';
#Component({
selector: 'app-discription-btn',
templateUrl: './discription-btn.component.html',
styleUrls: ['./discription-btn.component.css']
})
export class DiscriptionBtnComponent implements OnInit {
#Output() btnClick = new EventEmitter();
#Input() index!: number
constructor() { }
ngOnInit(): void { }
onClick() {
this.btnClick.emit();
}
}
Button Parent HTML and TS files:
<div class="card mb-4 h-100">
<img class="card-img-top-other" src= "{{ post.link }}" />
<div class="card-body">
<div class="small text-muted"> {{ post.created }} <app-discription-btn (btnClick) = "toggleDiscription()" [index] = index></app-discription-btn> </div>
<h2 class="card-title h4"> {{ post.title }} </h2>
<div *ngIf="showDiscription">
<p class="card-text"> {{ post.summary }} </p>
<a class="btn btn-primary" href="#!">Read More -></a>
</div>
</div>
</div>
import { Component, OnInit, Input } from '#angular/core';
import { Subscription } from 'rxjs';
import { BlogPost } from 'src/app/Post';
import { DiscriptionUiService } from 'src/app/services/discription-ui.service';
#Component({
selector: 'app-other-posts',
templateUrl: './other-posts.component.html',
styleUrls: ['./other-posts.component.css']
})
export class OtherPostsComponent implements OnInit {
#Input() post! : BlogPost
#Input() index! : number;
showDiscription : boolean = false;
subscription : Subscription;
constructor(private discritpionService: DiscriptionUiService) {
this.subscription = this.discritpionService.onToggle().subscribe((value) => (this.showDiscription = value));
}
ngOnInit(): void {
}
toggleDiscription(){
this.discritpionService.toggleDiscription();
}
}
Main HTML and TS files:
<div class="container">
<div class="row">
<div class="col-lg-8"><app-featured-post *ngFor="let post of posts; let i = index;" [post] = "post" [index] = "i"></app-featured-post></div>
<div class="col-lg-4"><app-side-widgets></app-side-widgets></div>
<app-other-posts *ngFor="let post of posts | myFilterPipe:filterargs; let i = index;" [post] = "post" [index] = "i" class="col-lg-4" style="padding-top: 10px;" ></app-other-posts>
<nav aria-label="Pagination">
<hr class="my-0" />
<ul class="pagination justify-content-center my-4">
<li class="page-item disabled"><a class="page-link" href="#" tabindex="-1" aria-disabled="true">Newer</a></li>
<li class="page-item active" aria-current="page"><a class="page-link" href="#!">1</a></li>
<li class="page-item"><a class="page-link" href="#!">Older</a></li>
</ul>
</nav>
</div>
</div>
import { Component, OnInit } from '#angular/core';
import { BlogPostService } from 'src/app/services/blog-post.service';
import { BlogPost } from '../../Post';
#Component({
selector: 'app-posts',
templateUrl: './posts.component.html',
styleUrls: ['./posts.component.css']
})
export class PostsComponent implements OnInit {
filterargs = {title: 'The Beginning'}
posts: BlogPost[] = [];
constructor(private postService: BlogPostService ) { }
ngOnInit(): void {
this.postService.getPosts().subscribe((posts) => (this.posts = posts));
}
}
Any ideas would be a great help. Thank you ahead of time!

Why Parent does not listen to child on Angular?

I cannot make this eventemitter work. Can you please help? I am a beginner and it should be quite simple code for you.
I have a parent component, reading two different emitters from two different children:
<app-van [vans]="vans"></app-van>
<app-modal *ngIf="modalOpen" (closed)="onClick()" (openModal)="onClickTwo($event)"></app-modal>
import { Component, OnInit } from '#angular/core';
import { Van } from '../../interface';
#Component({
selector: 'app-fleet-home',
templateUrl: './fleet-home.component.html',
styleUrls: ['./fleet-home.component.css']
})
export class FleetHomeComponent implements OnInit {
modalOpen = true;
vans: Van [] = [
{ name: 'Ubeddu', description: 'Mercedes Sprinter', plate: 'NH55GKA' },
{ name: 'Abbestia', description: 'Ford Transit', plate: 'DK66HHR' },
{ name: 'Eumulu', description: 'Citroen Berlingo', plate: 'DR55MKL' }
];
constructor( ) { }
ngOnInit() {
}
onClick() {
this.modalOpen = !this.modalOpen;
console.log('modalOpen changed');
}
onClickTwo(event) {
this.modalOpen = event;
console.log('modalOpen changed');
}
}
the parent listened to this child:
<div (click)="onCloseClick()" class="ui dimmer visible active">
<div (click)="$event.stopPropagation()" class="ui modal visible active">
<div class="asuca">
<form class="ui form" >
<h4 class="ui dividing huge header">Van</h4>
<div class="required field">
<label class="ui header">Van Name</label>
<input type="text" placeholder="Van NickName">
</div>
<div class="field">
<label class="ui header">Description</label>
<input type="text"placeholder="Description">
</div>
<div class="field">
<label class="ui header">Plate</label>
<input type="text"placeholder="License Plate">
</div>
<button (click)="onCloseClick()" class="ui button" type="submit">Submit</button>
</form>
</div>
</div>
</div>
import { Component, OnInit, ElementRef, Output, EventEmitter } from '#angular/core';
#Component({
selector: 'app-modal',
templateUrl: './modal.component.html',
styleUrls: ['./modal.component.css']
})
export class ModalComponent implements OnInit {
#Output() closed = new EventEmitter();
constructor(private el: ElementRef) { }
ngOnInit() {
document.body.appendChild(this.el.nativeElement);
}
// tslint:disable-next-line: use-lifecycle-interface
ngOnDestroy() {
this.el.nativeElement.remove();
}
onCloseClick() {
this.closed.emit();
}
}
and doesnt listen to the second child:
<div class="ui fluid four black cards">
<div *ngFor="let van of vans" class="card">
<div class="content">
<div class="header">
{{ van.name }}
</div>
<div class="meta">
{{ van.description }}
</div>
<div class="description">
{{ van.plate }}
</div>
</div>
<div class="extra content">
<div class="ui two buttons">
<div (click)="onEditClick(true)" class="ui basic black button">Edit</div>
<div class="ui basic red button">Delete</div>
</div>
</div>
</div>
</div>
import { Component, OnInit, Input, Output, EventEmitter } from '#angular/core';
#Component({
selector: 'app-van',
templateUrl: './van.component.html',
styleUrls: ['./van.component.css']
})
export class VanComponent implements OnInit {
#Input() vans = [];
#Output() openModal = new EventEmitter<boolean>();
constructor() { }
ngOnInit() {
}
onEditClick(event: boolean) {
this.openModal.emit(event);
}
}
the whole thing is to hide the modal clicking around the screen and show it again clicking a button.
On the console.log, the object emitter by the first child has got an observer, where the object emitter by the second child as none; no idea what means though.
thanks in advance for the help. I can provide the whole folder if needed. I am just trying to learn :)
Seems like you have missed binding the output event in parent template. Please correct like below:
<app-van [vans]="vans" (openModal)="onEditClick($event)"></app-van>

How to make ngModel available between components

I am seriously getting mad. I have tried everything. FormsModules,ReactiveForms,FORMDIRECTIVES,Input,Output i've been searching everywhere on how to make ngModel available between components. I am trying to show in an h1 tag the value which is being typed/deleted in the input tag using string interpolation, however it isn't working, these are the files:
app.component.html:
<div class="container text-center" id="headerCont">
<span style="color: #6E2435" class="header">note</span><span style="color: #6BBFDE" class="header">it</span>
</div>
<div class="container">
<app-input></app-input>
<app-notes></app-notes>
</div>
app.component.ts
import { Component, OnInit, Input, Output } from '#angular/core';
import { NgModule } from '#angular/core';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
}
notes.component.html
<div class="col-xs-2">
<h1>{{ TitleInput }}</h1>
<p>{{ noteInput }}</p>
</div>
input.component.html
<div class="container" id="noteCreate">
<form id="titleInputForm">
<input type="text" [(ngModel)]="TitleInput" name="TitleInput">
</form>
<form>
<textarea name="name" rows="8" cols="80">
</textarea>
</form>
</div>
If you can figure it out I would be so grateful.
You actually searched it but did not use it, the solution to your problem is #Input and #Output. I believe you did not use this effectively.
Since the other components is governed by a component called AppComponent you just simply need to put those data in it:
import { Component } from '#angular/core';
// The other imports are not necessary
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent
{
// declare those stuffs
title: string;
note: string;
constructor()
{
this.title = "";
this.note = "";
}
}
then in your AppComponent template
<div class="container">
<app-input [title]="title"
[note]="note"
// you should return $event always or else it will return undefined
(onTitleChange)="title = $event"
(onModelChange)="note = $event">
</app-input>
<app-notes [title]="title"
[note]="note">
</app-notes>
</div>
where [ ] are #Input and ( ) are #Output from the component
so your InputComponent will have:
// add these to your existing InputComponent
import { Input, Output, EventEmitter } from "#angular/core";
export class InputComponent
{
#Input("title") title: string;
#Input("note") note: string;
#Output() onTitleChange = new EventEmitter();
#Output() onNoteChange = new EventEmitter();
}
where #Input is the data your recieve and #Ouput is the data you send.
and your InputComponent template would be:
<div class="container" id="noteCreate">
<form id="titleInputForm">
<input type="text"
name="title"
[(ngModel)]="title"
(ngModelChange)="onTitleChange.emit(title)">
<textarea name="note"
rows="8"
cols="80"
[(ngModel)]="note"
(ngModelChange)="onNoteChange.emit(note)">
</textarea>
</form>
</div>
where setting [(ngModel)] with your #Input and (ngModelChange) to trigger #Output when modal has changed.
In this example you can actually set default values from AppComponent to InputComponent.
If you understand #Input correctly in these example I do not need to put what would be inside NotesComponent
hope that helps.

consoling angular form output failed

This is my html view in angular:
<div class="container">
<div class="row">
<div class="col-md-3">
</div>
<div class="col-md-6">
<div class="jumbotron">
<h2>Complete your Profile</h2>
<h5 style="color:royalblue;">Add your updated Resume to get notified by Recruiters</h5>
<form #ResumeForm="ngForm"
(ngSubmit)="submitResume(ResumeForm.value)">
<div class="form-group">
<label>Resume</label>
<input type="file" name="resume" id="resume" class="form-control">
</div>
<input value="submit" type="submit">
</form>
</div>
</div>
</div>
</div>
My .ts file is here
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-candidate-reg-complete',
templateUrl: './candidate-reg-complete.component.html',
styleUrls: ['./candidate-reg-complete.component.css']
})
export class CandidateRegCompleteComponent implements OnInit {
constructor() { }
ngOnInit() {
}
submitResume=function(user){
console.log(user);
}
}
But the console screen shows only object{}. No form content is shown.
I am trying to take file input.
Can anyone help me?
Thanks in advance.
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-candidate-reg-complete',
templateUrl: './candidate-reg-complete.component.html',
styleUrls: ['./candidate-reg-complete.component.css']
})
export class CandidateRegCompleteComponent implements OnInit {
constructor() { }
ngOnInit() {
}
submitResume(user){
console.log(user);
}
}
Put your submitResume(value) function outside ngOnInit. It will be called from the html.
submitResume(value){
console.log(value);
}

Angular 2 scope of Dynamic component

I have been learning about Angular 2 and their new features and i am having trouble when adding a component dynamically.
so i have a dashboard.component.ts
import { Component, OnInit, ViewContainerRef, ComponentFactoryResolver, ViewChild } from '#angular/core';
import { InputTextComponent } from '../input-text/input-text.component'
#Component({
templateUrl: 'dashboard.component.html',
providers: [InputTextComponent],
styleUrls: ['dashboard.component.css']
})
export class DashboardComponent implements OnInit {
constructor( private componentFactoryResolver: ComponentFactoryResolver,
private viewContainerRef: ViewContainerRef,
private inputTextComponent: InputTextComponent
) { }
#ViewChild(InputTextComponent) textComponent: InputTextComponent
attachIntup(){
const factory = this.componentFactoryResolver.resolveComponentFactory(InputTextComponent);
const ref = this.viewContainerRef.createComponent(factory);
ref.changeDetectorRef.detectChanges();
}
alertPop(){
alert(this.textComponent.passingStr);
}
ngOnInit() {
}
}
and it has an html code dashboard.component.html
<button (click)="attachIntup()">Inject Input</button>
<button (click)="alertPop()">Pop String</button>
and my inputTextComponent is as follows
import { Component, AfterViewInit } from '#angular/core';
#Component({
selector: 'app-input-text',
templateUrl: './input-text.component.html',
styleUrls: ['./input-text.component.css']
})
export class InputTextComponent implements AfterViewInit {
public inputType = '';
public passingStr = '';
constructor() { }
popupAlert(){
alert(this.passingStr);
}
ngAfterViewInit() {
this.inputType = 'text'
}
}
with an html:
<div [ngSwitch]="inputType" class="container">
<div class="row" *ngSwitchCase="'textarea'">
<div class="col-md-4">
<label>I am a textarea: </label>
</div>
<div class="col-md-8">
<textarea style="resize: both" class="form-control"></textarea>
</div>
</div>
<div class="row" *ngSwitchCase="'text'">
<div class="col-md-4">
<button (click)="popupAlert()"></button>
<label>I am an input text: </label>
</div>
<div class="col-md-8">
<input type="text" class="form-control" placeholder="Testing text" [(ngModel)]="passingStr">
</div>
</div>
</div>
What i am trying to do is obtain the scope from the inputTextComponent inside the dashboard component. I have read that the ViewChild allows you to access the variables inside a component, but in my case i am not able to do so.
Does anyone know how i can access the variables inside the InputTextComponent after injection; In order to display in the alert from the dashboard whatever information is been passed through the input.
Thanks in advance

Categories

Resources