Error while designing oxford dictionary application - javascript

I am designing a personal dictionary application using oxford dictionary api. I am trying to display a full page view of the word after clicking the search button or clicking the word in the list of suggested words. But I am getting error "Cannot read property "pathname" of undefined "after clicking the word in the list or the search button. Also the full page view is not coming
I have written two functions called btnClick() and onListClick() in search box component to achieve this. This has been handled in the respective HTML file. Also, I have one component called fullview which gives the full view of the word.
search-box.component.ts
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { FormControl } from '#angular/forms';
import { WordService } from '../word.service';
import { ToastrService } from 'ngx-toastr';
import { filter , switchMap } from 'rxjs/operators';
#Component({
selector: 'app-search-box',
templateUrl: './search-box.component.html',
styleUrls: ['./search-box.component.css']
})
export class SearchBoxComponent implements OnInit {
public searchField : FormControl = new FormControl();
public wordList:any;
public displayList = false;
public link;
constructor(private router:Router, private http:WordService, private toastr:ToastrService) { }
ngOnInit() {
this.searchField.valueChanges
.pipe(
filter(value => !value || value.length > 2 || value !== ''),
filter(value => value !== ''),
switchMap( query => query.length > 2 ? this.http.getWord(query) : this.wordList = ' ')
)
// handling observable
.subscribe(
data => {
this.wordList = '';
this.displayList = true;
this.wordList = data;
},
// handling http error codes
error => {
console.log(error);
if(error.status === 404 || error.status === 414){
this.toastr.error('Try again with valid word');
}
else if(error.status === 403){
this.toastr.error(`Invalid credentials`,`Please enter correct details`);
}
else if(error.status === 414){
this.toastr.error(`Your word is too long`,`Please reduce the length of the word`);
}
else if(error.status === 500){
this.toastr.warning(`Something is broken`,`Please contact developer`);
}
else if(error.status === 502){
this.toastr.info(`Oxford Dictionaries API is down or being upgraded`,`Bad Gateway`);
}
else if(error.status === 503){
this.toastr.info(`Please try again later`, `Service Unavailable`);
}
else if(error.status === 504){
this.toastr.info(`Please try again later`, `Gateway timeout`);
}
}
);
}
// declared focus function for search box value
public onFocus(value)
{
if(value.length > 0)
{
this.displayList = true;
}
else
{
this.displayList = false;
}
}
// declared onListClick function for clicking word in list
public onListClick(e)
{
this.link = this.router.url.split('/');
if (this.link.indexOf('definition') > -1) {
this.displayList = false;
}
e.stopPropagation();
this.router.navigate([e.target.children['0'].pathname]); // error in this line
}
//declared button click function
public btnClick(value)
{
const letters = /^[A-Za-z ]*$/;
const regexp = value.match(letters);
if(regexp === null || value === '')
{
alert('Please enter a word');
}
else
{
this.router.navigate(['/definition',value]);
}
}
}
search-box.component.html
<div class="form-inline m-auto flex-center input-group">
<input #searchBox [formControl]="searchField" type="search" class="form-control" placeholder="Enter More than 3 Characters"
(focus)="onFocus(searchBox.value)" required>
<div class="input-group-append">
<button (click)="btnClick(searchBox.value)" class="btn-rounded btn-md btn-mdb-color m-0" type="button"
>Search
<i class="fa fa-search" aria-hidden="true"></i>
</button>
</div>
<div *ngIf="displayList">
<ul class="autocomplete-wrap mt-3" *ngIf="wordList">
<li *ngFor="let word of wordList.results " (click)="onListClick($event)">
<a [routerLink]="['/definition', word.id]">
{{word.word}}
</a>
</li>
</ul>
</div>
</div>
full-view.component.ts
import { Component, OnInit } from '#angular/core';
import { ToastrService } from 'ngx-toastr';
import { Router, ActivatedRoute } from '#angular/router';
import { WordService } from '../word.service';
import { unionBy, uniq, sortBy } from 'lodash-es';
#Component({
selector: 'app-full-view',
templateUrl: './full-view.component.html',
styleUrls: ['./full-view.component.css']
})
export class FullViewComponent implements OnInit {
public fulldata;
public antonyms = [];
public synonyms = [];
public resultObject;
public lexicalentries = [];
public varientforms = [];
public wordOrigin;
public currentWord;
public residueData = [];
public notes = [];
public show = false;
constructor(private router:Router,private route:ActivatedRoute,private http:WordService,private toastr:ToastrService) {}
ngOnInit() {
// Getting the parameter from URL
this.route.params.subscribe(routeParams => {
this.currentWord = routeParams.id;
this.http.getDefinition(routeParams.id).subscribe(
data => {
this.fulldata = data;
this.updateData(this.fulldata);
},
error => {
this.handleError(error);
}
);
});
}
public updateData(data) {
this.resultObject = data.results['0'];
this.lexicalentries = this.resultObject['lexicalEntries'];
// removing residue data from full data
this.residueData = this.lexicalentries.filter(
lexicalEntry => lexicalEntry.lexicalCategory !== 'Residual'
);
// making arrays empty for new data
this.antonyms = [];
this.synonyms = [];
this.wordOrigin = '';
this.notes = [];
this.extractData(this.residueData);
}
play(audio)
{
audio.play(); // play audio on clicking speak icon
}
public extractData(data) {
for(let singleData of data){
console.log(singleData); // printing the word
// extracting word origin data
if(singleData.entries['0'].etymologies){
this.wordOrigin = singleData.entries['0'].etymologies;
}
// extracting varient forms data
if(singleData.entries['0'].hasOwnProperty('varientforms')){
this.varientforms.push(singleData.entries['0'].varientforms['0'].text);
}
// extracting notes
if(singleData.entries['0'].hasOwnProperty('notes')){
const temp = [];
for(const note of singleData.entries['0'].notes){
temp.push(note);
}
const not = unionBy(temp, 'text');
this.notes = not;
}
}
this.getSyn();
this.toastr.success(`Definition of ${this.resultObject['word']} is Loaded`);
}
// function to get the synonyms
public getSyn() {
this.http.SynAnt(this.currentWord).subscribe(
data => {
let values = data;
this.separateData(values);
},
error => {
this.handleError(error);
}
);
}
// separate synonym and antonym into separate arrays
public separateData(values) {
const synonyms = [];
const antonyms = [];
for(const data of values.results['0'].lexicalentries){
for(const syn of data.entries['0'].senses){
if(syn.synonyms){
synonyms.push(syn.synonyms);
}
if(syn.antonyms){
antonyms.push(syn.antonyms);
}
}
}
this.separateSyn(synonyms);
this.separateAnt(antonyms);
}
// separating antonyms
public separateAnt(data) {
const temp = [];
data.map(i => {
i.map(j => {
temp.push(j.text);
});
});
this.antonyms = sortBy(uniq(temp));
}
// separating synonyms
public separateSyn(data) {
const temp = [];
data.map(i => {
i.map(j => {
temp.push(j.text);
});
});
this.synonyms = sortBy(uniq(temp));
}
// function to handle error responses
public handleError(error)
{
if(error.status === 404 || error.status === 414){
this.toastr.error('Try again with valid word');
}
else if(error.status === 403){
this.toastr.error(`Invalid credentials`,`Please enter correct details`);
}
else if(error.status === 414){
this.toastr.error(`Your word is too long`,`Please reduce the length of the word`);
}
else if(error.status === 500){
this.toastr.warning(`Something is broken`,`Please contact developer`);
}
else if(error.status === 502){
this.toastr.info(`Oxford Dictionaries API is down or being upgraded`,`Bad Gateway`);
}
else if(error.status === 503){
this.toastr.info(`Please try again later`, `Service Unavailable`);
}
else if(error.status === 504){
this.toastr.info(`Please try again later`, `Gateway timeout`);
}
}
}
full-view.component.html
<div class="mt-6 container-fluid">
<div class="mt-2 mb-3">
<app-search-box></app-search-box>
</div>
<div class="jumbotron z-depth-3" *ngIf="fullData">
<p> Definition of
<span class="text-secondary font-weight-bold">{{ resultObject.word }}</span> in English ({{ resultObject.language }}) </p>
<h1 class="h1 red-text text-capitalize"> {{ resultObject.word }} </h1>
<p *ngIf="wordOrigin" class="lead font-weight-normal">
<strong>Origin : </strong>
<span class="text-muted">{{wordOrigin}}</span>
</p>
<hr class="my-1">
<div *ngFor="let lexicalEntry of residueData">
<h4 class="blue-text h4-responsive">
<u>{{lexicalEntry.lexicalCategory}}</u> :
</h4>
<h6 class="font-weight-normal" *ngIf="lexicalEntry.pronunciations.length > 0">Pronunciations :
<span *ngFor="let pronunciations of lexicalEntry.pronunciations">
<span> {{ pronunciations.phoneticSpelling }}
<audio #audio [src]="pronunciations.audioFile"></audio>
<a (click)=play(audio)>
<i class="fa fa-volume-up" aria-hidden="true"></i>
</a>
</span>
</span>
</h6>
<p> Definitions :</p>
<span *ngFor="let sense of lexicalEntry.entries['0'].senses">
<p>
<i class="fa fa-arrow-right indigo-text" aria-hidden="true"></i> {{ sense.definitions }} </p>
</span>
<button class="btn btn-outline-secondary btn-rounded btn-sm waves-light" type="button" (click)="test.toggle()" (click)="show = !show"
mdbWavesEffect>Show More
<i class="fa ml-1" [ngClass]="show ? 'fa-minus' : 'fa-plus'" aria-hidden="true"></i>
</button>
<div class=" bg-vio p-2" [mdbCollapse]="isCollapsed" #test="bs-collapse">
<div *ngIf="lexicalEntry.entries['0'].senses">
<span>Examples :</span>
<ul *ngFor="let senses of lexicalEntry.entries['0'].senses">
<li #eg *ngFor="let example of senses.examples"> {{ example.text }} </li>
</ul>
</div>
</div>
<hr class="dropdown-divider m-2">
</div>
<div class="card pink darken-1 z-depth-2" *ngIf="varientforms.length > 0">
<div class="card-body">
<span class="white-text mb-0">
<span>Variant Forms : {{ varientforms }}</span>
</span>
</div>
</div>
<div class="card pink darken-1 z-depth-2 mt-2" *ngIf="notes.length > 0">
<div class="card-body">
<span class="white-text mb-0">
<span>Notes : </span>
<ul class="list-group">
<li class="list-group-item black-text" *ngFor="let note of notes">
<span class=" font-weight-bold blue-text">{{note.type | uppercase}} :</span>
<span> {{note.text}}</span>
</li>
</ul>
</span>
</div>
</div>
<hr class="dropdown-divider m-2" *ngIf="synonyms.length > 0">
<div class="row">
<div class="col-12" *ngIf="synonyms.length > 0">
<button class="btn btn-outline-primary btn-rounded btn-sm waves-light text-center" type="button" (click)="syn1.toggle()"
(click)="show = !show" mdbWavesEffect>
synonyms
<i class="fa ml-1" [ngClass]="show ? 'fa-minus' : 'fa-plus'" aria-hidden="true"></i>
</button>
<div class="card indigo z-depth-2" [mdbCollapse]="isCollapsed" #syn1="bs-collapse">
<div class="card-body">
<ul class="list-inline white-text mb-0">
<li class="list-inline-item" *ngFor="let syn of synonyms;let last=last"> {{syn}}{{last ? ' ' : ', '}} </li>
</ul>
</div>
</div>
</div>
<hr class="dropdown-divider m-2" *ngIf="antonyms.length > 0">
<div class="col-12" *ngIf="antonyms.length > 0">
<button class="btn btn-outline-primary btn-rounded btn-sm waves-light text-center" type="button" (click)="ant.toggle()" (click)="show = !show"
mdbWavesEffect>
antonyms
<i class="fa ml-1" [ngClass]="show ? 'fa-minus' : 'fa-plus'" aria-hidden="true"></i>
</button>
<div class="card indigo z-depth-2" [mdbCollapse]="isCollapsed" #ant="bs-collapse">
<div class="card-body">
<ul class="list-inline white-text mb-0">
<li class="list-inline-item" *ngFor="let syn of antonyms;let last=last"> {{syn}}{{last ? ' ' : ', '}} </li>
</ul>
</div>
</div>
</div>
</div>
</div>

Related

How to achieve responsive api in Angular?

I need to achieve the responsive page as shown below in the image.
I have created something like this. But my mat-card gets cut or hidden in the tile , when I reduce the browser size. I managed to create this:
Where am I going wrong? Below is my code.
header.component.html
<div fxLayout="column" fxLayout.xs="column">
<mat-toolbar color="primary" >
<button mat-button (click)="side_nav.open()">
<mat-icon>menu</mat-icon>
</button>
<img src="../assets/weather_images/logo.png" style="width: 35px;">
<span> Minimus </span>
<span class="header_text"></span>
<span>TODAY</span>
<span class="header_text"></span>
<span>light</span>
<mat-slide-toggle [checked]="isDarkTheme | async" (change)="toggleDarkTheme($event.checked)"></mat-slide-toggle>
<span>dark</span>
</mat-toolbar>
<mat-sidenav-container [ngClass]="{'dark-theme': isDarkTheme | async}" >
<mat-sidenav #side_nav style="height: 100%;width: 200px;">
<br><br><div class="m"><span routerLink='' (click)="side_nav.close();" > Home </span></div><br><br><br>
<div class="m"><span routerLink='/search-cities' (click)="side_nav.close();">Add City</span></div>
</mat-sidenav>
<mat-sidenav-content><br>
<div [#fade] = "prepareRoute(o)" [#flyInOut] = "prepareRoute(o)">
<router-outlet #o="outlet"></router-outlet>
</div>
</mat-sidenav-content>
</mat-sidenav-container>
</div>
addciyt .component .html
<div>
<mat-grid-list [cols]="breakpoint" (window:resize)="onResize($event)" gutterSize="30px" [ngClass]="{'dark-theme': isDarkTheme | async}">
<mat-grid-tile>
<mat-card class="card_style" [ngClass]="{'dark-theme': isDarkTheme | async}" routerLink="/search-cities" #slideInOut>
<mat-card-title class="card_title" [ngClass]="{'dark-theme': isDarkTheme | async}">ADD CITY</mat-card-title><br>
<img src="../assets/weather_images/plus.png" alt="Plus image" width="150px" class="image_style">
<img mat-card-image src="../assets/weather_images/1.png" height="260px">
</mat-card>
</mat-grid-tile>
<mat-grid-tile *ngFor = "let v of value">
<mat-card class="card_style" [routerLink]="['/details',v.city_name]" #fade>
<mat-card-title class="card_title">
{{value ? (v.city_name).toUpperCase() : ''}}
</mat-card-title><br>
<div *ngIf = "v.des === 'Clouds'" style="text-align: center;">
<img src= "../assets/weather_images/cloudy.png" alt="cloudy" class="image">
</div>
<div *ngIf = "v.des === 'Rain'" style="text-align: center;">
<img src= "../assets/weather_images/raining.png" alt="raining" class="image">
</div>
<div *ngIf = "v.des === 'Clear'" style="text-align: center;">
<img src= "../assets/weather_images/sunny.png" alt="clear" class="image">
</div>
<div *ngIf = "v.des === 'Strom'" style="text-align: center;">
<img src= "../assets/weather_images/strom.png" alt="strom" class="image">
</div>
<div *ngIf = "v.des === 'Snow'" style="text-align: center;">
<img src= "../assets/weather_images/snowing.png" alt="strom" class="image">
</div>
<mat-card-content>
<div>
<p class="temp">{{value ? (v.temp - 273.15).toFixed(2) : ''}}℃</p>
</div>
<p class="main">{{value ? (v.des).toUpperCase() : ''}}</p>
<p style="margin-left: 35px; font-size: 16px;">Temp_min Temp_max</p>
<p class="temp_min">{{value ? (v.temp_min - 273.15).toFixed(2) : ''}}℃<span class="temp_max">{{value ? (v.temp_max - 273.15).toFixed(2) : ''}}℃</span></p>
</mat-card-content>
</mat-card>
</mat-grid-tile>
</mat-grid-list>
</div>
addcity.component.ts
import { Component, OnInit } from "#angular/core";
import { Observable } from "rxjs";
import { ThemeService } from "../services/theme.service";
import { WeatherService } from "../services/weather.service";
import { AngularFireDatabase } from "angularfire2/database";
import { slideInOut, fade } from "../animation";
import { FormControl } from '#angular/forms';
import { map, startWith } from 'rxjs/operators';
#Component({
selector: "app-addcity",
templateUrl: "./addcity.component.html",
styleUrls: ["./addcity.component.scss"],
animations: [
slideInOut,
fade
]
})
export class AddcityComponent implements OnInit {
value: Array<any> = [];
cities: Array<any>;
isDarkTheme: Observable<boolean>;
myControl = new FormControl();
options: string[] = ['One', 'Two', 'Three'];
filteredOptions: Observable<string[]>;
control = new FormControl();
streets: string[] = ['Champs-Élysées', 'Lombard Street', 'Abbey Road', 'Fifth Avenue', 's','d','f','y','u','h','l'];
filteredStreets: Observable<string[]>;
name = '';
breakpoint:number;
constructor(
private themeService: ThemeService,
private db: AngularFireDatabase,
private weatherService: WeatherService
) {
db.list("/user/cities")
.valueChanges()
.subscribe((cities) => {
this.cities = cities;
for (let c of cities) {
this.weatherService.getcities(c['name']).subscribe(value => {
const temp = value["main"].temp;
const temp_min = value["main"].temp_min;
const temp_max = value["main"].temp_max;
const des = value["weather"][0].main;
const city_name = c['name'];
const a = {
temp,
temp_min,
temp_max,
des,
city_name
};
this.value.push(a);
});
}
});
console.log(this.name);
}
ngOnInit() {
this.isDarkTheme = this.themeService.isDarkTheme;
this.breakpoint = (window.innerWidth <= 400) ? 1 : 2;
}
onResize(event) {
this.breakpoint = (event.target.innerWidth <= 400) ? 1 : 2;
}
}
I tried a lot but nothing seems to work.
#DHEERAJ to make your page responsive, you can use different CSS techniques, you can also use the #angular/flex-layout in combination with Angular Material
Find here the Details of #angular/flex-Layout and FlexLayout Examples

How to use for loop in "li tag href"

How can I create an array with 2 objects "title" and "link" then using for loop?? for each (li a href) ??
I'm using angular
<div class="text-footer">
<ul>
<li>
facebook
</li>
<li>
twitter
</li>
<li>
instagram
</li>
</ul>
</div>
Here is the Example
working Examlple
Component.html
<ul>
<li *ngFor = "let title of fetchData">
{{title.title}} -- {{title.description}} -- {{title.tagline}} {{title.date}}</li>
</ul>
component.ts
mydata = [
{"title":"http://tombatossals.github.io/angular-leaflet-directive/#!/","description":"dd","tagline":"tt","date":"derd"},
{"title":"http://tombatossals.github.io/angular-leaflet-directive/#!/","description":"fdfds","tagline":"tt","date":"rerrdd"},
{"title":"http://tombatossals.github.io/angular-leaflet-directive/#!/","description":"dsfsdf","tagline":"tt","date":"derred"},
{"title":"http://tombatossals.github.io/angular-leaflet-directive/#!/","description":"dsfd","tagline":"tt","date":"rrere"}
];
If i understand you correctly, you want to make "Filters" in your website, here is my answer for this :
Short Answer : use 'click' method in angular and inside it call your method
If this is not what you want, sorry but it may help others
**Code example for more clarification : **
//The Shop.Component :
import { Component, OnInit } from '#angular/core';
import { IProduct } from '../shared/models/product';
import { ShopService } from './shop.service';
import { IBrand } from '../shared/models/brand';
import { IType } from '../shared/models/ProductType';
#Component({
selector: 'app-shop',
templateUrl: './shop.component.html',
styleUrls: ['./shop.component.scss'],
})
export class ShopComponent implements OnInit {
products: IProduct[];
brands: IBrand[];
types: IType[];
brandIdSelected = 0;
typeIdSelected = 0;
constructor(private shopService: ShopService) {}
ngOnInit(): void {
this.getProducts();
this.getTypes();
this.getBrands();
}
getProducts() {
this.shopService.getProducts(this.brandIdSelected, this.typeIdSelected).subscribe(
(response) => {
this.products = response.data;
},
(error) => {
console.log(error);
});
}
getBrands() {
this.shopService.getBrands().subscribe(
(response) => {
this.brands = [{id: 0, name: 'All'}, ...response];
},
(error) => {
console.log(error);
});
}
getTypes() {
this.shopService.getTypes().subscribe(
(response) => {
this.types = [{id: 0, name: 'All'}, ...response];
},
(error) => {
console.log(error);
});
}
onBrandSelected(brandId: number) {
this.brandIdSelected = brandId;
this.getProducts();
}
onTypeSelected(typeId: number) {
this.typeIdSelected = typeId;
this.getProducts();
}
}
//Shop.Service :
import { Injectable } from '#angular/core';
import { HttpClient, HttpParams } from '#angular/common/http';
import { map } from 'rxjs/operators';
import { IPagination } from '../shared/models/pagination';
import { IBrand } from '../shared/models/brand';
import { IType } from '../shared/models/ProductType';
#Injectable({
providedIn: 'root'
})
export class ShopService {
baseUrl = 'https://localhost:5001/api/';
constructor(private http: HttpClient) { }
getProducts(brandId?: number, typeId?: number) {
let params = new HttpParams();
if (brandId) {
params = params.append('brandId', brandId.toString());
}
if (typeId) {
params = params.append('typeId', typeId.toString());
}
return this.http.get<IPagination>(this.baseUrl + 'products', {observe: 'response', params})
.pipe(
map(response => {
return response.body;
})
);
}
getBrands() {
return this.http.get<IBrand[]>(this.baseUrl + 'products/brands');
}
getTypes() {
return this.http.get<IType[]>(this.baseUrl + 'products/types');
}
}
//shop -> html:
<div class="container">
<div class="row">
<section class="col-3">
<h5 class="text-warning ml-3 my-3">Sort</h5>
<select class="custom-select mb-3">
<option>Alphabetical</option>
<option>Price : Low to High</option>
<option>Price : High to Low</option>
</select>
<h5 class="text-warning ml-3 my-3">Brands</h5>
<ul class="list-group my-3">
<li class="list-group-item"
*ngFor="let brand of brands"
[class.active]="brand.id === this.brandIdSelected"
[value]="brand.id"
(click)="onBrandSelected(brand.id)"
>
{{brand.name}}
</li>
</ul>
<h5 class="text-warning ml-3 my-3">Types</h5>
<ul class="list-group">
<li class="list-group-item"
*ngFor="let type of types"
[class.active]="type.id === this.typeIdSelected"
[value]="type.id"
(click)="onTypeSelected(type.id)"
>
{{type.name}}
</li>
</ul>
</section>
<section class="col-9">
<div class="d-flex justify-content-between align-items-center pb-2">
<header>
<span>Showing <strong>10</strong> of <strong>16</strong> Results </span>
</header>
<div class="form-inline mt-2">
<input class="form-control my-2 mt-2" style="width: 300px" placeholder="Search"
type="text">
<button class="btn btn-outline-primary ml-2 my-2">Search</button>
<button class="btn btn-outline-success ml-2 my-2">Reset</button>
</div>
</div>
<div class="row">
<div class="col-4 mb-2" *ngFor="let item of products">
<app-product-item [product]="item"></app-product-item>
</div>
</div>
</section>
</div>
Thanks

How to remove the child when removing the parent?

I am making angular application with angular dynamic form where i am using ng-select library.
The HTML with select:
<div *ngFor="let question of questions" class="form-row {{question.class}}">
<ng-container *ngIf="question.children">
<div [formArrayName]="question.key" class="w-100">
<div *ngFor="let item of form.get(question.key).controls; let i=index" [formGroupName]="i" class="row mt-1">
<div *ngFor="let item of question.children" class="{{item.class}} align-middle">
<div class="w-100">
<dynamic-form-builder [question]="item" [index]="i" [form]="form.get(question.key).at(i)"></dynamic-form-builder>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-6 col-sm-12 col-lg-6 col-md-6">
<div class="form-label-group" *ngIf="showTemplateDropdown">
<ngi-select placeholder="Select Template" [required]="true" [hideSelected]="false" [multiple]="true" [items]="templateList"
dropdownPosition="down" bindLabel="name" bindValue="id" (add)="getTemplateValues($event)" (remove)="onRemove($event)">
</ngi-select>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-6 col-sm-12 col-lg-6 col-md-6">
</div>
<div class="col-6 col-sm-12 col-lg-6 col-md-6 text-right">
<div class="btn-group float-right">
<button class="btn btn-primary btn-round btn-fab mat-raised-button" mat-min-fab="" mat-raised-button="" type="button"
(click)="addControls('template_properties')">
<span class="mat-button-wrapper"><i class="material-icons mt-2">add</i></span>
<div class="mat-button-ripple mat-ripple" matripple=""></div>
<div class="mat-button-focus-overlay"></div>
</button>
<button class="btn btn-primary btn-round btn-fab mat-raised-button" mat-min-fab="" mat-raised-button="" type="button"
(click)="removeControls('template_properties')">
<span class="mat-button-wrapper"><i class="material-icons mt-2">remove</i></span>
<div class="mat-button-ripple mat-ripple" matripple=""></div>
<div class="mat-button-focus-overlay"></div>
</button>
</div>
</div>
</div>
</div>
</div>
</ng-container>
<ng-container *ngIf="!question.children">
<div class="w-100">
<dynamic-form-builder [question]="question" [form]="form"></dynamic-form-builder>
</div>
</ng-container>
</div>
Here the [items]="templateList" has the following,
[{"id":"5bebba2c20ccc52871509d56","name":"Template One"},
{"id":"5bebba5720ccc52871509d57","name":"Template Two"},
{"id":"5bebba8d20ccc52871509d5d","name":"Template Three"}]
I am having (change)="getTemplateValues($event)" event for detecting each change happen when we select an item from dropdown.
The change event function Edited,
getTemplateValues(e) {
this.dynamicFormService.getRest("url" + '/' + e.id").subscribe(res => {
try {
if (res.status === "true") {
res.data.template_properties.forEach(element => {
this.templateArray.push(element);
});
this.form = this.qcs.toFormGroup(this.questions);
for (let i = 0; i < this.templateArray.length; i++) {
this.addControls('template_properties');
}
let propertiesArray = [];
this.templateArray.forEach(element => {
propertiesArray.push(element);
});
this.form.patchValue({
'template_properties': propertiesArray
});
} else {
}
}
catch (error) {
}
})
}
console.log(this.propertiesArray) gives the following,
[{"property_name":"Property one","property_type":4,"property_required":true,"property_origin":1},{"property_name":"Property one","property_type":5,"property_required":true,"property_origin":1}]
In the below image i have deleted template three but the template three properties still showing in it..
Here first i am filtering the data first and ignoring the duplicates and each time i am sending the newly selected values alone to the service and fetching the data related to the id element.id.
And using this.addControls('template_properties') to make open the number of rows, and elements will get patched to the form template_properties.
this.form.patchValue({
'template_properties': propertiesArray
});
As of now everything working fine..
The problem actually arise from here:
If we delete a selected list from dropdown, (say i have selected all three template and i have deleted the template two then that particular template's template_properties needs to get deleted..
I have tried with (remove)="onRemove($event)" but its not working because while remove data, the (change) function also calls..
How can i remove the template_properties with this.removeControls('template_properties'); of particular deleted template name in the change event or remove event..
Remove Function:
onRemove(e) {
console.log(e);
this.dynamicFormService.getRest("url" + '/' + e.value.id").subscribe(res => {
try {
if (res.status === "true") {
for (let i = 0; i < res.data.template_properties.length; i++) {
this.removeControls('template_properties');
}
} else {
}
}
catch (error) {
}
})
}
Remove Control:
removeControls(control: string) {
let array = this.form.get(control) as FormArray;
console.log(array)
array.removeAt(array.length);
}
console.log(array) gives,
It should be pretty easy fix. Use (add) instead of (change) in ngi-select.
onRemove(e) {
console.log(e);
this.dynamicFormService.getRest("url" + '/' + e.value.id").subscribe(res => {
try {
if (res.status === "true") {
this.form = this.qcs.toFormGroup(this.questions);
// Issue is here, you should remove only specific record
// which is being passed from function `e`
for (let i = 0; i < res.data.template_properties.length; i++) {
this.removeControls('template_properties');
}
let propertiesArray = [];
this.templateArray.forEach(element => {
propertiesArray.push(element);
});
this.form.patchValue({
'template_properties': propertiesArray
});
} else {
}
}
catch (error) {
}
})
}
Pass the index in removeControls where you want to remove the element from.
removeControls(control: string, index:number) {
let array = this.form.get(control) as FormArray;
console.log(array)
array.removeAt(index);
}
console.log(array) gives,

Html hide button is hiding all buttons instead of one

I am trying to hide a button when clicked.
component.ts:
import { Component, Input, OnInit, ChangeDetectionStrategy, ChangeDetectorRef } from '#angular/core';
import { DataService } from '../../shared/service/data.service';
import { TreeNode } from '../../shared/dto/TreeNode';
import html from './rightside.component.html';
import css from './rightside.component.css';
#Component({
selector: 'rightside-component',
template: html,
providers: [DataService],
styles: [css],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class RightSideComponent implements OnInit {
selections: string[];
#Input() treeNode: TreeNode<string>[];
hide: boolean = false;
constructor(private cd: ChangeDetectorRef) {}
ngOnInit() {
}
getSelections() : TreeNode<string>[] {
if (typeof(this.treeNode) == "undefined" || (this.treeNode) === null) {
return [];
}
return this.treeNode;
}
deselect(item: TreeNode<string>): void {
this.hide = true;
if((item.children) !== null) {
item.children.forEach(element => {
this.deselect(element);
});
}
item.selected = false;
}
}
component.html:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<div>
<ul class="selection-list">
<li *ngFor="let item of getSelections()">
<button class="btn" (click)="deselect(item)" *ngIf="!hide">
<i class="fa fa-close"> {{ item.displayName }} </i>
</button>
</li>
</ul>
</div>
When I click on any button, all of the items are disappearing. I want just the clicked item to disappear. When I select the checkbox again, the item should re-appear. I want to implement something similar to this plunkr I found but for my data structure :
http://next.plnkr.co/edit/1Fr83XHkY0bWd9IzOwuT?p=preview&utm_source=legacy&utm_medium=worker&utm_campaign=next&preview
How can I fix this? Let me know if any other code is required.
Instead of using the common hide variable, use selected attribute in each item since you are making it false when you deselect.
<button class="btn" (click)="deselect(item)" *ngIf="item.selected">
<i class="fa fa-close"> {{ item.displayName }} </i>
</button>
Try This
hide= [];
<div>
<ul class="selection-list">
<li *ngFor="let item of getSelections();let i=index">
<button class="btn" (click)="deselect(item:
TreeNode<string>);hide[i]=!hide[i]" *ngIf="hide[i]">
<i class="fa fa-close"> {{ item.displayName }} </i>
</button>
</li>
</ul>
</div>
All your items disappears because they all share the same "hide" attribute so when you click on One of them it will change for all the items. What you should have is an attribute for each item (this attribute should be initialized at true)
component.html
<div>
<ul class="selection-list">
<li *ngFor="let item of getSelections()">
<button class="btn" (click)="deselect(item)" *ngIf="item.selected">
<i class="fa fa-close"> {{ item.displayName }} </i>
</button>
</li>
</ul>
</div>
component.ts
deselect(item: TreeNode<string>): void {
item.selected = false;
if((item.children) !== null) {
item.children.forEach(element => {
this.deselect(element);
});
}
}

Github API - Get followers of follower in Angular2

How can i display followers count of a follower?
What i have setup right now:
Field (input) to enter Github username in, when button is clicked all of followers of the user will be listed bellow. Follower username & follower ID are already shown, but i also would like to show the amount of followers the follower has.
Picture for better understanding of what I'm looking for:
SCREENSHOT
github-profile.component.ts
import {Component} from 'angular2/core';
import {HTTP_PROVIDERS} from 'angular2/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/forkJoin';
import {GitHubService} from './github.service';
#Component({
selector: 'github-profile',
styles: [
`
/*noinspection CssInvalidPropertyValue*/.avatar {
width: 100;
height: 100;
border-radius: 100%;
}
`
],
template: `
<i *ngIf="isLoading" class="fa fa-spinner fa-spin fa-3x"></i>
<form #f="ngForm" class="animated fadeInRight">
<div class="form-group">
<label for="name">Follower finder</label>
<input ngControl="username"
#username="ngForm"
[(ngModel)] = "inputusr"
type="text"
class="form-control"
placeholder="Enter GitHub username"
required
minlength="3">
<div *ngIf="username.touched && username.errors">
<div *ngIf="username.errors.required"
class="alert alert-danger">
Username is required.
</div>
<div class="alert alert-danger"
*ngIf="username.errors.minlength">
First name should be minimum 3 characters.
</div>
</div>
</div>
<button (click)=OnClick($event) type="submit" class="btn btn-default" [disabled]="!f.valid">Search</button>\
<button type="submit" class="btn btn-danger" (click)=ClearResults($event)>Clear</button>
</form>
<h3 *ngIf="isVisible">#{{user.login}} aka {{user.name}}</h3>
<img *ngIf="isVisible" class="avatar" src="{{ user.avatar_url }}">
<h3 *ngIf="isVisible">Followers</h3>
<div *ngIf="isVisible" class="row">
<div *ngFor="#follower of followers" class="col-sm-3 animated fadeInRight">
<div class="thumbnail">
<img *ngIf="isVisible" src="{{ follower.avatar_url }}" alt="...">
<div class="caption">
<h4 class="text-center">{{ follower.login }}</h4>
<p class="text-center">User ID: {{ follower.id }}</p>
<p class="text-center">Followers: Show followers of a follower here.</p>
</div>
</div>
</div>
</div>
`,
providers: [HTTP_PROVIDERS, GitHubService]
})
export class GitHubProfileComponent {
inputusr: string;
isVisible = false;
isLoading = false;
username: string;
user = {};
followers = {};
constructor(private _gitHubService: GitHubService){
}
ClearResults($event){
this.isVisible = false;
this.inputusr = "";
}
OnClick($event){
this.isLoading = true;
this.username = this.inputusr;
Observable.forkJoin(
this._gitHubService.getUser(this.username),
this._gitHubService.getFollowers(this.username)
)
.subscribe(
res => {
this.user = res[0];
this.followers = res[1];
},
null,
() => { this.isLoading = false; this.isVisible = true; })
}
}
github.service.ts
import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Injectable()
export class GitHubService {
private _baseUrl = "https://api.github.com/users/";
constructor(private _http: Http){}
getUser(username){
return this._http.get(this._baseUrl + username)
.map(res => res.json());
}
getFollowers(username){
return this._http.get(this._baseUrl + username + "/followers")
.map(res => res.json());
}
}
There is a key named "followers" in the response for https://api.github.com/users/odetocode which is pretty much what u need.
The below method can be used if u want the basic details of each follower of the user.
The URL https://api.github.com/users/:username/followers basically returns an array of objects, with each object representing a follower.
There is an upper limit of 30 on the number of entries returned in the response.
Workaround
So basically in order to fetch more users we can append to the url a query string parameter ?page=1, ?page=2and so on.
Check for the response till the length of array = 0;
That will give u the last page till which followers exists.
Then count the number of followers in the last page.
Example: I have 340 followers
So response for https://api.github.com/users/:username/followers?page=13 will be and array of length 0.
Then send a request for https://api.github.com/users/:username/followers?page=12 which will return an array of length 10
Count of followers: (30 * 11) + (10 * 1) = 340

Categories