suppose i want to insert some HTML element from the server side to the component, how can i do it
import { Component, ElementRef, ViewChild, AfterViewChecked, TemplateRef, ViewContainerRef } from '#angular/core';
#Component({
selector: 'app-root',
template: `
<div>
<h3>this is the container</h3>
<div #holder></div>
</div>
`
})
export class AppComponent implements AfterViewChecked {
#ViewChild('holder', { read: TemplateRef }) _template: TemplateRef<any>;
constructor() { }
ngAfterViewChecked() {
debugger;
this._template.createEmbeddedView('<div>this is a new "div" element</div>');
}
}
in this code i am trying to insert a div to another div with the id='holder' but i am not able to achieve it.
I got the simple way to achieve.
html
<div [innerHTML]="yourHtml"></div>
ts
public yourHtml = '<div>this is a new "div" element</div>';
Related
I have a set of components that work together. Basically I am displaying a list of labels, and a list of data for each label. Since the label pane is resizable, it becomes a sibling of the data component. I.e.- my list component looks like:
<app-list-labels></app-list-labels>
<app-list-data></app-list-data>
And list-labels and list-data look like this, respectively:
// app-list-labels:
<div class="label-header">Labels</div>
<div class="label-labels" id="labels-labels">
<!-- all of my labels looped over and displayed -->
</div>
// app-list-data:
<div class="data-header">Labels</div>
<div class="data-data" id="data-data">
<!-- all of my data rows looped over and displayed -->
</div>
Both labels-labels and data-data have overflow-y set to auto, so that they can scroll if the number of rows exceeds the container size. The number and size of rows between the two are always identical. My goal is to have both containers scroll if one container is being scrolled. So I'd need to attach a (scroll) event listener to both of those divs (#data-data and #labels-labels), and update the scroll value of the non-scrolled element. My problem is- how can I access an element from one component in a sibling component? If app-labels was embedded in app-data it would be straight forward, but being siblings, I cant see how to do it.
You could try exposing the Div's using #Output decoratos, like this:
<app-component-one (divComponent)="divOne = $event"></app-component-one>
<app-component-two (divComponent)="divTwo = $event"></app-component-two>
Sibling 1:
import { AfterViewInit, Component, ElementRef, EventEmitter, OnInit, Output, ViewChild } from '#angular/core';
#Component({
selector: 'app-component-one',
templateUrl: './component-one.component.html',
styleUrls: ['./component-one.component.css']
})
export class ComponentOneComponent implements OnInit, AfterViewInit {
#ViewChild('divComponent1') divComponent1: ElementRef;
#Output() divComponent = new EventEmitter();
constructor() {
}
ngOnInit() {
}
ngAfterViewInit(): void {
this.divComponent.emit(this.divComponent1);
}
}
Sibling 2:
import { AfterViewInit, Component, ElementRef, EventEmitter, OnInit, Output, ViewChild } from '#angular/core';
#Component({
selector: 'app-component-two',
templateUrl: './component-two.component.html',
styleUrls: ['./component-two.component.css']
})
export class ComponentTwoComponent implements OnInit, AfterViewInit {
#ViewChild('divComponent2') divComponent1: ElementRef;
#Output() divComponent = new EventEmitter();
constructor() {
}
ngOnInit() {
}
ngAfterViewInit(): void {
this.divComponent.emit(this.divComponent1);
}
}
Parent Component, the one that has the siblings in :
import { AfterViewInit, Component, ElementRef, OnInit } from '#angular/core';
#Component({
selector: 'app-component-base',
templateUrl: './component-base.component.html',
styleUrls: ['./component-base.component.css']
})
export class ComponentBaseComponent implements OnInit, AfterViewInit {
divOne: ElementRef;
divTwo: ElementRef;
constructor() {
}
ngOnInit() {
}
ngAfterViewInit(): void {
console.log('div one' , this.divOne);
console.log('div two' , this.divTwo);
}
}
I'm using a service to dynamically change the content in my header depending on the page I'm on, however when I put HTML in my component it doesn't render in the browser (see example below)
home.component.ts
import { Component, OnInit } from '#angular/core';
import { HeaderTitleService } from '../../services/headerTitle.service';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
constructor(
private headerTitleService: HeaderTitleService
) { }
ngOnInit() {
this.headerTitleService.setTitle(`
We strive to create things
<br> that are engaging, progressive
<br> & above all
<span class="highlight">
<em>innovative.</em>
</span>
`);
}
}
header.component.ts
import { Component, OnInit } from '#angular/core';
import { HeaderTitleService } from '../../../services/headerTitle.service'
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent implements OnInit {
title: any;
constructor(
private headerTitleService: HeaderTitleService
) { }
ngOnInit() {
this.headerTitleService.title.subscribe(updatedTitle => {
this.title = updatedTitle;
});
}
}
header.component.html
<h1>{{title}}</h1>
so Im trying to set the title to be a string that has html tags in it that I want to be rendered but what happens is the whole thing comes out as a string instead of how it would look like it I had put it in my home.component.html.
Is there a way I can do this??
You can set the [innerHtml] property
<h1 [innerHtml]="title"></h1>
Example
I have a my-alert-component which looks like this:
import { Component, OnInit,Input } from '#angular/core';
#Component({
selector: 'app-my-alert',
template: `
<h1 (click)="alert()">{{type}}</h1>
<ng-content></ng-content>
`
})
export class MyAlertComponent implements OnInit {
#Input() type: string = "Success";
alert(){
console.log("alert");
}
constructor() { }
ngOnInit() {
}
}
And in my app component, I am doing the following:
import { Component,ComponentRef,ComponentFactory,ViewContainerRef, ComponentFactoryResolver,ChangeDetectorRef, ViewChild, TemplateRef, ViewChildren, QueryList, AfterViewInit,ElementRef, ContentChild, AfterContentInit } from '#angular/core';
import { MyAlertComponent } from './my-alert.component';
#Component({
selector: 'app-root',
template: `
<app-my-alert>
<p #insideNgContentVar>A paragraph inside ng-content</p>
</app-my-alert>
<app-my-alert type="danger"></app-my-alert>
<app-my-alert type="success"></app-my-alert>
`
})
export class AppComponent implements AfterViewInit{
#ViewChildren(MyAlertComponent) alertComponents : QueryList<AlertComponent>;
#ContentChild('insideNgContentVar') insideNgContent:ElementRef;
ngAfterContentInit(){
console.log(this.insideNgContent.nativeElement.textContent);
}
ngAfterViewInit(){
this.alertComponents.forEach((alertComponentInstance) => console.log(alertComponentInstance));
}
}
This is pretty simple, I thought.
But the error I am getting is:
EXCEPTION: Error in :0:0 caused by: Cannot read property 'nativeElement' of undefined
What am I doing wrong?
EDIT
If in my-alert-component I do:
#Component({
selector: 'app-my-alert',
template: `
<h1 (click)="alert()">{{type}}</h1>
<ng-content></ng-content>
`
})
export class MyAlertComponent implements AfterContentInit,AfterViewInit {
#Input() type: string = "Success";
#ContentChild('insideNgContent') insideNgContentRef:ElementRef;
alert(){
console.log("alert");
}
ngAfterContentInit(){
console.log(this.insideNgContentRef.nativeElement.textContent);
}
And in my app component:
template: `
<app-my-alert>
</app-my-alert>
<app-my-alert type="danger">
<p #insideNgContent>A paragraph inside ng-content</p>
</app-my-alert>
<app-my-alert type="success"></app-my-alert>
`
After these changes also, something seems to be missing.
What is that?
I think you should be using #ViewChild here, as per this answer:
https://stackoverflow.com/a/34327754/5018962
So basically, ViewChild is going to look for components in the DOM that are defined in your component's template, but ContentChild will look for components defined as ng-content of your app-root component itself, but not ng-content of some child components. But in this case no one is using your app-root component and no one is going to inject any DOM there, so that's why you get undefined
EDIT.
It would work, if you added the following line to the app-my-alert component:
#ContentChild('insideNgContentVar') insideNgContent:ElementRef;
because that means, look at what is defined in the ng-content of app-my-alert. Hope that sheds some light on this topic
I'm new in angular2. my code is like this:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'main',
template: `
<div class="current">
</div>
`
})
export class MainComponent implements OnInit {
ngOnInit(): void {
//change the div class from current to next...
}
}
i'd like to change the div class from 'current' to 'next'.
i appropriate if you let me know what is the best way do that?
One option is to use a template reference variable.
In the example below, the reference variable #target is added to the desired element and then the decorator #ViewChild (#ViewChild('target') target) allows you to access the variable in your component.
From there, you can get a reference to the DOM element by accessing the nativeElement property on the variable.
Here is an example where the class name is updated:
import { Component, AfterViewInit, ViewChild } from '#angular/core';
#Component({
selector: 'main',
template: `
<div #target class="current">
</div>
`
})
export class MainComponent implements AfterViewInit {
#ViewChild('target') target;
constructor() { }
ngAfterViewInit(): void {
let element = this.target.nativeElement;
element.className = 'next';
}
}
However, it's worth pointing out that you can handle most DOM manipulation with the build-in DOM directives. In this case you could just use the ngClass directive to bind a variable with the class attribute:
import { Component, AfterViewInit } from '#angular/core';
#Component({
selector: 'main',
template: `
<div [ngClass]="targetClass">
</div>
`
})
export class MainComponent implements AfterViewInit {
private targetClass: string = 'current';
constructor() { }
ngAfterViewInit(): void {
this.targetClass = 'next';
}
}
I'm building a standard angular2 app(more specific a todo app). I also added #Ngrx/store.
The first time I load the page, the button is disabled, but when I enter some value in the input box, the button needs to be enabled, but it stays disabled...
app/app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: `
<h1>Hello {{name}}</h1>
<div>
<add-todo></add-todo>
</div>`,
})
export class AppComponent { name = 'Angular'; }
app/components/add-todo/add-todo.component.ts
import { Component, ViewChild, ElementRef } from '#angular/core';
#Component({
moduleId: module.id,
selector: 'add-todo',
template: `
Create new todo
<input #myInput />
<button (click)="addTodo()" [disabled]="!myInput.value">Add</button>`
})
export class AddTodoComponent {
#ViewChild('myInput') input: ElementRef;
constructor() {}
addTodo(): void {
alert(this.input.nativeElement.value);
}
}
From the documentation https://angular.io/docs/ts/latest/guide/forms.html Track the change state and validity of form controls using ngModel...
Update your code to use ngModel and it should work as expected
import { Component, ViewChild, ElementRef } from '#angular/core';
#Component({
moduleId: module.id,
selector: 'add-todo',
template: `
Create new todo
<input #myInput [(ngModel)]="inputFieldValue" />
<button (click)="addTodo()" [disabled]="!myInput.value">Add</button>`
})
export class AddTodoComponent {
#ViewChild('myInput') input: ElementRef;
public inputFieldValue:string = '';
constructor() {}
addTodo(): void {
alert(this.input.nativeElement.value);
}
}
What if you do this way:
import {Component} from '#angular/core';
#Component({
selector: 'add-todo',
template: `
Create new todo
<input #todoTitleInput [(ngModel)]="todoTitle"/>
<button (click)="addTodo(todoTitleInput.value)" [disabled]="!todoTitle">Add</button>
`,
})
export class AddTodoComponent {
addTodo(title: string): void {
alert(title);
}
}