Working through an Angular2 tutorial. The challenge was to create a 'tweet' component that used a 'tweet' service to retrieve its posts.
The service is to return an array of hard-coded tweets. This is just for the sake of exercise; obviously not efficiency. However, the service can only return an array of strings so I am not sure how to return an array of HTML that can then be rendered as HTML rather than text in the view. I've read up and seen that there are of course better ways of accomplishing this than through a service, perhaps through a directive. However this is what the challenge is.
This is what I've come up with so far. The view renders the array of tweets from the service as text. Everything else works fine as I tested it with the service returning an array of strings which rendered as planned.
app.component.ts:
import {Component} from 'angular2/core';
import {TweetComponent} from './tweet.component'
#Component({
selector: 'my-app',
template: `
<tweet></tweet>
`,
directives: [TweetComponent]
})
export class AppComponent {
}
tweet.component.ts:
import {Component} from 'angular2/core'
import {TweetService} from './tweet.service'
#Component ({
selector: 'tweet',
template: `
<li *ngFor="#tweet of tweets">
{{tweet}}
</li>
`,
providers: [TweetService]
})
export class TweetComponent {
tweets;
constructor(tweetService: TweetService){
this.tweets = tweetService.getTweets();
}
}
tweet.service.ts:
export class TweetService {
getTweets() {
return [`
<div class="media">
<div class="media-left">
<a href="#">
<img class="media-object" src="http://lorempixel.com/100/100/people/?1" alt="...">
</a>
</div>
<div class="media-body">
<h4 class="media-heading">Tweet 1<br>Media Title 1?<br><like></like></h4>
</div>
</div>
`,
`
<div class="media">
<div class="media-left">
<a href="#">
<img class="media-object" src="http://lorempixel.com/100/100/people/?2" alt="...">
</a>
</div>
<div class="media-body">
<h4 class="media-heading">Tweet 2<br>Media Title 2<br><like></like></h4>
</div>
</div>`
];
}
}
In tweet.component.ts use innerHTML:
import {Component} from 'angular2/core'
import {TweetService} from './tweet.service'
#Component ({
selector: 'tweet',
template: `
<li *ngFor="#tweet of tweets">
<span [innerHTML]="tweet"></span>
</li>
`,
providers: [TweetService]
})
by the way, if you are using more recent angular2 version you should change
<li *ngFor="#tweet of tweets">
to
<li *ngFor="let tweet of tweets">
Related
The data I work with (bosses[]) has a boss object with contains the key-value email which is an string. I want to create the anchor with that string in the HTML. Also note that there's a loop in HTML that allows to access to each boss in bosses[].
So how can I access to create an anchor with boss.email which it only exists in the HTML loop?
I've tried <a [href]=`"mailto: + boss.email"></a> but doesn't work.
the html:
<div class="boss" *ngFor="let boss of bosses" >
<div class="boss-text">
<div class="boss-text-name">{{boss.name}} </div>
<div>{{boss.email}}</div>
<a [href]="mailto: + boss.email"></a>
</div>
</div>
The component:
import { Component, Input, OnInit } from '#angular/core';
import { boss} from 'interfaces'
#Component({
templateUrl: 'boss-cell.component.html',
selector: 'boss-cell',
})
export class BossCellComponent implements OnInit {
constructor() {}
bosses: any[] = [{
email: 'kennedy#gmail.com',
name: 'kennedy',
}]
}
You're close! I think this is what you're looking for:
<div class="boss" *ngFor="let boss of bosses" >
<div class="boss-text">
<div class="boss-text-name">{{boss.name}} </div>
<a [href]="'mailto:' + boss.email">{{ boss.email }}</a>
</div>
</div>
You can use interpolation as Suraj already mentionned in the comments, or bind to a function creating the string. Depending on weather you are going to link other elements to the mail, you should pick the cleanest option for you.
Template
<div class="boss" *ngFor="let boss of bosses; let i = index">
<div class="boss-text">
<div class="boss-text-name">{{ boss.name }}</div>
<a [href]="getMail(i)">{{ boss.email }}</a>
</div>
</div>
Script
bosses: any[] = [{
email: 'kennedy#gmail.com',
name: 'kennedy',
}]
getMail(index: number) {
return 'mailto:' + this.bosses[index].email
}
You need to update this line
<a [href]="'mailto:' + boss.email">{{ boss.email }}</a>
I'm working with Angular 8 and trying to create a reusable Web Component using the createCustomElement() command in the Angular Elements package "#angular/elements"
So the component itself is very simple. It just contains a some wrapper HTML code and anIMG tag with a src to a logo image. Here is my code.
HTML
<a [routerLink]="homeURL" class="logo-branding no-link flex-grow-2">
<img class="logo align-middle" [src]="headerImgPath">
<span class="branding text-nowrap">{{ this.headerBranding }}</span>
</a>
TS
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'header-logo',
templateUrl: './header-logo.component.html',
styleUrls: ['./header-logo.component.scss'],
})
export class HeaderLogoComponent implements OnInit {
#Input() logo: string;
#Input() branding: string;
#Input() url: string;
public headerImgPath = 'elements-assets/images/my-logo.svg';
public headerBranding = 'Platform Name';
public homeURL: string;
constructor() {}
ngOnInit() {
if (this.branding) {
this.headerBranding = this.branding;
}
if (this.logo) {
this.headerImgPath = this.logo;
}
if (this.url) {
this.homeURL = this.url;
}
}
}
So then I compile the code into a web component inside of the AppModule, like so.
const el = createCustomElement(LogoComponent, { injector: this.injector });
customElements.define('page-logo', el);
And finally pull the exported JS library into a new custom HTML page.
HTML
<div class="container" style="position: relative; height:200px; top: 100px;">
<page-logo></page-logo>
</div>
But what I see is only part of the HTML.
Render in the browser as
<div class="container" style="position: relative; height:200px; top: 100px; >
<my-logo _ngcontent-trw-c0="">
<a class="logo-branding no-link flex-grow-2"></a>
</page-logo>
</div>
The img tag is never rendered at all.
Try this
<a [routerLink]="homeURL" class="logo-branding no-link flex-grow-2">
<img class="logo align-middle" [src]="elements-assets/images/my-logo.svg">
<span class="branding text-nowrap">{{ this.headerBranding }}</span>
</a>
Or this
<a [routerLink]="homeURL" class="logo-branding no-link flex-grow-2">
<img class="logo align-middle" [src]="this.logo">
<span class="branding text-nowrap">{{ this.headerBranding }}</span>
</a>
The HTML is written where I am getting the file name but i want to get rid of the file extension and also store the files in an array and access them in the UI.
<div class="myReadingListContainer">
<div class="readingList">
My Reading List
</div>
<div class="myReadingList">
<div class="uploadWrap">
<input type="file" #file (change)="onChange(file.files)" class="fileUploadInput" />
<div class="innerText">
<img src="assets/img/my_reading_list/Add.svg" class="addIcon">
<h6 class="addFile">Add Files</h6>
</div>
</div>
<div *ngFor="let file of fileList">
<div class="selectedFile">
<div class="documentName">
{{file.name}}
</div>
<span *ngIf="file.type === 'application/pdf'">
<img src="assets/img/my_reading_list/PDF.svg" class="fileTypeImage">
</span>
<span *ngIf="file.type === 'application/vnd.ms-excel'">
<img src="assets/img/my_reading_list/Excel.svg" class="fileTypeImage">
</span>
<div class="readingStatus">
20/35 Pages
</div>
<div class="progress">
<div class="progressBar"></div>
</div>
</div>
</div>
</div>
</div>
The typescript file is written like this. Since I am new to Angular 6 any help is really appreciated, thanks in advance
import { Component, OnInit } from "#angular/core";
#Component({
selector: "app-myReadingList",
templateUrl: "./myReadingList.component.html",
styleUrls: \["./myReadingList.component.scss"\]
})
export class MyReadingListComponent implements OnInit {
//localUrl: String;
fileList: any = \[\];
files: any;
constructor() {}
onChange(files: FileList) {
console.log(files);
this.files = files;
this.fileList.push(files\[0\]);
this.fileList.forEach(file => {
let temp = file.name.split(".");
file.name = temp.splice(0, temp.length - 1).join(".");
});
console.log(this.fileList);
}
ngOnInit() {}
}
Here is the sample code to remove file extension while displaying from each fileList.name
<div class="documentName">
{{file.name.split('.').slice(0, -1).join('.')}}
</div>
Demo for the same
update1:
hey thanks for your reply...but when I type h it shows set of values....and when I select the value it should show in the text box with cross symbol....like in stackoverflow we edit tags
I have a search engine code in angular2.
When I select the search results I need to display the values in the text box With cross button next to it.
Right now I am getting the results.
But when I slect the values, how to display in the text box with cross symbol.
https://stackblitz.com/edit/angular6-ya3e4u?file=app/app.component.html
service
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/switchMap';
#Injectable()
export class SearchService {
baseUrl: string = 'https://api.cdnjs.com/libraries';
queryUrl: string = '?search=';
constructor(private http: Http) { }
search(terms: Observable<string>) {
return terms.debounceTime(400)
.distinctUntilChanged()
.switchMap(term => this.searchEntries(term));
}
searchEntries(term) {
return this.http
.get(this.baseUrl + this.queryUrl + term)
.map(res => res.json());
}
}
html
<input
(keyup)="searchTerm$.next($event.target.value)">
<ul *ngIf="results">
<li *ngFor="let result of results | slice:0:9">
<a href="{{ result.latest }}" target="_blank">
{{ result.name }}
</a>
</li>
</ul>
<div class="close" (click)="delete(currentItem)">X</div>
Try the following code it will help you. Demo StackBlitz
<input
(keyup)="searchTerm$.next($event.target.value)">
<ul *ngIf="results">
<li *ngFor="let result of results | slice:0:9">
<a href="{{ result.latest }}" target="_blank">
{{ result.name }}
</a>
<div class="close rigth" (click)="delete(result)">X</div>
</li>
</ul>
I have an angular component template like this.
<my-app>
<nav id="nav-bar">
<ul>
<li id="item-1"></li>
<li>
<div id="item-2"></div>
</li>
<li id="item-3"></li>
<div id="middle-div">
</div>
<div id="side-div">
</div>
</nav>
</my-app>
Now here I want to take the div with id, 'item-2' and append it to nav-bar so that it appears below the div with id "side-div".
I can easily do this with javascript's appendChild function like this.
var item = document.getElementById("item-2");
var nav = document.getElementById("nav-bar");
//change position of searchform in DOM
nav.appendChild(item);
However, I want to be able to do this in component's typescript file. Is ElementRef an ideal solution to this? or is there any other way to achieve this?
the component looks like this:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: '/app/Templates/nav.html',
providers: [MyService]
})
export class MyComponent implements OnInit {
constructor(){
}
ngOnInit(){
}
}
You can use appendChild using ElementRef. Here is an example
#Component({
selector: 'app',
template: `
<div>
<button type="button" (click)="appendToChild()">Append Item to Child</button>
<div #item>Item</div>
<div #appendToChildEl></div>
</div>
`
})
export class App {
#ViewChild('item') item: ElementRef;
#ViewChild('appendToChildEl') appendToChildEl: ElementRef;
appendToChild() {
this.appendToChildEl.nativeElement.appendChild(this.item.nativeElement);
}
}
A plunker example:
https://embed.plnkr.co/7DJ1nWN6sl563hcR71FV/
You could also do something like this if you don't want to use ElementRef
User a service or component variable to control the position:
<my-app>
<nav id="nav-bar">
<ul>
<li id="item-1"></li>
<li>
<div id="item-2" *ngIf="defaultPos"></div>
</li>
<li id="item-3"></li>
<div id="middle-div">
</div>
<div id="side-div">
</div>
<div id="item-2" *ngIf="newPos"></div>
</nav>
</my-app>