For the purposes of an application written in Angular 2, i need to include dynamics html contained in a variable, to a template. You can see the code here:
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: '{{name}}',
})
export class AppComponent { name = '<h2>Angular</h2>'; }
However, the result is not what i want :
<h2>Angular</h2>
I would like to know if there is a technique to include this variable for handle the tags as html.
Ps: i try this code :
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: ' <div innerHTML="name" ></div>',
})
export class AppComponent { name = '<h2>Angular</h2>'; }
But it's not really what i want because i don't want that a div(or another tag) encapsulate the <h2>.
If you don't want to encapsulate the h2, you juste have to write:
<h2 [innerHTML]="name"></h2>
crdly.
PS: name is a variable, if you want to test it with a string try that:
<h2 [innerHTML]="'<b>my html code</b>'"></h2>
Related
I have created a component to reuse the mat-progress-spinner from angular material. I need this in order to avoid putting for every single page the same code. Here is the code that is working:
<div id="overlayProgressSpinner">
<div class="center">
<mat-progress-spinner
style="margin:0 auto;"
mode="indeterminate"
diameter="100"
*ngIf="loading">
</mat-progress-spinner>
</div>
</div>
It is simple. Only to set "loading" as true or false.
What did I do?
I put above code inside a custom component. Now it is like so:
<app-progress-spinner></app-progress-spinner>
its HTML code is the same and its TS code is as a follows:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-progress-spinner',
templateUrl: './progress-spinner.component.html',
styleUrls: ['./progress-spinner.component.scss']
})
export class ProgressSpinnerComponent implements OnInit {
loading = false;
constructor() { }
ngOnInit() {
}
public isLoading(value: boolean) {
this.loading = value;
}
public changeSpinnerCSSClass() {
const htmlDivElement = (window.document.getElementById('overlayProgressSpinner') as HTMLDivElement);
if (this.loading) {
htmlDivElement.className = 'overlay';
} else {
htmlDivElement.className = '';
}
}
}
when the property "loading" belongs to the current component, I can show and hide the "mat-progress-spinner" component. Otherwise, when it belongs to "app-progress-spinner" it is set but it is not being displayed. The code that I am trying to make it visible is as follows:
this.progressSpinner.isLoading(false); // it is set, but it does not work.
this.progressSpinner.changeSpinnerCSSClass(); // it works
it appears that *ngIf="loading" cannot be set by using the approach the works if the logic behind belongs to the current component.
How to achieve this?
You need to create an input in your ProgressSpinnerComponent. To do that, add the #Input() decorator before the property loading:
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-progress-spinner',
templateUrl: './progress-spinner.component.html',
styleUrls: ['./progress-spinner.component.scss']
})
export class ProgressSpinnerComponent implements OnInit {
#Input() loading = false;
So anywhere you need to use the app-progress-spinner you do:
<app-progress-spinner [loading]="loading"></app-progress-spinner>
Note: The loading variable assigned to the input loading belongs to the component that contains theapp-progress-spinner.
This happens because every component have it own scope, meaning that it have no access to external world unless you create an input or output in order to receive or send data. There's also the ngModel that can be used for bi-diretional data, but not recommend in most cases.
I come from a Python background, but I started trying to learn Angular and I'm really having trouble. Working between components is confusing to me and I can't figure it out. I made a good example that I think if someone helped me with it would go along way towards understanding Angular.
I just have two components: a "header" component and an app component. In the header component, I ask for the user's name and they click a button, and then it should show "Hello {{name}}" in the next component. I cannot get it to work to say the least and it's really frustrating. The Header part seems to work okay, but it's just not communicating with the other component at all. Neither the button part or the "name" part are working so I am clearly misunderstanding something I need to do when it comes to listening from the parent component.
Here is my Header HTML:
Name: <input type="text" id="userInput" value="Joe">
<button (click)=showName()>Show More</button>
Here is my Header TS:
import { Component, OnInit, Output, EventEmitter } from '#angular/core';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
bodyDiv = false;
inputName = '';
#Output() buttonClicked = new EventEmitter();
constructor() { }
ngOnInit() {
}
showName() {
console.log('showName clicked.');
this.bodyDiv = true;
this.inputName = document.getElementById('userInput').value;
console.log(this.inputName);
console.log(this.bodyDiv);
this.buttonClicked.emit(this.bodyDiv);
this.buttonClicked.emit(this.inputName);
}
}
Here is the main Component's HTML:
<app-header (buttonClicked)='showNextComponent($event)'></app-header>
<p *ngIf="![hiddenDiv]" [inputName]="name">Hello {{ name }} </p>
Here is the main component's TS:
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
hiddenComponent = true;
title = 'show-button';
showNextComponent() {
console.log('Button clicked.');
this.hiddenComponent = false;
console.log(this.hiddenComponent);
}
}
So who can show me what I'm doing wrong and help figure out Angular a little better? :) Thank you!
replace showName function with below code :
showName() {
console.log('showName clicked.');
this.bodyDiv = true;
this.inputName = document.getElementById('userInput').value;
console.log(this.inputName);
console.log(this.bodyDiv);
this.buttonClicked.emit(this.inputName);
}
replace below code in your main component.
name:string
showNextComponent(value:string) {
this.name = value;
}
replace below code in your html :
<app-header (buttonClicked)='showNextComponent($event)'></app-header>
<p *ngIf="name">Hello {{ name }} </p>
Please let me if you have any question and I would suggest try to use ngmodel or something else instead of directly communicating with the DOM.
Here is a slightly modified and working sample: https://stackblitz.com/edit/angular-jhhctr
The event emitter in the header component emits the name (string) which is the $event in showNextComponent($event). You have to capture this in the main component and assign it to a local variable to be able to use it in the main component's template as {{name}}
[inputName]="name" is incorrect. You can pass values like that to angular components not to actual HTML DOM elements.
There are couple of ways to communicate from one component to another in angular - Using #Input()in your child component will expects an input from parent component and #Output() from your child component will emit an event from the child component
So in your case if you want to pass a value from parent to child you need to use input property or decorator on your child property - I will provide you the code but just go through proper guidance from the link provided this will make you to create better angular applications https://angular.io/guide/component-interaction
First you need to swap your components your header component should be your parent and the child component will be your main component - if you want to work in the same way just move your codes vice versa
Header html
Name: <input type="text" id="userInput" name='userInput' [(ngModel)]='inputName' value="Joe">
<button (click)=showName()>Show More</button>
<div [hidden]='bodyDiv'>
<app-header [bindName]='inputName'></app-header>
</div>
Header Component
import { Component, OnInit, Output, EventEmitter } from '#angular/core';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
bodyDiv = true;
inputName = '';
constructor() { }
ngOnInit() {
}
showName() {
bodyDiv = false;
}
}
Main Component Html
<p>Hello {{ bindName }} </p>
Main component ts
import { Component, Input } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
#Input()
bindName: string;
}
In your header component the inputName property will be binded using two way data binding where i used [(ngModel)]='inputName' so whatever you enter in the input text it will be updated in your inputName property
Now we need to do only one thing just to show your child component with any event - so when the button is clicked the div with [hidden] property will be false and it will be displayed and as we pass the inputName to the child Component it will be updated
And finally the child component will be displayed and the input written in the text will be updated in the child component - when the child component html displays the bindName will be updated and there will be result you expected
That's all I think this should work well - Try this and let me know - Thanks Happy coding !!
Don't forget to look into the link above where you can see many types of component interactions
I have HTML code on Component variable like below :
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
template: `Hi <div [innerHTML]="name"></div>`,
styleUrls: ['./app.component.css'],
styles: [`
.highlight {
background-color: yellow;
}
`],
})
export class AppComponent {
name :string ="dude ! <input type='text'/>";
}
It shows the output like "Hi dude !" But no text box there.How can I display the text box bind using component variable ?
This code is not secure. So, rendering input elements is disallowed by default. You need to use DomSanitizer to allow it:
constructor(sanitizer: DomSanitizer) {
this.name = sanitizer.bypassSecurityTrustHtml( this.name);
}
See the plunker sample that illustrates this.
I am trying to implement a basic shopping list, but my ngFor in Angular is not working.
import { Component, View } from 'angular2/angular2';
#Component({
selector: 'my-app'
})
#View({
template: '<h1>{{title}}</h1><ul><li *ngFor="let i of items"><span>{{i}}</span></li></ul>'
})
export default class MyAppComponent {
title = 'ShoppinList';
items = ['Milk','Ham','Eggs'];
}
The only thing that appears is "loading..." and I am getting more than 10 cryptic errors.
Without trying it first I noticed an error in the import statement at the top. Should be:
import { Component } from '#angular/core'
#View() was removed almost a year ago. If you see examples that use it, just move the content to the #Component() decorator while directives and pipes were moved from #Component() to #NgModule()s declaration.
You need to add CommonModule to #NgModule({ imports: [CommonModule], ...}) export class SomeModule{} in every module where you want to use ngFor (or other directives shippled with Angular - BrowserModule already includes CommonModule).
its good way to use ngIf and use your template inside your component properties.
import { Component, View } from 'angular2/angular2';
#Component({
selector: 'my-app',
template : '<div>
<h1>{{title}}</h1>
<ul *ngIf="items">
<li *ngFor="let i of items"><span>{{i}}</span></li>
</ul>
</div>'
})
export default class MyAppComponent {
title : string = 'ShoppinList';
items : Array<string> = ['Milk','Ham','Eggs'];
}
You don't have to use #View here.
#Component({
selector: 'my-app',
template: `
<div>
{{title}}
<ul><li *ngFor="let i of items"><span>{{i}}</span></li></ul>
</div>
`,
})
export class App {
title = 'ShoppinList';
items = ['Milk','Ham','Eggs'];
}
Working plunker
Is it possible to use Angular 2 without using a template or an #View?
I'm looking for a similar way like you did the following in example:
Angular 1
index.html
<div ng-controller="appcontroller">
<div ng-class="{active: isActive()}">
.....
</div>
</div>
app.js
angular.module('app', []).controller('appcontroller', function(){
$scope.isActive = function(){
return true;
}
});
I was guessing it would look something like this, if it was possible:
Angular 2
index.html
<app>
<div [ngclass]="{active: isActive()}">
.....
</div>
</app>
app.ts
import {Component} from 'angular2/core';
#Component({
selector: 'app'
})
export class AppComponent {
isActive(){
return true;
}
}
But unfortunately I'm getting the error:
... must have either 'template', 'templateUrl', or '#View' set.
I don't really like putting html in Javascript, so I hope there some sort of workaround or way to do this.
In fact, you should implement the AppComponent like this:
import {Component} from 'angular2/core';
#Component({
selector: 'app'
template: `
<div [ngClass]="{active: isActive()}">
.....
</div>
`
})
export class AppComponent {
isActive(){
return true;
}
}
or using the templateUrl property:
import {Component} from 'angular2/core';
#Component({
selector: 'app'
templateUrl: 'component.html'
})
export class AppComponent {
isActive(){
return true;
}
}
and use the component like this:
<app></app>
If you put some HTML inside the app tag, this means that you want to provide some content to the component that can be included in the component template using ng-content. Here is a sample: Angular 2 Template Component.
Hope it helps you,
Thierry