Dynamicly add html elements through ngFor in AngularJS - html

I am new comer in Angular 5. I would like to get the html elements from .ts file and dynamically add them in html file through ngFor. I tried to do it using [innerHtml] but it is not working and return me [object HTMLSelectElement]. How can I solve this problem?
transferDataSuccess(event) {
var dropHere = document.getElementById('dropHere')
var dropInSettings = document.getElementById('dropInSettings')
for (var key in this.transferData) {
if (this.transferData[key].name == event.dragData.name) {
this.receivedData.push({
elem:this.transferData[key].element});
}
}
}
<div class="panel-heading" id="dropHere" *ngFor="let x of receivedData" [innerHTML] = "x.elem">

A better way to do this can be as below:
let's say your options are coming dynamically from the service and you want to create <option> element dynamically.
A sample snippet to describe the functionality :
<select>
<ng-container *ngFor="let option of options;">
<option [value]="option['value']">{{option['label']}}</option>
</ng-container>
</select>
If you already have the element in the component, you can access it using the ElementRef as below:
import { Component, ElementRef, AfterViewInit } from '#angular/core';
#Component({
selector: 'app-my-component',
templateUrl: './my.component.html',
styleUrls: ['./my.component.scss']
})
export class MyComponent implements AfterViewInit {
constructor(private el: ElementRef) {
this.el = el;
}
ngAfterViewInit() {
console.log('element', this.el.nativeElement);
this.el.nativeElement.getElementById('dropHere');
}
}
If it not good practice to manipulate DOM from the component class.
I hope this help.

Related

Update embedded Swagger UI on toggle button change

I want to provide three different OpenApi definitions in a webapp, so users can read the documentation of different APIs.
The plan is to have a toggle button group with three buttons at the top and the swagger ui underneath it.
My problem is, that the swagger ui won't update if I click on a button. My approach looks like this:
api-docs.component.html
<mat-card>
<mat-button-toggle-group style="width: auto; display: flex;" (change)="toggleApiDoc($event)">
<mat-button-toggle checked value="mainPlattform" style="width: 100%">Main Plattform</mat-button-toggle>
<mat-button-toggle value="adapterHttp" style="width: 100%">Adapter HTTP</mat-button-toggle>
<mat-button-toggle value="adapterMqtt" style="width: 100%">Adapter MQTT</mat-button-toggle>
</mat-button-toggle-group>
<app-swagger-ui [url]=activeApiDoc></app-swagger-ui>
</mat-card>
api-docs.component.ts
import { Component } from '#angular/core';
import { MatButtonToggleChange } from '#angular/material/button-toggle';
import { environment } from 'src/environments/environment';
#Component({
selector: 'app-api-docs',
templateUrl: './api-docs.component.html',
styleUrls: ['./api-docs.component.scss']
})
export class ApiDocsComponent {
readonly mainApiDoc = environment.main_api_doc;
readonly httpAdapterApiDoc = environment.http_adapter_doc;
readonly mqttAdapterApiDoc = environment.http_adapter_doc;
activeApiDoc = this.mainApiDoc;
constructor() {
}
toggleApiDoc(event: MatButtonToggleChange) {
switch (event.value) {
case 'mainPlattform':
this.activeApiDoc = this.mainApiDoc;
break;
case 'adapterHttp':
this.activeApiDoc = this.httpAdapterApiDoc;
break;
case 'adapterMqtt':
this.activeApiDoc = this.mqttAdapterApiDoc;
break;
default:
this.activeApiDoc = this.mainApiDoc;
break;
}
}
}
swagger-ui.component.html
<div id="swagger"></div>
swagger-ui.component.ts
import { Component, Input, OnInit } from '#angular/core';
import SwaggerUI from 'swagger-ui';
#Component({
selector: 'app-swagger-ui',
templateUrl: './swagger-ui.component.html',
styleUrls: ['./swagger-ui.component.scss']
})
export class SwaggerUiComponent implements OnInit {
#Input() url: string = "";
constructor() { }
ngOnInit(): void {
const ui = SwaggerUI({
url: this.url,
dom_id: '#swagger'
});
}
}
environment.ts
export const environment = {
main_api_doc: 'https://petstore.swagger.io/v2/swagger.json',
http_adapter_doc: 'https://raw.githubusercontent.com/hjacobs/connexion-example/master/swagger.yaml'
};
As you can see I use random yaml files to test this. The first one gets rendered. I have an complete Swagger UI embedded in my webapp, but it won't render another Swagger UI, when I click a different toggle button. It just stays the same.
As you can tell, I'm not so good with typescript and angular. So I guess it shouldn't be too hard. But I can't tell whats wrong here.
The problem seems to be the angular lifecycle. When I tried to view all docs at the same time I saw that still only one would get rendered.
I changed the lifecycle hook function, where I create the Swagger UI and now it works.
import { Component, Input, OnChanges } from '#angular/core';
import SwaggerUI from 'swagger-ui';
#Component({
selector: 'app-swagger-ui',
templateUrl: './swagger-ui.component.html',
styleUrls: ['./swagger-ui.component.scss']
})
export class SwaggerUiComponent implements OnChanges {
#Input() url: string = "";
constructor() { }
ngOnChanges() {
const ui = SwaggerUI({
url: this.url,
dom_id: '#swagger'
});
}
}

How to get check particular checkboxes by default based on some values in angular 7

I have a checkboxes and selectbox whose values are coming from loop,but here I need to get some checkboxes checked by default based on an array of object.Here checkbox and selectbox value is coming from usersg and usersr variable.But the checked and selected by default should be from variable usersg_checked and usersr_selected inside ngOnInit(). Here is the code below
home.component.html
<p *ngFor="let group of usersg"><input type="checkbox" checked="checked.id" value="{{group.id}}" />{{group.name}}</p>
<p><select><option *ngFor="let role of usersr" value="{{role.id}}">{{role.name}}</option></select></p>
home.component.html
import { Component, OnInit } from '#angular/core';
import { CommonserviceService } from './../utilities/services/commonservice.service';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
submitted = false;
usersg_checked:any;
usersr_selected:any;
constructor(private formBuilder: FormBuilder) {
}
public usersg = [{"id":1,"name":"test1"},{"id":2,"name":"test2"},{"id":3,"name":"test3"},{"id":4,"name":"test4"}];
public usersr = [{"id":1,"name":"test1"},{"id":2,"name":"test2"}];
ngOnInit() {
this.usersg_checked = [{"id":1,"name":"test1"},{"id":2,"name":"test2"}];
this.usersr_selected = [{"id":1,"name":"test1"}];
}
}
Add isChecked() method in component to check if a checkbox must be selected.
Component:
isChecked(id) {
return this.usersg_checked.some(item => item.id === id);
}
Template:
<p *ngFor="let group of usersg">
<input type="checkbox" [checked]="isChecked(group.id)" value="{{group.id}}" />{{group.name}}
</p>
For <select> elements better to use [(ngModel)].
Template:
<p><select [(ngModel)]="usersr_selected.id">
<option *ngFor="let role of usersr" value="{{role.id}}">{{role.name}}</option>
</select></p>
Component:
And change usersr_selected to an object.
ngOnInit() {
this.usersr_selected = {"id":1,"name":"test1"};
}
If usersr_selected is an array, use the first element of the array as NgModel.
ngOnInit() {
this.usersr_selected = this.usersr_selected[0];
}

Reload some directives after generated html code

I'm trying to create some html dynamically with angular framework from ngOnInit function. I want to add events thanks to directives on this generated html. The fact is that all directives are loaded before html generation and I didn't succeed to reload one of these.
I'm generating html in my components with Renderer2:
import { Component, AfterViewInit, ElementRef, ViewChild, Renderer2 } from '#angular/core';
import { AngularDraggableDirective } from 'angular2-draggable';
#Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css']
})
export class TestComponent {
#ViewChild("myDiv", {static: false}) divView: ElementRef;
private myDiv: ElementRef;
constructor(private el: ElementRef, private renderer: Renderer2) {
this.myDiv = el;
}
ngOnInit(){
let div = this.renderer.createElement('div');
let text = this.renderer.createText('Generated draggable');
this.renderer.setAttribute(div, 'ngdraggable', '');
this.renderer.appendChild(div, text);
this.renderer.appendChild(this.myDiv.nativeElement, div);
}
}
And associate html is really simple:
<div #myDiv>
</div>
<div ngDraggable>Not generated draggable</div>
The first div (generated one) isn't draggable.
This second (initial one) is draggable.
Is there any way to reload my AngularDraggableDirective to set events on my generated div?
Thanks
You should write the code in ngafterviewinit method.

Kind of recursive usage of an Component possible?

After searching for like two hours for a solution I decided to ask some pros suspecting the solution could be quite simple.
It is an Angular7 project.
I would like to have a "goal" in my goals component with a button "+". When you click that button I want to have annother goal being added to the page. So I want to click a button of the goal component to create a new goal, which is something like recursive to me.
goals.component.html:
<input type="text" value="Ich brauche einen Laptop für maximal 1000 Euro.">
<br/>
<br/>
<app-goal id="{{lastGivenId+1}}"></app-goal>
goals.component.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-goals',
templateUrl: './goals.component.html',
styleUrls: ['./goals.component.scss']
})
export class GoalsComponent implements OnInit {
lastGivenId: number = 0;
constructor() { }
ngOnInit() {
}
}
goal.component.ts and goal.component.html:
//Typescript code
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-goal',
templateUrl: './goal.component.html',
styleUrls: ['./goal.component.scss']
})
export class GoalComponent implements OnInit {
#Input() id : number;
constructor() { }
ngOnInit() {
}
onAddLowerGoal(currentGoalID:number){
// var goalElement = document.registerElement('app-goal');
// document.body.appendChild(new goalElement());
let newGoal = document.createElement("app-goal");
newGoal.setAttribute("id", "999");
let currentGoal = document.getElementById(currentGoalID.toString());
document.body.insertBefore(newGoal, currentGoal);
}
}
<html>
<div id="{{id}}" class="goal">goal{{id}}</div>
<button id="AddLowerGoal1" (click)="onAddLowerGoal(999)">+</button>
</html>
This way, it creates an app-goal element, but the div and button elements within the app-goal element is missing.
How can this problem be solved? Any help is welcome. Thanks in advance.
First glance: delete the html tags from your goal.component.html file.
Next: you can recursively add app-goal using angular. Inserting app-goal element the javascript way only adds the <app-goal></app-goal> object. It doesn't create an angular component. It doesn't bind your data.
Also if you're using Angular's #Input, you need to assign a component input with square braces. Do not use tags.
goals.component.html:
<input type="text" value="Ich brauche einen Laptop für maximal 1000 Euro.">
<br/>
<br/>
<app-goal [id]="lastGivenId+1"></app-goal>
goal.component.html:
<div id="{{id}}" class="goal">goal{{id}}</div>
<button id="AddLowerGoal1" (click)="onAddLowerGoal(999)">+</button>
<div *ngFor="let subGoal of subGoals">
<app-goal [id]="subGoal.id"></app-goal>
</div>
goal.component.ts:
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-goal',
templateUrl: './goal.component.html',
styleUrls: ['./goal.component.scss']
})
export class GoalComponent implements OnInit {
#Input() id : number;
subGoals: Array<any> = [];
constructor() { }
ngOnInit() { }
onAddLowerGoal(currentGoalID: number){
this.subGoals.push({id: currentGoalID});
}
}
You can also use a service to store your goals and subgoals to access them later.
I think what you're looking for is a Reactive Form with FormArray with dynamically added form controls.
Take a look at this for eg:
import { Component } from '#angular/core';
import { FormControl, FormGroup, FormArray, FormBuilder } from '#angular/forms';
#Component({...})
export class GoalsComponent {
goalsForm: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.goalsForm = this.fb.group({
goals: this.fb.array([])
});
}
onFormSubmit() {
console.log('Form Value: ', this.goalsForm.value);
}
get goals() {
return (<FormArray>this.goalsForm.get('goals')).controls;
}
addGoal() {
(<FormArray>this.goalsForm.get('goals')).push(this.fb.control(null));
}
}
And here's the template for this:
<h2>Goals:</h2>
<form [formGroup]="goalsForm" (submit)="onFormSubmit()">
<button type="button" (click)="addGoal()">Add Goal</button>
<hr>
<div *ngFor="let goal of goals; let i = index;" formArrayName="goals">
<div>
<label for="goal">Goal {{ i + 1 }}: </label>
<input type="text" id="goal" [formControlName]="i">
</div>
<br>
</div>
<hr>
<button>Submit Form</button>
</form>
Here's a Sample StackBlitz for your ref.

Angular2 Select 2-Way Binding not updating

so im trying to Bind the selected Item of a Dropdown to a Property with 2 way binding but the property in my typescript code always stays the same.
This is my Select Tag:
<select #select class="form-control" id="favouriteValue" ([ngModel])="selectedValue">
<option *ngFor="let value of valuesFromHomeComp" [ngValue]="value">{{value.name}}</option>
</select>
this is my component:
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.css']
})
export class RegisterComponent implements OnInit {
model: any = {};
#Input()valuesFromHomeComp: any[];
selectedValue: any;
constructor() {}
ngOnInit() {
this.selectedValue = this.valuesFromHomeComp[0];
}
}
You're using the wrong syntax, it should be [(ngModel)] instead.
As a hint: Its bananas in a box. The square brackets enclose the "banana" brackets.